2 * interface to user space for the gigaset driver
4 * Copyright (c) 2004 by Hansjoerg Lipp <hjlipp@web.de>
6 * =====================================================================
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 * =====================================================================
12 * Version: $Id: interface.c,v 1.14.4.15 2006/02/04 18:28:16 hjlipp Exp $
13 * =====================================================================
17 #include <linux/gigaset_dev.h>
18 #include <linux/tty.h>
19 #include <linux/tty_flip.h>
23 static int if_lock(struct cardstate *cs, int *arg)
27 dbg(DEBUG_IF, "%u: if_lock (%d)", cs->minor_index, cmd);
33 *arg = atomic_read(&cs->mstate) == MS_LOCKED; //FIXME remove?
37 if (!cmd && atomic_read(&cs->mstate) == MS_LOCKED
38 && atomic_read(&cs->connected)) {
39 cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS);
40 cs->ops->baud_rate(cs, B115200);
41 cs->ops->set_line_ctrl(cs, CS8);
42 cs->control_state = TIOCM_DTR|TIOCM_RTS;
46 if (!gigaset_add_event(cs, &cs->at_state, EV_IF_LOCK,
52 dbg(DEBUG_CMD, "scheduling IF_LOCK");
53 gigaset_schedule_event(cs);
55 wait_event(cs->waitqueue, !cs->waiting);
57 if (cs->cmd_result >= 0) {
58 *arg = cs->cmd_result;
62 return cs->cmd_result;
65 static int if_version(struct cardstate *cs, unsigned arg[4])
67 static const unsigned version[4] = GIG_VERSION;
68 static const unsigned compat[4] = GIG_COMPAT;
69 unsigned cmd = arg[0];
71 dbg(DEBUG_IF, "%u: if_version (%d)", cs->minor_index, cmd);
75 memcpy(arg, version, sizeof version);
78 memcpy(arg, compat, sizeof compat);
82 if (!gigaset_add_event(cs, &cs->at_state, EV_IF_VER,
88 dbg(DEBUG_CMD, "scheduling IF_VER");
89 gigaset_schedule_event(cs);
91 wait_event(cs->waitqueue, !cs->waiting);
93 if (cs->cmd_result >= 0)
96 return cs->cmd_result;
102 static int if_config(struct cardstate *cs, int *arg)
104 dbg(DEBUG_IF, "%u: if_config (%d)", cs->minor_index, *arg);
109 if (atomic_read(&cs->mstate) != MS_LOCKED)
113 return gigaset_enterconfigmode(cs);
116 /*** the terminal driver ***/
117 /* stolen from usbserial and some other tty drivers */
119 static int if_open(struct tty_struct *tty, struct file *filp);
120 static void if_close(struct tty_struct *tty, struct file *filp);
121 static int if_ioctl(struct tty_struct *tty, struct file *file,
122 unsigned int cmd, unsigned long arg);
123 static int if_write_room(struct tty_struct *tty);
124 static int if_chars_in_buffer(struct tty_struct *tty);
125 static void if_throttle(struct tty_struct *tty);
126 static void if_unthrottle(struct tty_struct *tty);
127 static void if_set_termios(struct tty_struct *tty, struct termios *old);
128 static int if_tiocmget(struct tty_struct *tty, struct file *file);
129 static int if_tiocmset(struct tty_struct *tty, struct file *file,
130 unsigned int set, unsigned int clear);
131 static int if_write(struct tty_struct *tty,
132 const unsigned char *buf, int count);
134 static struct tty_operations if_ops = {
139 .write_room = if_write_room,
140 .chars_in_buffer = if_chars_in_buffer,
141 .set_termios = if_set_termios,
142 .throttle = if_throttle,
143 .unthrottle = if_unthrottle,
145 .break_ctl = serial_break,
147 .tiocmget = if_tiocmget,
148 .tiocmset = if_tiocmset,
151 static int if_open(struct tty_struct *tty, struct file *filp)
153 struct cardstate *cs;
156 dbg(DEBUG_IF, "%d+%d: %s()", tty->driver->minor_start, tty->index,
159 tty->driver_data = NULL;
161 cs = gigaset_get_cs_by_tty(tty);
165 if (down_interruptible(&cs->sem))
166 return -ERESTARTSYS; // FIXME -EINTR?
167 tty->driver_data = cs;
171 if (cs->open_count == 1) {
172 spin_lock_irqsave(&cs->lock, flags);
174 spin_unlock_irqrestore(&cs->lock, flags);
175 tty->low_latency = 1; //FIXME test
183 static void if_close(struct tty_struct *tty, struct file *filp)
185 struct cardstate *cs;
188 cs = (struct cardstate *) tty->driver_data;
190 err("cs==NULL in %s", __FUNCTION__);
194 dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
199 warn("%s: device not opened", __FUNCTION__);
201 if (!--cs->open_count) {
202 spin_lock_irqsave(&cs->lock, flags);
204 spin_unlock_irqrestore(&cs->lock, flags);
212 static int if_ioctl(struct tty_struct *tty, struct file *file,
213 unsigned int cmd, unsigned long arg)
215 struct cardstate *cs;
216 int retval = -ENODEV;
218 unsigned char buf[6];
221 cs = (struct cardstate *) tty->driver_data;
223 err("cs==NULL in %s", __FUNCTION__);
227 dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __FUNCTION__, cmd);
229 if (down_interruptible(&cs->sem))
230 return -ERESTARTSYS; // FIXME -EINTR?
233 warn("%s: device not opened", __FUNCTION__);
238 retval = get_user(int_arg, (int __user *) arg);
240 retval = if_lock(cs, &int_arg);
242 retval = put_user(int_arg, (int __user *) arg);
245 retval = get_user(int_arg, (int __user *) arg);
247 retval = if_config(cs, &int_arg);
249 retval = put_user(int_arg, (int __user *) arg);
251 case GIGASET_BRKCHARS:
252 //FIXME test if MS_LOCKED
253 gigaset_dbg_buffer(DEBUG_IF, "GIGASET_BRKCHARS",
254 6, (const unsigned char *) arg, 1);
255 if (!atomic_read(&cs->connected)) {
256 dbg(DEBUG_ANY, "can't communicate with unplugged device");
260 retval = copy_from_user(&buf,
261 (const unsigned char __user *) arg, 6)
264 retval = cs->ops->brkchars(cs, buf);
266 case GIGASET_VERSION:
267 retval = copy_from_user(version, (unsigned __user *) arg,
268 sizeof version) ? -EFAULT : 0;
270 retval = if_version(cs, version);
272 retval = copy_to_user((unsigned __user *) arg, version,
277 dbg(DEBUG_ANY, "%s: arg not supported - 0x%04x",
279 retval = -ENOIOCTLCMD;
288 static int if_tiocmget(struct tty_struct *tty, struct file *file)
290 struct cardstate *cs;
293 cs = (struct cardstate *) tty->driver_data;
295 err("cs==NULL in %s", __FUNCTION__);
299 dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
301 if (down_interruptible(&cs->sem))
302 return -ERESTARTSYS; // FIXME -EINTR?
304 // FIXME read from device?
305 retval = cs->control_state & (TIOCM_RTS|TIOCM_DTR);
312 static int if_tiocmset(struct tty_struct *tty, struct file *file,
313 unsigned int set, unsigned int clear)
315 struct cardstate *cs;
319 cs = (struct cardstate *) tty->driver_data;
321 err("cs==NULL in %s", __FUNCTION__);
326 "%u: %s(0x%x, 0x%x)", cs->minor_index, __FUNCTION__, set, clear);
328 if (down_interruptible(&cs->sem))
329 return -ERESTARTSYS; // FIXME -EINTR?
331 if (!atomic_read(&cs->connected)) {
332 dbg(DEBUG_ANY, "can't communicate with unplugged device");
335 mc = (cs->control_state | set) & ~clear & (TIOCM_RTS|TIOCM_DTR);
336 retval = cs->ops->set_modem_ctrl(cs, cs->control_state, mc);
337 cs->control_state = mc;
345 static int if_write(struct tty_struct *tty, const unsigned char *buf, int count)
347 struct cardstate *cs;
348 int retval = -ENODEV;
350 cs = (struct cardstate *) tty->driver_data;
352 err("cs==NULL in %s", __FUNCTION__);
356 dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
358 if (down_interruptible(&cs->sem))
359 return -ERESTARTSYS; // FIXME -EINTR?
362 warn("%s: device not opened", __FUNCTION__);
363 else if (atomic_read(&cs->mstate) != MS_LOCKED) {
364 warn("can't write to unlocked device");
366 } else if (!atomic_read(&cs->connected)) {
367 dbg(DEBUG_ANY, "can't write to unplugged device");
368 retval = -EBUSY; //FIXME
370 retval = cs->ops->write_cmd(cs, buf, count,
371 &cs->if_wake_tasklet);
379 static int if_write_room(struct tty_struct *tty)
381 struct cardstate *cs;
382 int retval = -ENODEV;
384 cs = (struct cardstate *) tty->driver_data;
386 err("cs==NULL in %s", __FUNCTION__);
390 dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
392 if (down_interruptible(&cs->sem))
393 return -ERESTARTSYS; // FIXME -EINTR?
396 warn("%s: device not opened", __FUNCTION__);
397 else if (atomic_read(&cs->mstate) != MS_LOCKED) {
398 warn("can't write to unlocked device");
399 retval = -EBUSY; //FIXME
400 } else if (!atomic_read(&cs->connected)) {
401 dbg(DEBUG_ANY, "can't write to unplugged device");
402 retval = -EBUSY; //FIXME
404 retval = cs->ops->write_room(cs);
411 static int if_chars_in_buffer(struct tty_struct *tty)
413 struct cardstate *cs;
414 int retval = -ENODEV;
416 cs = (struct cardstate *) tty->driver_data;
418 err("cs==NULL in %s", __FUNCTION__);
422 dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
424 if (down_interruptible(&cs->sem))
425 return -ERESTARTSYS; // FIXME -EINTR?
428 warn("%s: device not opened", __FUNCTION__);
429 else if (atomic_read(&cs->mstate) != MS_LOCKED) {
430 warn("can't write to unlocked device");
432 } else if (!atomic_read(&cs->connected)) {
433 dbg(DEBUG_ANY, "can't write to unplugged device");
434 retval = -EBUSY; //FIXME
436 retval = cs->ops->chars_in_buffer(cs);
443 static void if_throttle(struct tty_struct *tty)
445 struct cardstate *cs;
447 cs = (struct cardstate *) tty->driver_data;
449 err("cs==NULL in %s", __FUNCTION__);
453 dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
458 warn("%s: device not opened", __FUNCTION__);
466 static void if_unthrottle(struct tty_struct *tty)
468 struct cardstate *cs;
470 cs = (struct cardstate *) tty->driver_data;
472 err("cs==NULL in %s", __FUNCTION__);
476 dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
481 warn("%s: device not opened", __FUNCTION__);
489 static void if_set_termios(struct tty_struct *tty, struct termios *old)
491 struct cardstate *cs;
494 unsigned int old_cflag;
495 unsigned int control_state, new_state;
497 cs = (struct cardstate *) tty->driver_data;
499 err("cs==NULL in %s", __FUNCTION__);
503 dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__);
507 if (!cs->open_count) {
508 warn("%s: device not opened", __FUNCTION__);
512 if (!atomic_read(&cs->connected)) {
513 dbg(DEBUG_ANY, "can't communicate with unplugged device");
517 // stolen from mct_u232.c
518 iflag = tty->termios->c_iflag;
519 cflag = tty->termios->c_cflag;
520 old_cflag = old ? old->c_cflag : cflag; //FIXME?
521 dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x", cs->minor_index,
522 iflag, cflag, old_cflag);
524 /* get a local copy of the current port settings */
525 control_state = cs->control_state;
529 * Do not attempt to cache old rates and skip settings,
530 * disconnects screw such tricks up completely.
531 * Premature optimization is the root of all evil.
534 /* reassert DTR and (maybe) RTS on transition from B0 */
535 if ((old_cflag & CBAUD) == B0) {
536 new_state = control_state | TIOCM_DTR;
537 /* don't set RTS if using hardware flow control */
538 if (!(old_cflag & CRTSCTS))
539 new_state |= TIOCM_RTS;
540 dbg(DEBUG_IF, "%u: from B0 - set DTR%s", cs->minor_index,
541 (new_state & TIOCM_RTS) ? " only" : "/RTS");
542 cs->ops->set_modem_ctrl(cs, control_state, new_state);
543 control_state = new_state;
546 cs->ops->baud_rate(cs, cflag & CBAUD);
548 if ((cflag & CBAUD) == B0) {
549 /* Drop RTS and DTR */
550 dbg(DEBUG_IF, "%u: to B0 - drop DTR/RTS", cs->minor_index);
551 new_state = control_state & ~(TIOCM_DTR | TIOCM_RTS);
552 cs->ops->set_modem_ctrl(cs, control_state, new_state);
553 control_state = new_state;
557 * Update line control register (LCR)
560 cs->ops->set_line_ctrl(cs, cflag);
563 //FIXME this hangs M101 [ts 2005-03-09]
564 //FIXME do we need this?
566 * Set flow control: well, I do not really now how to handle DTR/RTS.
567 * Just do what we have seen with SniffUSB on Win98.
569 /* Drop DTR/RTS if no flow control otherwise assert */
570 dbg(DEBUG_IF, "%u: control_state %x", cs->minor_index, control_state);
571 new_state = control_state;
572 if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS))
573 new_state |= TIOCM_DTR | TIOCM_RTS;
575 new_state &= ~(TIOCM_DTR | TIOCM_RTS);
576 if (new_state != control_state) {
577 dbg(DEBUG_IF, "%u: new_state %x", cs->minor_index, new_state);
578 gigaset_set_modem_ctrl(cs, control_state, new_state); // FIXME: mct_u232.c sets the old state here. is this a bug?
579 control_state = new_state;
583 /* save off the modified port settings */
584 cs->control_state = control_state;
591 /* wakeup tasklet for the write operation */
592 static void if_wake(unsigned long data)
594 struct cardstate *cs = (struct cardstate *) data;
595 struct tty_struct *tty;
601 if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
602 tty->ldisc.write_wakeup) {
603 dbg(DEBUG_IF, "write wakeup call");
604 tty->ldisc.write_wakeup(tty);
607 wake_up_interruptible(&tty->write_wait);
610 /*** interface to common ***/
612 void gigaset_if_init(struct cardstate *cs)
614 struct gigaset_driver *drv;
620 tasklet_init(&cs->if_wake_tasklet, &if_wake, (unsigned long) cs);
621 tty_register_device(drv->tty, cs->minor_index, NULL);
624 void gigaset_if_free(struct cardstate *cs)
626 struct gigaset_driver *drv;
632 tasklet_disable(&cs->if_wake_tasklet);
633 tasklet_kill(&cs->if_wake_tasklet);
634 tty_unregister_device(drv->tty, cs->minor_index);
637 void gigaset_if_receive(struct cardstate *cs,
638 unsigned char *buffer, size_t len)
641 struct tty_struct *tty;
643 spin_lock_irqsave(&cs->lock, flags);
644 if ((tty = cs->tty) == NULL)
645 dbg(DEBUG_ANY, "receive on closed device");
647 tty_buffer_request_room(tty, len);
648 tty_insert_flip_string(tty, buffer, len);
649 tty_flip_buffer_push(tty);
651 spin_unlock_irqrestore(&cs->lock, flags);
653 EXPORT_SYMBOL_GPL(gigaset_if_receive);
655 /* gigaset_if_initdriver
656 * Initialize tty interface.
659 * procname Name of the driver (e.g. for /proc/tty/drivers)
660 * devname Name of the device files (prefix without minor number)
661 * devfsname Devfs name of the device files without %d
663 void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
664 const char *devname, const char *devfsname)
666 unsigned minors = drv->minors;
668 struct tty_driver *tty;
672 if ((drv->tty = alloc_tty_driver(minors)) == NULL)
676 tty->magic = TTY_DRIVER_MAGIC,
677 tty->major = GIG_MAJOR,
678 tty->type = TTY_DRIVER_TYPE_SERIAL,
679 tty->subtype = SERIAL_TYPE_NORMAL,
680 tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
682 tty->driver_name = procname;
684 tty->minor_start = drv->minor;
685 tty->num = drv->minors;
687 tty->owner = THIS_MODULE;
688 tty->devfs_name = devfsname;
690 tty->init_termios = tty_std_termios; //FIXME
691 tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; //FIXME
692 tty_set_operations(tty, &if_ops);
694 ret = tty_register_driver(tty);
696 warn("failed to register tty driver (error %d)", ret);
699 dbg(DEBUG_IF, "tty driver initialized");
704 warn("could not allocate tty structures");
707 put_tty_driver(drv->tty);
710 void gigaset_if_freedriver(struct gigaset_driver *drv)
716 tty_unregister_driver(drv->tty);
717 put_tty_driver(drv->tty);