diff options
Diffstat (limited to 'drivers/usb/serial/digi_acceleport.c')
| -rw-r--r-- | drivers/usb/serial/digi_acceleport.c | 1195 |
1 files changed, 432 insertions, 763 deletions
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 5f9c6e46bee..8a23c53b946 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -13,229 +13,10 @@ * * Peter Berger (pberger@brimson.com) * Al Borchers (borchers@steinerpoint.com) -* -* (12/03/2001) gkh -* switched to using port->open_count instead of private version. -* Removed port->active -* -* (04/08/2001) gb -* Identify version on module load. -* -* (11/01/2000) Adam J. Richter -* usb_device_id table support -* -* (11/01/2000) pberger and borchers -* -- Turned off the USB_DISABLE_SPD flag for write bulk urbs--it caused -* USB 4 ports to hang on startup. -* -- Serialized access to write urbs by adding the dp_write_urb_in_use -* flag; otherwise, the driver caused SMP system hangs. Watching the -* urb status is not sufficient. -* -* (10/05/2000) gkh -* -- Fixed bug with urb->dev not being set properly, now that the usb -* core needs it. -* -* (8/8/2000) pberger and borchers -* -- Fixed close so that -* - it can timeout while waiting for transmit idle, if needed; -* - it ignores interrupts when flushing the port, turning -* of modem signalling, and so on; -* - it waits for the flush to really complete before returning. -* -- Read_bulk_callback and write_bulk_callback check for a closed -* port before using the tty struct or writing to the port. -* -- The two changes above fix the oops caused by interrupted closes. -* -- Added interruptible args to write_oob_command and set_modem_signals -* and added a timeout arg to transmit_idle; needed for fixes to -* close. -* -- Added code for rx_throttle and rx_unthrottle so that input flow -* control works. -* -- Added code to set overrun, parity, framing, and break errors -* (untested). -* -- Set USB_DISABLE_SPD flag for write bulk urbs, so no 0 length -* bulk writes are done. These hung the Digi USB device. The -* 0 length bulk writes were a new feature of usb-uhci added in -* the 2.4.0-test6 kernels. -* -- Fixed mod inc race in open; do mod inc before sleeping to wait -* for a close to finish. -* -* (7/31/2000) pberger -* -- Fixed bugs with hardware handshaking: -* - Added code to set/clear tty->hw_stopped in digi_read_oob_callback() -* and digi_set_termios() -* -- Added code in digi_set_termios() to -* - add conditional in code handling transition from B0 to only -* set RTS if RTS/CTS flow control is either not in use or if -* the port is not currently throttled. -* - handle turning off CRTSCTS. -* -* (7/30/2000) borchers -* -- Added support for more than one Digi USB device by moving -* globals to a private structure in the pointed to from the -* usb_serial structure. -* -- Moved the modem change and transmit idle wait queues into -* the port private structure, so each port has its own queue -* rather than sharing global queues. -* -- Added support for break signals. -* -* (7/25/2000) pberger -* -- Added USB-2 support. Note: the USB-2 supports 3 devices: two -* serial and a parallel port. The parallel port is implemented -* as a serial-to-parallel converter. That is, the driver actually -* presents all three USB-2 interfaces as serial ports, but the third -* one physically connects to a parallel device. Thus, for example, -* one could plug a parallel printer into the USB-2's third port, -* but from the kernel's (and userland's) point of view what's -* actually out there is a serial device. -* -* (7/15/2000) borchers -* -- Fixed race in open when a close is in progress. -* -- Keep count of opens and dec the module use count for each -* outstanding open when shutdown is called (on disconnect). -* -- Fixed sanity checks in read_bulk_callback and write_bulk_callback -* so pointers are checked before use. -* -- Split read bulk callback into in band and out of band -* callbacks, and no longer restart read chains if there is -* a status error or a sanity error. This fixed the seg -* faults and other errors we used to get on disconnect. -* -- Port->active is once again a flag as usb-serial intended it -* to be, not a count. Since it was only a char it would -* have been limited to 256 simultaneous opens. Now the open -* count is kept in the port private structure in dp_open_count. -* -- Added code for modularization of the digi_acceleport driver. -* -* (6/27/2000) pberger and borchers -* -- Zeroed out sync field in the wakeup_task before first use; -* otherwise the uninitialized value might prevent the task from -* being scheduled. -* -- Initialized ret value to 0 in write_bulk_callback, otherwise -* the uninitialized value could cause a spurious debugging message. -* -* (6/22/2000) pberger and borchers -* -- Made cond_wait_... inline--apparently on SPARC the flags arg -* to spin_lock_irqsave cannot be passed to another function -* to call spin_unlock_irqrestore. Thanks to Pauline Middelink. -* -- In digi_set_modem_signals the inner nested spin locks use just -* spin_lock() rather than spin_lock_irqsave(). The old code -* mistakenly left interrupts off. Thanks to Pauline Middelink. -* -- copy_from_user (which can sleep) is no longer called while a -* spinlock is held. We copy to a local buffer before getting -* the spinlock--don't like the extra copy but the code is simpler. -* -- Printk and dbg are no longer called while a spin lock is held. -* -* (6/4/2000) pberger and borchers -* -- Replaced separate calls to spin_unlock_irqrestore and -* interruptible_sleep_on_timeout with a new function -* cond_wait_interruptible_timeout_irqrestore. This eliminates -* the race condition where the wake up could happen after -* the unlock and before the sleep. -* -- Close now waits for output to drain. -* -- Open waits until any close in progress is finished. -* -- All out of band responses are now processed, not just the -* first in a USB packet. -* -- Fixed a bug that prevented the driver from working when the -* first Digi port was not the first USB serial port--the driver -* was mistakenly using the external USB serial port number to -* try to index into its internal ports. -* -- Fixed an SMP bug -- write_bulk_callback is called directly from -* an interrupt, so spin_lock_irqsave/spin_unlock_irqrestore are -* needed for locks outside write_bulk_callback that are also -* acquired by write_bulk_callback to prevent deadlocks. -* -- Fixed support for select() by making digi_chars_in_buffer() -* return 256 when -EINPROGRESS is set, as the line discipline -* code in n_tty.c expects. -* -- Fixed an include file ordering problem that prevented debugging -* messages from working. -* -- Fixed an intermittent timeout problem that caused writes to -* sometimes get stuck on some machines on some kernels. It turns -* out in these circumstances write_chan() (in n_tty.c) was -* asleep waiting for our wakeup call. Even though we call -* wake_up_interruptible() in digi_write_bulk_callback(), there is -* a race condition that could cause the wakeup to fail: if our -* wake_up_interruptible() call occurs between the time that our -* driver write routine finishes and write_chan() sets current->state -* to TASK_INTERRUPTIBLE, the effect of our wakeup setting the state -* to TASK_RUNNING will be lost and write_chan's subsequent call to -* schedule() will never return (unless it catches a signal). -* This race condition occurs because write_bulk_callback() (and thus -* the wakeup) are called asynchronously from an interrupt, rather than -* from the scheduler. We can avoid the race by calling the wakeup -* from the scheduler queue and that's our fix: Now, at the end of -* write_bulk_callback() we queue up a wakeup call on the scheduler -* task queue. We still also invoke the wakeup directly since that -* squeezes a bit more performance out of the driver, and any lost -* race conditions will get cleaned up at the next scheduler run. -* -* NOTE: The problem also goes away if you comment out -* the two code lines in write_chan() where current->state -* is set to TASK_RUNNING just before calling driver.write() and to -* TASK_INTERRUPTIBLE immediately afterwards. This is why the -* problem did not show up with the 2.2 kernels -- they do not -* include that code. -* -* (5/16/2000) pberger and borchers -* -- Added timeouts to sleeps, to defend against lost wake ups. -* -- Handle transition to/from B0 baud rate in digi_set_termios. -* -* (5/13/2000) pberger and borchers -* -- All commands now sent on out of band port, using -* digi_write_oob_command. -* -- Get modem control signals whenever they change, support TIOCMGET/ -* SET/BIS/BIC ioctls. -* -- digi_set_termios now supports parity, word size, stop bits, and -* receive enable. -* -- Cleaned up open and close, use digi_set_termios and -* digi_write_oob_command to set port parameters. -* -- Added digi_startup_device to start read chains on all ports. -* -- Write buffer is only used when count==1, to be sure put_char can -* write a char (unless the buffer is full). -* -* (5/10/2000) pberger and borchers -* -- Added MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT calls on open/close. -* -- Fixed problem where the first incoming character is lost on -* port opens after the first close on that port. Now we keep -* the read_urb chain open until shutdown. -* -- Added more port conditioning calls in digi_open and digi_close. -* -- Convert port->active to a use count so that we can deal with multiple -* opens and closes properly. -* -- Fixed some problems with the locking code. -* -* (5/3/2000) pberger and borchers -* -- First alpha version of the driver--many known limitations and bugs. -* -* -* Locking and SMP -* -* - Each port, including the out-of-band port, has a lock used to -* serialize all access to the port's private structure. -* - The port lock is also used to serialize all writes and access to -* the port's URB. -* - The port lock is also used for the port write_wait condition -* variable. Holding the port lock will prevent a wake up on the -* port's write_wait; this can be used with cond_wait_... to be sure -* the wake up is not lost in a race when dropping the lock and -* sleeping waiting for the wakeup. -* - digi_write() does not sleep, since it is sometimes called on -* interrupt time. -* - digi_write_bulk_callback() and digi_read_bulk_callback() are -* called directly from interrupts. Hence spin_lock_irqsave() -* and spin_unlock_irqrestore() are used in the rest of the code -* for any locks they acquire. -* - digi_write_bulk_callback() gets the port lock before waking up -* processes sleeping on the port write_wait. It also schedules -* wake ups so they happen from the scheduler, because the tty -* system can miss wake ups from interrupts. -* - All sleeps use a timeout of DIGI_RETRY_TIMEOUT before looping to -* recheck the condition they are sleeping on. This is defensive, -* in case a wake up is lost. -* - Following Documentation/DocBook/kernel-locking.pdf no spin locks -* are held when calling copy_to/from_user or printk. -* -* $Id: digi_acceleport.c,v 1.80.1.2 2000/11/02 05:45:08 root Exp $ */ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> @@ -243,17 +24,13 @@ #include <linux/module.h> #include <linux/spinlock.h> #include <linux/workqueue.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <linux/usb.h> #include <linux/wait.h> #include <linux/usb/serial.h> /* Defines */ -/* - * Version Information - */ -#define DRIVER_VERSION "v1.80.1.2" #define DRIVER_AUTHOR "Peter Berger <pberger@brimson.com>, Al Borchers <borchers@steinerpoint.com>" #define DRIVER_DESC "Digi AccelePort USB-2/USB-4 Serial Converter driver" @@ -418,13 +195,11 @@ struct digi_port { unsigned char dp_out_buf[DIGI_OUT_BUF_SIZE]; int dp_write_urb_in_use; unsigned int dp_modem_signals; - wait_queue_head_t dp_modem_change_wait; int dp_transmit_idle; wait_queue_head_t dp_transmit_idle_wait; int dp_throttled; int dp_throttle_restart; wait_queue_head_t dp_flush_wait; - int dp_in_close; /* close in progress */ wait_queue_head_t dp_close_wait; /* wait queue for close */ struct work_struct dp_wakeup_work; struct usb_serial_port *dp_port; @@ -433,7 +208,6 @@ struct digi_port { /* Local Function Declarations */ -static void digi_wakeup_write(struct usb_serial_port *port); static void digi_wakeup_write_lock(struct work_struct *work); static int digi_write_oob_command(struct usb_serial_port *port, unsigned char *buf, int count, int interruptible); @@ -443,60 +217,50 @@ static int digi_set_modem_signals(struct usb_serial_port *port, unsigned int modem_signals, int interruptible); static int digi_transmit_idle(struct usb_serial_port *port, unsigned long timeout); -static void digi_rx_throttle (struct usb_serial_port *port); -static void digi_rx_unthrottle (struct usb_serial_port *port); -static void digi_set_termios(struct usb_serial_port *port, - struct ktermios *old_termios); -static void digi_break_ctl(struct usb_serial_port *port, int break_state); -static int digi_ioctl(struct usb_serial_port *port, struct file *file, - unsigned int cmd, unsigned long arg); -static int digi_tiocmget(struct usb_serial_port *port, struct file *file); -static int digi_tiocmset(struct usb_serial_port *port, struct file *file, - unsigned int set, unsigned int clear); -static int digi_write(struct usb_serial_port *port, const unsigned char *buf, int count); +static void digi_rx_throttle(struct tty_struct *tty); +static void digi_rx_unthrottle(struct tty_struct *tty); +static void digi_set_termios(struct tty_struct *tty, + struct usb_serial_port *port, struct ktermios *old_termios); +static void digi_break_ctl(struct tty_struct *tty, int break_state); +static int digi_tiocmget(struct tty_struct *tty); +static int digi_tiocmset(struct tty_struct *tty, unsigned int set, + unsigned int clear); +static int digi_write(struct tty_struct *tty, struct usb_serial_port *port, + const unsigned char *buf, int count); static void digi_write_bulk_callback(struct urb *urb); -static int digi_write_room(struct usb_serial_port *port); -static int digi_chars_in_buffer(struct usb_serial_port *port); -static int digi_open(struct usb_serial_port *port, struct file *filp); -static void digi_close(struct usb_serial_port *port, struct file *filp); +static int digi_write_room(struct tty_struct *tty); +static int digi_chars_in_buffer(struct tty_struct *tty); +static int digi_open(struct tty_struct *tty, struct usb_serial_port *port); +static void digi_close(struct usb_serial_port *port); +static void digi_dtr_rts(struct usb_serial_port *port, int on); static int digi_startup_device(struct usb_serial *serial); static int digi_startup(struct usb_serial *serial); -static void digi_shutdown(struct usb_serial *serial); +static void digi_disconnect(struct usb_serial *serial); +static void digi_release(struct usb_serial *serial); +static int digi_port_probe(struct usb_serial_port *port); +static int digi_port_remove(struct usb_serial_port *port); static void digi_read_bulk_callback(struct urb *urb); static int digi_read_inb_callback(struct urb *urb); static int digi_read_oob_callback(struct urb *urb); -/* Statics */ - -static int debug; - -static struct usb_device_id id_table_combined [] = { +static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(DIGI_VENDOR_ID, DIGI_2_ID) }, { USB_DEVICE(DIGI_VENDOR_ID, DIGI_4_ID) }, { } /* Terminating entry */ }; -static struct usb_device_id id_table_2 [] = { +static const struct usb_device_id id_table_2[] = { { USB_DEVICE(DIGI_VENDOR_ID, DIGI_2_ID) }, { } /* Terminating entry */ }; -static struct usb_device_id id_table_4 [] = { +static const struct usb_device_id id_table_4[] = { { USB_DEVICE(DIGI_VENDOR_ID, DIGI_4_ID) }, { } /* Terminating entry */ }; -MODULE_DEVICE_TABLE (usb, id_table_combined); - -static struct usb_driver digi_driver = { - .name = "digi_acceleport", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, - .no_dynamic_id = 1, -}; - +MODULE_DEVICE_TABLE(usb, id_table_combined); /* device info needed for the Digi serial converter */ @@ -506,14 +270,11 @@ static struct usb_serial_driver digi_acceleport_2_device = { .name = "digi_2", }, .description = "Digi 2 port USB adapter", - .usb_driver = &digi_driver, .id_table = id_table_2, - .num_interrupt_in = 0, - .num_bulk_in = 4, - .num_bulk_out = 4, .num_ports = 3, .open = digi_open, .close = digi_close, + .dtr_rts = digi_dtr_rts, .write = digi_write, .write_room = digi_write_room, .write_bulk_callback = digi_write_bulk_callback, @@ -521,13 +282,15 @@ static struct usb_serial_driver digi_acceleport_2_device = { .chars_in_buffer = digi_chars_in_buffer, .throttle = digi_rx_throttle, .unthrottle = digi_rx_unthrottle, - .ioctl = digi_ioctl, .set_termios = digi_set_termios, .break_ctl = digi_break_ctl, .tiocmget = digi_tiocmget, .tiocmset = digi_tiocmset, .attach = digi_startup, - .shutdown = digi_shutdown, + .disconnect = digi_disconnect, + .release = digi_release, + .port_probe = digi_port_probe, + .port_remove = digi_port_remove, }; static struct usb_serial_driver digi_acceleport_4_device = { @@ -536,11 +299,7 @@ static struct usb_serial_driver digi_acceleport_4_device = { .name = "digi_4", }, .description = "Digi 4 port USB adapter", - .usb_driver = &digi_driver, .id_table = id_table_4, - .num_interrupt_in = 0, - .num_bulk_in = 5, - .num_bulk_out = 5, .num_ports = 4, .open = digi_open, .close = digi_close, @@ -551,34 +310,40 @@ static struct usb_serial_driver digi_acceleport_4_device = { .chars_in_buffer = digi_chars_in_buffer, .throttle = digi_rx_throttle, .unthrottle = digi_rx_unthrottle, - .ioctl = digi_ioctl, .set_termios = digi_set_termios, .break_ctl = digi_break_ctl, .tiocmget = digi_tiocmget, .tiocmset = digi_tiocmset, .attach = digi_startup, - .shutdown = digi_shutdown, + .disconnect = digi_disconnect, + .release = digi_release, + .port_probe = digi_port_probe, + .port_remove = digi_port_remove, }; +static struct usb_serial_driver * const serial_drivers[] = { + &digi_acceleport_2_device, &digi_acceleport_4_device, NULL +}; /* Functions */ /* -* Cond Wait Interruptible Timeout Irqrestore -* -* Do spin_unlock_irqrestore and interruptible_sleep_on_timeout -* so that wake ups are not lost if they occur between the unlock -* and the sleep. In other words, spin_unlock_irqrestore and -* interruptible_sleep_on_timeout are "atomic" with respect to -* wake ups. This is used to implement condition variables. -* -* interruptible_sleep_on_timeout is deprecated and has been replaced -* with the equivalent code. -*/ + * Cond Wait Interruptible Timeout Irqrestore + * + * Do spin_unlock_irqrestore and interruptible_sleep_on_timeout + * so that wake ups are not lost if they occur between the unlock + * and the sleep. In other words, spin_unlock_irqrestore and + * interruptible_sleep_on_timeout are "atomic" with respect to + * wake ups. This is used to implement condition variables. + * + * interruptible_sleep_on_timeout is deprecated and has been replaced + * with the equivalent code. + */ static long cond_wait_interruptible_timeout_irqrestore( wait_queue_head_t *q, long timeout, spinlock_t *lock, unsigned long flags) +__releases(lock) { DEFINE_WAIT(wait); @@ -592,56 +357,51 @@ static long cond_wait_interruptible_timeout_irqrestore( /* -* Digi Wakeup Write -* -* Wake up port, line discipline, and tty processes sleeping -* on writes. -*/ + * Digi Wakeup Write + * + * Wake up port, line discipline, and tty processes sleeping + * on writes. + */ static void digi_wakeup_write_lock(struct work_struct *work) { - struct digi_port *priv = container_of(work, struct digi_port, dp_wakeup_work); + struct digi_port *priv = + container_of(work, struct digi_port, dp_wakeup_work); struct usb_serial_port *port = priv->dp_port; unsigned long flags; spin_lock_irqsave(&priv->dp_port_lock, flags); - digi_wakeup_write(port); + tty_port_tty_wakeup(&port->port); spin_unlock_irqrestore(&priv->dp_port_lock, flags); } -static void digi_wakeup_write(struct usb_serial_port *port) -{ - tty_wakeup(port->tty); -} - - /* -* Digi Write OOB Command -* -* Write commands on the out of band port. Commands are 4 -* bytes each, multiple commands can be sent at once, and -* no command will be split across USB packets. Returns 0 -* if successful, -EINTR if interrupted while sleeping and -* the interruptible flag is true, or a negative error -* returned by usb_submit_urb. -*/ + * Digi Write OOB Command + * + * Write commands on the out of band port. Commands are 4 + * bytes each, multiple commands can be sent at once, and + * no command will be split across USB packets. Returns 0 + * if successful, -EINTR if interrupted while sleeping and + * the interruptible flag is true, or a negative error + * returned by usb_submit_urb. + */ static int digi_write_oob_command(struct usb_serial_port *port, unsigned char *buf, int count, int interruptible) { - int ret = 0; int len; struct usb_serial_port *oob_port = (struct usb_serial_port *)((struct digi_serial *)(usb_get_serial_data(port->serial)))->ds_oob_port; struct digi_port *oob_priv = usb_get_serial_port_data(oob_port); unsigned long flags = 0; - dbg("digi_write_oob_command: TOP: port=%d, count=%d", oob_priv->dp_port_num, count); + dev_dbg(&port->dev, + "digi_write_oob_command: TOP: port=%d, count=%d\n", + oob_priv->dp_port_num, count); spin_lock_irqsave(&oob_priv->dp_port_lock, flags); - while(count > 0) { - while(oob_port->write_urb->status == -EINPROGRESS - || oob_priv->dp_write_urb_in_use) { + while (count > 0) { + while (oob_priv->dp_write_urb_in_use) { cond_wait_interruptible_timeout_irqrestore( &oob_port->write_wait, DIGI_RETRY_TIMEOUT, &oob_priv->dp_port_lock, flags); @@ -656,8 +416,8 @@ static int digi_write_oob_command(struct usb_serial_port *port, len &= ~3; memcpy(oob_port->write_urb->transfer_buffer, buf, len); oob_port->write_urb->transfer_buffer_length = len; - oob_port->write_urb->dev = port->serial->dev; - if ((ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC)) == 0) { + ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC); + if (ret == 0) { oob_priv->dp_write_urb_in_use = 1; count -= len; buf += len; @@ -665,23 +425,24 @@ static int digi_write_oob_command(struct usb_serial_port *port, } spin_unlock_irqrestore(&oob_priv->dp_port_lock, flags); if (ret) - err("%s: usb_submit_urb failed, ret=%d", __FUNCTION__, ret); + dev_err(&port->dev, "%s: usb_submit_urb failed, ret=%d\n", + __func__, ret); return ret; } /* -* Digi Write In Band Command -* -* Write commands on the given port. Commands are 4 -* bytes each, multiple commands can be sent at once, and -* no command will be split across USB packets. If timeout -* is non-zero, write in band command will return after -* waiting unsuccessfully for the URB status to clear for -* timeout ticks. Returns 0 if successful, or a negative -* error returned by digi_write. -*/ + * Digi Write In Band Command + * + * Write commands on the given port. Commands are 4 + * bytes each, multiple commands can be sent at once, and + * no command will be split across USB packets. If timeout + * is non-zero, write in band command will return after + * waiting unsuccessfully for the URB status to clear for + * timeout ticks. Returns 0 if successful, or a negative + * error returned by digi_write. + */ static int digi_write_inb_command(struct usb_serial_port *port, unsigned char *buf, int count, unsigned long timeout) @@ -692,7 +453,7 @@ static int digi_write_inb_command(struct usb_serial_port *port, unsigned char *data = port->write_urb->transfer_buffer; unsigned long flags = 0; - dbg("digi_write_inb_command: TOP: port=%d, count=%d", + dev_dbg(&port->dev, "digi_write_inb_command: TOP: port=%d, count=%d\n", priv->dp_port_num, count); if (timeout) @@ -701,9 +462,9 @@ static int digi_write_inb_command(struct usb_serial_port *port, timeout = ULONG_MAX; spin_lock_irqsave(&priv->dp_port_lock, flags); - while(count > 0 && ret == 0) { - while((port->write_urb->status == -EINPROGRESS - || priv->dp_write_urb_in_use) && time_before(jiffies, timeout)) { + while (count > 0 && ret == 0) { + while (priv->dp_write_urb_in_use && + time_before(jiffies, timeout)) { cond_wait_interruptible_timeout_irqrestore( &port->write_wait, DIGI_RETRY_TIMEOUT, &priv->dp_port_lock, flags); @@ -732,9 +493,9 @@ static int digi_write_inb_command(struct usb_serial_port *port, memcpy(data, buf, len); port->write_urb->transfer_buffer_length = len; } - port->write_urb->dev = port->serial->dev; - if ((ret = usb_submit_urb(port->write_urb, GFP_ATOMIC)) == 0) { + ret = usb_submit_urb(port->write_urb, GFP_ATOMIC); + if (ret == 0) { priv->dp_write_urb_in_use = 1; priv->dp_out_buf_len = 0; count -= len; @@ -745,21 +506,22 @@ static int digi_write_inb_command(struct usb_serial_port *port, spin_unlock_irqrestore(&priv->dp_port_lock, flags); if (ret) - err("%s: usb_submit_urb failed, ret=%d, port=%d", - __FUNCTION__, ret, priv->dp_port_num); + dev_err(&port->dev, + "%s: usb_submit_urb failed, ret=%d, port=%d\n", + __func__, ret, priv->dp_port_num); return ret; } /* -* Digi Set Modem Signals -* -* Sets or clears DTR and RTS on the port, according to the -* modem_signals argument. Use TIOCM_DTR and TIOCM_RTS flags -* for the modem_signals argument. Returns 0 if successful, -* -EINTR if interrupted while sleeping, or a non-zero error -* returned by usb_submit_urb. -*/ + * Digi Set Modem Signals + * + * Sets or clears DTR and RTS on the port, according to the + * modem_signals argument. Use TIOCM_DTR and TIOCM_RTS flags + * for the modem_signals argument. Returns 0 if successful, + * -EINTR if interrupted while sleeping, or a non-zero error + * returned by usb_submit_urb. + */ static int digi_set_modem_signals(struct usb_serial_port *port, unsigned int modem_signals, int interruptible) @@ -767,19 +529,20 @@ static int digi_set_modem_signals(struct usb_serial_port *port, int ret; struct digi_port *port_priv = usb_get_serial_port_data(port); - struct usb_serial_port *oob_port = (struct usb_serial_port *)((struct digi_serial *)(usb_get_serial_data(port->serial)))->ds_oob_port; + struct usb_serial_port *oob_port = (struct usb_serial_port *) ((struct digi_serial *)(usb_get_serial_data(port->serial)))->ds_oob_port; struct digi_port *oob_priv = usb_get_serial_port_data(oob_port); unsigned char *data = oob_port->write_urb->transfer_buffer; unsigned long flags = 0; - dbg("digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x", + dev_dbg(&port->dev, + "digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x\n", port_priv->dp_port_num, modem_signals); spin_lock_irqsave(&oob_priv->dp_port_lock, flags); spin_lock(&port_priv->dp_port_lock); - while(oob_port->write_urb->status == -EINPROGRESS || oob_priv->dp_write_urb_in_use) { + while (oob_priv->dp_write_urb_in_use) { spin_unlock(&port_priv->dp_port_lock); cond_wait_interruptible_timeout_irqrestore( &oob_port->write_wait, DIGI_RETRY_TIMEOUT, @@ -791,17 +554,19 @@ static int digi_set_modem_signals(struct usb_serial_port *port, } data[0] = DIGI_CMD_SET_DTR_SIGNAL; data[1] = port_priv->dp_port_num; - data[2] = (modem_signals&TIOCM_DTR) ? DIGI_DTR_ACTIVE : DIGI_DTR_INACTIVE; + data[2] = (modem_signals & TIOCM_DTR) ? + DIGI_DTR_ACTIVE : DIGI_DTR_INACTIVE; data[3] = 0; data[4] = DIGI_CMD_SET_RTS_SIGNAL; data[5] = port_priv->dp_port_num; - data[6] = (modem_signals&TIOCM_RTS) ? DIGI_RTS_ACTIVE : DIGI_RTS_INACTIVE; + data[6] = (modem_signals & TIOCM_RTS) ? + DIGI_RTS_ACTIVE : DIGI_RTS_INACTIVE; data[7] = 0; oob_port->write_urb->transfer_buffer_length = 8; - oob_port->write_urb->dev = port->serial->dev; - if ((ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC)) == 0) { + ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC); + if (ret == 0) { oob_priv->dp_write_urb_in_use = 1; port_priv->dp_modem_signals = (port_priv->dp_modem_signals&~(TIOCM_DTR|TIOCM_RTS)) @@ -810,21 +575,22 @@ static int digi_set_modem_signals(struct usb_serial_port *port, spin_unlock(&port_priv->dp_port_lock); spin_unlock_irqrestore(&oob_priv->dp_port_lock, flags); if (ret) - err("%s: usb_submit_urb failed, ret=%d", __FUNCTION__, ret); + dev_err(&port->dev, "%s: usb_submit_urb failed, ret=%d\n", + __func__, ret); return ret; } /* -* Digi Transmit Idle -* -* Digi transmit idle waits, up to timeout ticks, for the transmitter -* to go idle. It returns 0 if successful or a negative error. -* -* There are race conditions here if more than one process is calling -* digi_transmit_idle on the same port at the same time. However, this -* is only called from close, and only one process can be in close on a -* port at a time, so its ok. -*/ + * Digi Transmit Idle + * + * Digi transmit idle waits, up to timeout ticks, for the transmitter + * to go idle. It returns 0 if successful or a negative error. + * + * There are race conditions here if more than one process is calling + * digi_transmit_idle on the same port at the same time. However, this + * is only called from close, and only one process can be in close on a + * port at a time, so its ok. + */ static int digi_transmit_idle(struct usb_serial_port *port, unsigned long timeout) @@ -843,12 +609,13 @@ static int digi_transmit_idle(struct usb_serial_port *port, timeout += jiffies; - if ((ret = digi_write_inb_command(port, buf, 2, timeout - jiffies)) != 0) + ret = digi_write_inb_command(port, buf, 2, timeout - jiffies); + if (ret != 0) return ret; spin_lock_irqsave(&priv->dp_port_lock, flags); - while(time_before(jiffies, timeout) && !priv->dp_transmit_idle) { + while (time_before(jiffies, timeout) && !priv->dp_transmit_idle) { cond_wait_interruptible_timeout_irqrestore( &priv->dp_transmit_idle_wait, DIGI_RETRY_TIMEOUT, &priv->dp_port_lock, flags); @@ -863,14 +630,12 @@ static int digi_transmit_idle(struct usb_serial_port *port, } -static void digi_rx_throttle(struct usb_serial_port *port) +static void digi_rx_throttle(struct tty_struct *tty) { unsigned long flags; + struct usb_serial_port *port = tty->driver_data; struct digi_port *priv = usb_get_serial_port_data(port); - - dbg("digi_rx_throttle: TOP: port=%d", priv->dp_port_num); - /* stop receiving characters by not resubmitting the read urb */ spin_lock_irqsave(&priv->dp_port_lock, flags); priv->dp_throttled = 1; @@ -879,54 +644,54 @@ static void digi_rx_throttle(struct usb_serial_port *port) } -static void digi_rx_unthrottle(struct usb_serial_port *port) +static void digi_rx_unthrottle(struct tty_struct *tty) { int ret = 0; unsigned long flags; + struct usb_serial_port *port = tty->driver_data; struct digi_port *priv = usb_get_serial_port_data(port); - dbg("digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num); - spin_lock_irqsave(&priv->dp_port_lock, flags); + /* restart read chain */ + if (priv->dp_throttle_restart) + ret = usb_submit_urb(port->read_urb, GFP_ATOMIC); + /* turn throttle off */ priv->dp_throttled = 0; priv->dp_throttle_restart = 0; - /* restart read chain */ - if (priv->dp_throttle_restart) { - port->read_urb->dev = port->serial->dev; - ret = usb_submit_urb(port->read_urb, GFP_ATOMIC); - } - spin_unlock_irqrestore(&priv->dp_port_lock, flags); if (ret) - err("%s: usb_submit_urb failed, ret=%d, port=%d", - __FUNCTION__, ret, priv->dp_port_num); + dev_err(&port->dev, + "%s: usb_submit_urb failed, ret=%d, port=%d\n", + __func__, ret, priv->dp_port_num); } -static void digi_set_termios(struct usb_serial_port *port, - struct ktermios *old_termios) +static void digi_set_termios(struct tty_struct *tty, + struct usb_serial_port *port, struct ktermios *old_termios) { - struct digi_port *priv = usb_get_serial_port_data(port); - struct tty_struct *tty = port->tty; - unsigned int iflag = tty->termios->c_iflag; - unsigned int cflag = tty->termios->c_cflag; + struct device *dev = &port->dev; + unsigned int iflag = tty->termios.c_iflag; + unsigned int cflag = tty->termios.c_cflag; unsigned int old_iflag = old_termios->c_iflag; unsigned int old_cflag = old_termios->c_cflag; unsigned char buf[32]; unsigned int modem_signals; - int arg,ret; + int arg, ret; int i = 0; speed_t baud; - dbg("digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, old_cflag=0x%x", priv->dp_port_num, iflag, old_iflag, cflag, old_cflag); + dev_dbg(dev, + "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, old_cflag=0x%x\n", + priv->dp_port_num, iflag, old_iflag, cflag, old_cflag); /* set baud rate */ - if ((baud = tty_get_baud_rate(tty)) != tty_termios_baud_rate(old_termios)) { + baud = tty_get_baud_rate(tty); + if (baud != tty_termios_baud_rate(old_termios)) { arg = -1; /* reassert DTR and (maybe) RTS on transition from B0 */ @@ -934,36 +699,36 @@ static void digi_set_termios(struct usb_serial_port *port, /* don't set RTS if using hardware flow control */ /* and throttling input */ modem_signals = TIOCM_DTR; - if (!(tty->termios->c_cflag & CRTSCTS) || + if (!(tty->termios.c_cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) modem_signals |= TIOCM_RTS; digi_set_modem_signals(port, modem_signals, 1); } switch (baud) { - /* drop DTR and RTS on transition to B0 */ - case 0: digi_set_modem_signals(port, 0, 1); break; - case 50: arg = DIGI_BAUD_50; break; - case 75: arg = DIGI_BAUD_75; break; - case 110: arg = DIGI_BAUD_110; break; - case 150: arg = DIGI_BAUD_150; break; - case 200: arg = DIGI_BAUD_200; break; - case 300: arg = DIGI_BAUD_300; break; - case 600: arg = DIGI_BAUD_600; break; - case 1200: arg = DIGI_BAUD_1200; break; - case 1800: arg = DIGI_BAUD_1800; break; - case 2400: arg = DIGI_BAUD_2400; break; - case 4800: arg = DIGI_BAUD_4800; break; - case 9600: arg = DIGI_BAUD_9600; break; - case 19200: arg = DIGI_BAUD_19200; break; - case 38400: arg = DIGI_BAUD_38400; break; - case 57600: arg = DIGI_BAUD_57600; break; - case 115200: arg = DIGI_BAUD_115200; break; - case 230400: arg = DIGI_BAUD_230400; break; - case 460800: arg = DIGI_BAUD_460800; break; - default: - arg = DIGI_BAUD_9600; - baud = 9600; - break; + /* drop DTR and RTS on transition to B0 */ + case 0: digi_set_modem_signals(port, 0, 1); break; + case 50: arg = DIGI_BAUD_50; break; + case 75: arg = DIGI_BAUD_75; break; + case 110: arg = DIGI_BAUD_110; break; + case 150: arg = DIGI_BAUD_150; break; + case 200: arg = DIGI_BAUD_200; break; + case 300: arg = DIGI_BAUD_300; break; + case 600: arg = DIGI_BAUD_600; break; + case 1200: arg = DIGI_BAUD_1200; break; + case 1800: arg = DIGI_BAUD_1800; break; + case 2400: arg = DIGI_BAUD_2400; break; + case 4800: arg = DIGI_BAUD_4800; break; + case 9600: arg = DIGI_BAUD_9600; break; + case 19200: arg = DIGI_BAUD_19200; break; + case 38400: arg = DIGI_BAUD_38400; break; + case 57600: arg = DIGI_BAUD_57600; break; + case 115200: arg = DIGI_BAUD_115200; break; + case 230400: arg = DIGI_BAUD_230400; break; + case 460800: arg = DIGI_BAUD_460800; break; + default: + arg = DIGI_BAUD_9600; + baud = 9600; + break; } if (arg != -1) { buf[i++] = DIGI_CMD_SET_BAUD_RATE; @@ -973,7 +738,7 @@ static void digi_set_termios(struct usb_serial_port *port, } } /* set parity */ - tty->termios->c_cflag &= ~CMSPAR; + tty->termios.c_cflag &= ~CMSPAR; if ((cflag&(PARENB|PARODD)) != (old_cflag&(PARENB|PARODD))) { if (cflag&PARENB) { @@ -998,7 +763,8 @@ static void digi_set_termios(struct usb_serial_port *port, case CS7: arg = DIGI_WORD_SIZE_7; break; case CS8: arg = DIGI_WORD_SIZE_8; break; default: - dbg("digi_set_termios: can't handle word size %d", + dev_dbg(dev, + "digi_set_termios: can't handle word size %d\n", (cflag&CSIZE)); break; } @@ -1089,14 +855,16 @@ static void digi_set_termios(struct usb_serial_port *port, buf[i++] = arg; buf[i++] = 0; } - if ((ret = digi_write_oob_command(port, buf, i, 1)) != 0) - dbg("digi_set_termios: write oob failed, ret=%d", ret); + ret = digi_write_oob_command(port, buf, i, 1); + if (ret != 0) + dev_dbg(dev, "digi_set_termios: write oob failed, ret=%d\n", ret); tty_encode_baud_rate(tty, baud, baud); } -static void digi_break_ctl(struct usb_serial_port *port, int break_state) +static void digi_break_ctl(struct tty_struct *tty, int break_state) { + struct usb_serial_port *port = tty->driver_data; unsigned char buf[4]; buf[0] = DIGI_CMD_BREAK_CONTROL; @@ -1107,14 +875,13 @@ static void digi_break_ctl(struct usb_serial_port *port, int break_state) } -static int digi_tiocmget(struct usb_serial_port *port, struct file *file) +static int digi_tiocmget(struct tty_struct *tty) { + struct usb_serial_port *port = tty->driver_data; struct digi_port *priv = usb_get_serial_port_data(port); unsigned int val; unsigned long flags; - dbg("%s: TOP: port=%d", __FUNCTION__, priv->dp_port_num); - spin_lock_irqsave(&priv->dp_port_lock, flags); val = priv->dp_modem_signals; spin_unlock_irqrestore(&priv->dp_port_lock, flags); @@ -1122,15 +889,14 @@ static int digi_tiocmget(struct usb_serial_port *port, struct file *file) } -static int digi_tiocmset(struct usb_serial_port *port, struct file *file, - unsigned int set, unsigned int clear) +static int digi_tiocmset(struct tty_struct *tty, + unsigned int set, unsigned int clear) { + struct usb_serial_port *port = tty->driver_data; struct digi_port *priv = usb_get_serial_port_data(port); unsigned int val; unsigned long flags; - dbg("%s: TOP: port=%d", __FUNCTION__, priv->dp_port_num); - spin_lock_irqsave(&priv->dp_port_lock, flags); val = (priv->dp_modem_signals & ~clear) | set; spin_unlock_irqrestore(&priv->dp_port_lock, flags); @@ -1138,35 +904,17 @@ static int digi_tiocmset(struct usb_serial_port *port, struct file *file, } -static int digi_ioctl(struct usb_serial_port *port, struct file *file, - unsigned int cmd, unsigned long arg) +static int digi_write(struct tty_struct *tty, struct usb_serial_port *port, + const unsigned char *buf, int count) { - struct digi_port *priv = usb_get_serial_port_data(port); - dbg("digi_ioctl: TOP: port=%d, cmd=0x%x", priv->dp_port_num, cmd); - switch (cmd) { - case TIOCMIWAIT: - /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/ - /* TODO */ - return 0; - case TIOCGICOUNT: - /* return count of modemline transitions */ - /* TODO */ - return 0; - } - return -ENOIOCTLCMD; - -} - -static int digi_write(struct usb_serial_port *port, const unsigned char *buf, int count) -{ - - int ret,data_len,new_len; + int ret, data_len, new_len; struct digi_port *priv = usb_get_serial_port_data(port); unsigned char *data = port->write_urb->transfer_buffer; unsigned long flags = 0; - dbg("digi_write: TOP: port=%d, count=%d, in_interrupt=%ld", + dev_dbg(&port->dev, + "digi_write: TOP: port=%d, count=%d, in_interrupt=%ld\n", priv->dp_port_num, count, in_interrupt()); /* copy user data (which can sleep) before getting spin lock */ @@ -1175,11 +923,10 @@ static int digi_write(struct usb_serial_port *port, const unsigned char *buf, in /* be sure only one write proceeds at a time */ /* there are races on the port private buffer */ - /* and races to check write_urb->status */ spin_lock_irqsave(&priv->dp_port_lock, flags); /* wait for urb status clear to submit another urb */ - if (port->write_urb->status == -EINPROGRESS || priv->dp_write_urb_in_use) { + if (priv->dp_write_urb_in_use) { /* buffer data if count is 1 (probably put_char) if possible */ if (count == 1 && priv->dp_out_buf_len < DIGI_OUT_BUF_SIZE) { priv->dp_out_buf[priv->dp_out_buf_len++] = *buf; @@ -1202,7 +949,6 @@ static int digi_write(struct usb_serial_port *port, const unsigned char *buf, in } port->write_urb->transfer_buffer_length = data_len+2; - port->write_urb->dev = port->serial->dev; *data++ = DIGI_CMD_SEND_DATA; *data++ = data_len; @@ -1214,7 +960,8 @@ static int digi_write(struct usb_serial_port *port, const unsigned char *buf, in /* copy in new data */ memcpy(data, buf, new_len); - if ((ret = usb_submit_urb(port->write_urb, GFP_ATOMIC)) == 0) { + ret = usb_submit_urb(port->write_urb, GFP_ATOMIC); + if (ret == 0) { priv->dp_write_urb_in_use = 1; ret = new_len; priv->dp_out_buf_len = 0; @@ -1223,41 +970,41 @@ static int digi_write(struct usb_serial_port *port, const unsigned char *buf, in /* return length of new data written, or error */ spin_unlock_irqrestore(&priv->dp_port_lock, flags); if (ret < 0) - err("%s: usb_submit_urb failed, ret=%d, port=%d", - __FUNCTION__, ret, priv->dp_port_num); - dbg("digi_write: returning %d", ret); + dev_err_console(port, + "%s: usb_submit_urb failed, ret=%d, port=%d\n", + __func__, ret, priv->dp_port_num); + dev_dbg(&port->dev, "digi_write: returning %d\n", ret); return ret; -} +} static void digi_write_bulk_callback(struct urb *urb) { - struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct usb_serial_port *port = urb->context; struct usb_serial *serial; struct digi_port *priv; struct digi_serial *serial_priv; int ret = 0; int status = urb->status; - dbg("digi_write_bulk_callback: TOP, urb->status=%d", status); - /* port and serial sanity check */ - if (port == NULL || (priv=usb_get_serial_port_data(port)) == NULL) { - err("%s: port or port->private is NULL, status=%d", - __FUNCTION__, status); + if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) { + pr_err("%s: port or port->private is NULL, status=%d\n", + __func__, status); return; } serial = port->serial; - if (serial == NULL || (serial_priv=usb_get_serial_data(serial)) == NULL) { - err("%s: serial or serial->private is NULL, status=%d", - __FUNCTION__, status); + if (serial == NULL || (serial_priv = usb_get_serial_data(serial)) == NULL) { + dev_err(&port->dev, + "%s: serial or serial->private is NULL, status=%d\n", + __func__, status); return; } /* handle oob callback */ if (priv->dp_port_num == serial_priv->ds_oob_port_num) { - dbg("digi_write_bulk_callback: oob callback"); + dev_dbg(&port->dev, "digi_write_bulk_callback: oob callback\n"); spin_lock(&priv->dp_port_lock); priv->dp_write_urb_in_use = 0; wake_up_interruptible(&port->write_wait); @@ -1265,112 +1012,92 @@ static void digi_write_bulk_callback(struct urb *urb) return; } - /* try to send any buffered data on this port, if it is open */ + /* try to send any buffered data on this port */ spin_lock(&priv->dp_port_lock); priv->dp_write_urb_in_use = 0; - if (port->open_count && port->write_urb->status != -EINPROGRESS - && priv->dp_out_buf_len > 0) { + if (priv->dp_out_buf_len > 0) { *((unsigned char *)(port->write_urb->transfer_buffer)) = (unsigned char)DIGI_CMD_SEND_DATA; - *((unsigned char *)(port->write_urb->transfer_buffer)+1) + *((unsigned char *)(port->write_urb->transfer_buffer) + 1) = (unsigned char)priv->dp_out_buf_len; - port->write_urb->transfer_buffer_length = priv->dp_out_buf_len+2; - port->write_urb->dev = serial->dev; - memcpy(port->write_urb->transfer_buffer+2, priv->dp_out_buf, + port->write_urb->transfer_buffer_length = + priv->dp_out_buf_len + 2; + memcpy(port->write_urb->transfer_buffer + 2, priv->dp_out_buf, priv->dp_out_buf_len); - if ((ret = usb_submit_urb(port->write_urb, GFP_ATOMIC)) == 0) { + ret = usb_submit_urb(port->write_urb, GFP_ATOMIC); + if (ret == 0) { priv->dp_write_urb_in_use = 1; priv->dp_out_buf_len = 0; } } /* wake up processes sleeping on writes immediately */ - digi_wakeup_write(port); + tty_port_tty_wakeup(&port->port); /* also queue up a wakeup at scheduler time, in case we */ /* lost the race in write_chan(). */ schedule_work(&priv->dp_wakeup_work); spin_unlock(&priv->dp_port_lock); - if (ret) - err("%s: usb_submit_urb failed, ret=%d, port=%d", - __FUNCTION__, ret, priv->dp_port_num); + if (ret && ret != -EPERM) + dev_err_console(port, + "%s: usb_submit_urb failed, ret=%d, port=%d\n", + __func__, ret, priv->dp_port_num); } -static int digi_write_room(struct usb_serial_port *port) +static int digi_write_room(struct tty_struct *tty) { - - int room; + struct usb_serial_port *port = tty->driver_data; struct digi_port *priv = usb_get_serial_port_data(port); + int room; unsigned long flags = 0; spin_lock_irqsave(&priv->dp_port_lock, flags); - if (port->write_urb->status == -EINPROGRESS || priv->dp_write_urb_in_use) + if (priv->dp_write_urb_in_use) room = 0; else room = port->bulk_out_size - 2 - priv->dp_out_buf_len; spin_unlock_irqrestore(&priv->dp_port_lock, flags); - dbg("digi_write_room: port=%d, room=%d", priv->dp_port_num, room); + dev_dbg(&port->dev, "digi_write_room: port=%d, room=%d\n", priv->dp_port_num, room); return room; } -static int digi_chars_in_buffer(struct usb_serial_port *port) +static int digi_chars_in_buffer(struct tty_struct *tty) { - + struct usb_serial_port *port = tty->driver_data; struct digi_port *priv = usb_get_serial_port_data(port); - - if (port->write_urb->status == -EINPROGRESS - || priv->dp_write_urb_in_use) { - dbg("digi_chars_in_buffer: port=%d, chars=%d", + if (priv->dp_write_urb_in_use) { + dev_dbg(&port->dev, "digi_chars_in_buffer: port=%d, chars=%d\n", priv->dp_port_num, port->bulk_out_size - 2); /* return(port->bulk_out_size - 2); */ return 256; } else { - dbg("digi_chars_in_buffer: port=%d, chars=%d", + dev_dbg(&port->dev, "digi_chars_in_buffer: port=%d, chars=%d\n", priv->dp_port_num, priv->dp_out_buf_len); return priv->dp_out_buf_len; } } +static void digi_dtr_rts(struct usb_serial_port *port, int on) +{ + /* Adjust DTR and RTS */ + digi_set_modem_signals(port, on * (TIOCM_DTR|TIOCM_RTS), 1); +} -static int digi_open(struct usb_serial_port *port, struct file *filp) +static int digi_open(struct tty_struct *tty, struct usb_serial_port *port) { int ret; unsigned char buf[32]; struct digi_port *priv = usb_get_serial_port_data(port); struct ktermios not_termios; - unsigned long flags = 0; - - dbg("digi_open: TOP: port=%d, open_count=%d", - priv->dp_port_num, port->open_count); /* be sure the device is started up */ if (digi_startup_device(port->serial) != 0) return -ENXIO; - spin_lock_irqsave(&priv->dp_port_lock, flags); - - /* don't wait on a close in progress for non-blocking opens */ - if (priv->dp_in_close && (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0) { - spin_unlock_irqrestore(&priv->dp_port_lock, flags); - return -EAGAIN; - } - - /* wait for a close in progress to finish */ - while(priv->dp_in_close) { - cond_wait_interruptible_timeout_irqrestore( - &priv->dp_close_wait, DIGI_RETRY_TIMEOUT, - &priv->dp_port_lock, flags); - if (signal_pending(current)) - return -EINTR; - spin_lock_irqsave(&priv->dp_port_lock, flags); - } - - spin_unlock_irqrestore(&priv->dp_port_lock, flags); - /* read modem signals automatically whenever they change */ buf[0] = DIGI_CMD_READ_INPUT_SIGNALS; buf[1] = priv->dp_port_num; @@ -1383,125 +1110,96 @@ static int digi_open(struct usb_serial_port *port, struct file *filp) buf[6] = DIGI_FLUSH_TX | DIGI_FLUSH_RX; buf[7] = 0; - if ((ret = digi_write_oob_command(port, buf, 8, 1)) != 0) - dbg("digi_open: write oob failed, ret=%d", ret); + ret = digi_write_oob_command(port, buf, 8, 1); + if (ret != 0) + dev_dbg(&port->dev, "digi_open: write oob failed, ret=%d\n", ret); /* set termios settings */ - not_termios.c_cflag = ~port->tty->termios->c_cflag; - not_termios.c_iflag = ~port->tty->termios->c_iflag; - digi_set_termios(port, ¬_termios); - - /* set DTR and RTS */ - digi_set_modem_signals(port, TIOCM_DTR|TIOCM_RTS, 1); - + if (tty) { + not_termios.c_cflag = ~tty->termios.c_cflag; + not_termios.c_iflag = ~tty->termios.c_iflag; + digi_set_termios(tty, port, ¬_termios); + } return 0; } -static void digi_close(struct usb_serial_port *port, struct file *filp) +static void digi_close(struct usb_serial_port *port) { DEFINE_WAIT(wait); int ret; unsigned char buf[32]; - struct tty_struct *tty = port->tty; struct digi_port *priv = usb_get_serial_port_data(port); - dbg("digi_close: TOP: port=%d, open_count=%d", - priv->dp_port_num, port->open_count); - mutex_lock(&port->serial->disc_mutex); /* if disconnected, just clear flags */ if (port->serial->disconnected) goto exit; - /* do cleanup only after final close on this port */ - spin_lock_irq(&priv->dp_port_lock); - priv->dp_in_close = 1; - spin_unlock_irq(&priv->dp_port_lock); + /* FIXME: Transmit idle belongs in the wait_unti_sent path */ + digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT); + + /* disable input flow control */ + buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL; + buf[1] = priv->dp_port_num; + buf[2] = DIGI_DISABLE; + buf[3] = 0; - /* tell line discipline to process only XON/XOFF */ - tty->closing = 1; + /* disable output flow control */ + buf[4] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL; + buf[5] = priv->dp_port_num; + buf[6] = DIGI_DISABLE; + buf[7] = 0; - /* wait for output to drain */ - if ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0) - tty_wait_until_sent(tty, DIGI_CLOSE_TIMEOUT); + /* disable reading modem signals automatically */ + buf[8] = DIGI_CMD_READ_INPUT_SIGNALS; + buf[9] = priv->dp_port_num; + buf[10] = DIGI_DISABLE; + buf[11] = 0; - /* flush driver and line discipline buffers */ - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); - tty_ldisc_flush(tty); + /* disable receive */ + buf[12] = DIGI_CMD_RECEIVE_ENABLE; + buf[13] = priv->dp_port_num; + buf[14] = DIGI_DISABLE; + buf[15] = 0; - if (port->serial->dev) { - /* wait for transmit idle */ - if ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0) { - digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT); - } - /* drop DTR and RTS */ - digi_set_modem_signals(port, 0, 0); - - /* disable input flow control */ - buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL; - buf[1] = priv->dp_port_num; - buf[2] = DIGI_DISABLE; - buf[3] = 0; - - /* disable output flow control */ - buf[4] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL; - buf[5] = priv->dp_port_num; - buf[6] = DIGI_DISABLE; - buf[7] = 0; - - /* disable reading modem signals automatically */ - buf[8] = DIGI_CMD_READ_INPUT_SIGNALS; - buf[9] = priv->dp_port_num; - buf[10] = DIGI_DISABLE; - buf[11] = 0; - - /* disable receive */ - buf[12] = DIGI_CMD_RECEIVE_ENABLE; - buf[13] = priv->dp_port_num; - buf[14] = DIGI_DISABLE; - buf[15] = 0; - - /* flush fifos */ - buf[16] = DIGI_CMD_IFLUSH_FIFO; - buf[17] = priv->dp_port_num; - buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX; - buf[19] = 0; - - if ((ret = digi_write_oob_command(port, buf, 20, 0)) != 0) - dbg("digi_close: write oob failed, ret=%d", ret); - - /* wait for final commands on oob port to complete */ - prepare_to_wait(&priv->dp_flush_wait, &wait, TASK_INTERRUPTIBLE); - schedule_timeout(DIGI_CLOSE_TIMEOUT); - finish_wait(&priv->dp_flush_wait, &wait); - - /* shutdown any outstanding bulk writes */ - usb_kill_urb(port->write_urb); - } - tty->closing = 0; + /* flush fifos */ + buf[16] = DIGI_CMD_IFLUSH_FIFO; + buf[17] = priv->dp_port_num; + buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX; + buf[19] = 0; + + ret = digi_write_oob_command(port, buf, 20, 0); + if (ret != 0) + dev_dbg(&port->dev, "digi_close: write oob failed, ret=%d\n", + ret); + /* wait for final commands on oob port to complete */ + prepare_to_wait(&priv->dp_flush_wait, &wait, + TASK_INTERRUPTIBLE); + schedule_timeout(DIGI_CLOSE_TIMEOUT); + finish_wait(&priv->dp_flush_wait, &wait); + + /* shutdown any outstanding bulk writes */ + usb_kill_urb(port->write_urb); exit: spin_lock_irq(&priv->dp_port_lock); priv->dp_write_urb_in_use = 0; - priv->dp_in_close = 0; wake_up_interruptible(&priv->dp_close_wait); spin_unlock_irq(&priv->dp_port_lock); mutex_unlock(&port->serial->disc_mutex); - dbg("digi_close: done"); } /* -* Digi Startup Device -* -* Starts reads on all ports. Must be called AFTER startup, with -* urbs initialized. Returns 0 if successful, non-zero error otherwise. -*/ + * Digi Startup Device + * + * Starts reads on all ports. Must be called AFTER startup, with + * urbs initialized. Returns 0 if successful, non-zero error otherwise. + */ static int digi_startup_device(struct usb_serial *serial) { - int i,ret = 0; + int i, ret = 0; struct digi_serial *serial_priv = usb_get_serial_data(serial); struct usb_serial_port *port; @@ -1518,124 +1216,135 @@ static int digi_startup_device(struct usb_serial *serial) /* set USB_DISABLE_SPD flag for write bulk urbs */ for (i = 0; i < serial->type->num_ports + 1; i++) { port = serial->port[i]; - port->write_urb->dev = port->serial->dev; - if ((ret = usb_submit_urb(port->read_urb, GFP_KERNEL)) != 0) { - err("%s: usb_submit_urb failed, ret=%d, port=%d", - __FUNCTION__, ret, i); + ret = usb_submit_urb(port->read_urb, GFP_KERNEL); + if (ret != 0) { + dev_err(&port->dev, + "%s: usb_submit_urb failed, ret=%d, port=%d\n", + __func__, ret, i); break; } } return ret; } - -static int digi_startup(struct usb_serial *serial) +static int digi_port_init(struct usb_serial_port *port, unsigned port_num) { - - int i; struct digi_port *priv; - struct digi_serial *serial_priv; - dbg("digi_startup: TOP"); - - /* allocate the private data structures for all ports */ - /* number of regular ports + 1 for the out-of-band port */ - for(i = 0; i < serial->type->num_ports + 1; i++) { - /* allocate port private structure */ - priv = kmalloc(sizeof(struct digi_port), GFP_KERNEL); - if (priv == NULL) { - while (--i >= 0) - kfree(usb_get_serial_port_data(serial->port[i])); - return 1; /* error */ - } + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; - /* initialize port private structure */ - spin_lock_init(&priv->dp_port_lock); - priv->dp_port_num = i; - priv->dp_out_buf_len = 0; - priv->dp_write_urb_in_use = 0; - priv->dp_modem_signals = 0; - init_waitqueue_head(&priv->dp_modem_change_wait); - priv->dp_transmit_idle = 0; - init_waitqueue_head(&priv->dp_transmit_idle_wait); - priv->dp_throttled = 0; - priv->dp_throttle_restart = 0; - init_waitqueue_head(&priv->dp_flush_wait); - priv->dp_in_close = 0; - init_waitqueue_head(&priv->dp_close_wait); - INIT_WORK(&priv->dp_wakeup_work, digi_wakeup_write_lock); - priv->dp_port = serial->port[i]; - /* initialize write wait queue for this port */ - init_waitqueue_head(&serial->port[i]->write_wait); - - usb_set_serial_port_data(serial->port[i], priv); - } + spin_lock_init(&priv->dp_port_lock); + priv->dp_port_num = port_num; + init_waitqueue_head(&priv->dp_transmit_idle_wait); + init_waitqueue_head(&priv->dp_flush_wait); + init_waitqueue_head(&priv->dp_close_wait); + INIT_WORK(&priv->dp_wakeup_work, digi_wakeup_write_lock); + priv->dp_port = port; - /* allocate serial private structure */ - serial_priv = kmalloc(sizeof(struct digi_serial), GFP_KERNEL); - if (serial_priv == NULL) { - for (i = 0; i < serial->type->num_ports + 1; i++) - kfree(usb_get_serial_port_data(serial->port[i])); - return 1; /* error */ - } + init_waitqueue_head(&port->write_wait); + + usb_set_serial_port_data(port, priv); + + return 0; +} + +static int digi_startup(struct usb_serial *serial) +{ + struct digi_serial *serial_priv; + int ret; + + serial_priv = kzalloc(sizeof(*serial_priv), GFP_KERNEL); + if (!serial_priv) + return -ENOMEM; - /* initialize serial private structure */ spin_lock_init(&serial_priv->ds_serial_lock); serial_priv->ds_oob_port_num = serial->type->num_ports; serial_priv->ds_oob_port = serial->port[serial_priv->ds_oob_port_num]; - serial_priv->ds_device_started = 0; + + ret = digi_port_init(serial_priv->ds_oob_port, + serial_priv->ds_oob_port_num); + if (ret) { + kfree(serial_priv); + return ret; + } + usb_set_serial_data(serial, serial_priv); return 0; } -static void digi_shutdown(struct usb_serial *serial) +static void digi_disconnect(struct usb_serial *serial) { int i; - dbg("digi_shutdown: TOP, in_interrupt()=%ld", in_interrupt()); /* stop reads and writes on all ports */ for (i = 0; i < serial->type->num_ports + 1; i++) { usb_kill_urb(serial->port[i]->read_urb); usb_kill_urb(serial->port[i]->write_urb); } +} + + +static void digi_release(struct usb_serial *serial) +{ + struct digi_serial *serial_priv; + struct digi_port *priv; + + serial_priv = usb_get_serial_data(serial); + + priv = usb_get_serial_port_data(serial_priv->ds_oob_port); + kfree(priv); + + kfree(serial_priv); +} - /* free the private data structures for all ports */ - /* number of regular ports + 1 for the out-of-band port */ - for(i = 0; i < serial->type->num_ports + 1; i++) - kfree(usb_get_serial_port_data(serial->port[i])); - kfree(usb_get_serial_data(serial)); +static int digi_port_probe(struct usb_serial_port *port) +{ + return digi_port_init(port, port->port_number); } +static int digi_port_remove(struct usb_serial_port *port) +{ + struct digi_port *priv; + + priv = usb_get_serial_port_data(port); + kfree(priv); + + return 0; +} static void digi_read_bulk_callback(struct urb *urb) { - struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct usb_serial_port *port = urb->context; struct digi_port *priv; struct digi_serial *serial_priv; int ret; int status = urb->status; - dbg("digi_read_bulk_callback: TOP"); - /* port sanity check, do not resubmit if port is not valid */ - if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) { - err("%s: port or port->private is NULL, status=%d", - __FUNCTION__, status); + if (port == NULL) + return; + priv = usb_get_serial_port_data(port); + if (priv == NULL) { + dev_err(&port->dev, "%s: port->private is NULL, status=%d\n", + __func__, status); return; } if (port->serial == NULL || - (serial_priv=usb_get_serial_data(port->serial)) == NULL) { - err("%s: serial is bad or serial->private is NULL, status=%d", - __FUNCTION__, status); + (serial_priv = usb_get_serial_data(port->serial)) == NULL) { + dev_err(&port->dev, "%s: serial is bad or serial->private " + "is NULL, status=%d\n", __func__, status); return; } /* do not resubmit urb if it has any status error */ if (status) { - err("%s: nonzero read bulk status: status=%d, port=%d", - __FUNCTION__, status, priv->dp_port_num); + dev_err(&port->dev, + "%s: nonzero read bulk status: status=%d, port=%d\n", + __func__, status, priv->dp_port_num); return; } @@ -1649,49 +1358,48 @@ static void digi_read_bulk_callback(struct urb *urb) } /* continue read */ - urb->dev = port->serial->dev; - if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) != 0) { - err("%s: failed resubmitting urb, ret=%d, port=%d", - __FUNCTION__, ret, priv->dp_port_num); + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret != 0 && ret != -EPERM) { + dev_err(&port->dev, + "%s: failed resubmitting urb, ret=%d, port=%d\n", + __func__, ret, priv->dp_port_num); } } -/* -* Digi Read INB Callback -* -* Digi Read INB Callback handles reads on the in band ports, sending -* the data on to the tty subsystem. When called we know port and -* port->private are not NULL and port->serial has been validated. -* It returns 0 if successful, 1 if successful but the port is -* throttled, and -1 if the sanity checks failed. -*/ +/* + * Digi Read INB Callback + * + * Digi Read INB Callback handles reads on the in band ports, sending + * the data on to the tty subsystem. When called we know port and + * port->private are not NULL and port->serial has been validated. + * It returns 0 if successful, 1 if successful but the port is + * throttled, and -1 if the sanity checks failed. + */ static int digi_read_inb_callback(struct urb *urb) { - - struct usb_serial_port *port = (struct usb_serial_port *)urb->context; - struct tty_struct *tty = port->tty; + struct usb_serial_port *port = urb->context; struct digi_port *priv = usb_get_serial_port_data(port); int opcode = ((unsigned char *)urb->transfer_buffer)[0]; int len = ((unsigned char *)urb->transfer_buffer)[1]; int port_status = ((unsigned char *)urb->transfer_buffer)[2]; - unsigned char *data = ((unsigned char *)urb->transfer_buffer)+3; - int flag,throttled; - int i; + unsigned char *data = ((unsigned char *)urb->transfer_buffer) + 3; + int flag, throttled; int status = urb->status; /* do not process callbacks on closed ports */ /* but do continue the read chain */ - if (port->open_count == 0) + if (urb->status == -ENOENT) return 0; /* short/multiple packet check */ if (urb->actual_length != len + 2) { - err("%s: INCOMPLETE OR MULTIPLE PACKET, urb->status=%d, " - "port=%d, opcode=%d, len=%d, actual_length=%d, " - "status=%d", __FUNCTION__, status, priv->dp_port_num, - opcode, len, urb->actual_length, port_status); + dev_err(&port->dev, "%s: INCOMPLETE OR MULTIPLE PACKET, " + "status=%d, port=%d, opcode=%d, len=%d, " + "actual_length=%d, status=%d\n", __func__, status, + priv->dp_port_num, opcode, len, urb->actual_length, + port_status); return -1; } @@ -1710,7 +1418,7 @@ static int digi_read_inb_callback(struct urb *urb) /* overrun is special, not associated with a char */ if (port_status & DIGI_OVERRUN_ERROR) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); /* break takes precedence over parity, */ /* which takes precedence over framing errors */ @@ -1723,60 +1431,52 @@ static int digi_read_inb_callback(struct urb *urb) /* data length is len-1 (one byte of len is port_status) */ --len; - - len = tty_buffer_request_room(tty, len); if (len > 0) { - /* Hot path */ - if (flag == TTY_NORMAL) - tty_insert_flip_string(tty, data, len); - else { - for(i = 0; i < len; i++) - tty_insert_flip_char(tty, data[i], flag); - } - tty_flip_buffer_push(tty); + tty_insert_flip_string_fixed_flag(&port->port, data, + flag, len); + tty_flip_buffer_push(&port->port); } } spin_unlock(&priv->dp_port_lock); if (opcode == DIGI_CMD_RECEIVE_DISABLE) - dbg("%s: got RECEIVE_DISABLE", __FUNCTION__); + dev_dbg(&port->dev, "%s: got RECEIVE_DISABLE\n", __func__); else if (opcode != DIGI_CMD_RECEIVE_DATA) - dbg("%s: unknown opcode: %d", __FUNCTION__, opcode); + dev_dbg(&port->dev, "%s: unknown opcode: %d\n", __func__, opcode); - return(throttled ? 1 : 0); + return throttled ? 1 : 0; } -/* -* Digi Read OOB Callback -* -* Digi Read OOB Callback handles reads on the out of band port. -* When called we know port and port->private are not NULL and -* the port->serial is valid. It returns 0 if successful, and -* -1 if the sanity checks failed. -*/ +/* + * Digi Read OOB Callback + * + * Digi Read OOB Callback handles reads on the out of band port. + * When called we know port and port->private are not NULL and + * the port->serial is valid. It returns 0 if successful, and + * -1 if the sanity checks failed. + */ static int digi_read_oob_callback(struct urb *urb) { - struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct usb_serial_port *port = urb->context; struct usb_serial *serial = port->serial; + struct tty_struct *tty; struct digi_port *priv = usb_get_serial_port_data(port); int opcode, line, status, val; int i; - - dbg("digi_read_oob_callback: port=%d, len=%d", - priv->dp_port_num, urb->actual_length); + unsigned int rts; /* handle each oob command */ - for(i = 0; i < urb->actual_length - 3;) { + for (i = 0; i < urb->actual_length - 3;) { opcode = ((unsigned char *)urb->transfer_buffer)[i++]; line = ((unsigned char *)urb->transfer_buffer)[i++]; status = ((unsigned char *)urb->transfer_buffer)[i++]; val = ((unsigned char *)urb->transfer_buffer)[i++]; - dbg("digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d", + dev_dbg(&port->dev, "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d\n", opcode, line, status, val); if (status != 0 || line >= serial->type->num_ports) @@ -1784,27 +1484,31 @@ static int digi_read_oob_callback(struct urb *urb) port = serial->port[line]; - if ((priv=usb_get_serial_port_data(port)) == NULL) + priv = usb_get_serial_port_data(port); + if (priv == NULL) return -1; - if (opcode == DIGI_CMD_READ_INPUT_SIGNALS) { + tty = tty_port_tty_get(&port->port); + + rts = 0; + if (tty) + rts = tty->termios.c_cflag & CRTSCTS; + + if (tty && opcode == DIGI_CMD_READ_INPUT_SIGNALS) { spin_lock(&priv->dp_port_lock); /* convert from digi flags to termiox flags */ if (val & DIGI_READ_INPUT_SIGNALS_CTS) { priv->dp_modem_signals |= TIOCM_CTS; /* port must be open to use tty struct */ - if (port->open_count - && port->tty->termios->c_cflag & CRTSCTS) { - port->tty->hw_stopped = 0; - digi_wakeup_write(port); + if (rts) { + tty->hw_stopped = 0; + tty_port_tty_wakeup(&port->port); } } else { priv->dp_modem_signals &= ~TIOCM_CTS; /* port must be open to use tty struct */ - if (port->open_count - && port->tty->termios->c_cflag & CRTSCTS) { - port->tty->hw_stopped = 1; - } + if (rts) + tty->hw_stopped = 1; } if (val & DIGI_READ_INPUT_SIGNALS_DSR) priv->dp_modem_signals |= TIOCM_DSR; @@ -1819,7 +1523,6 @@ static int digi_read_oob_callback(struct urb *urb) else priv->dp_modem_signals &= ~TIOCM_CD; - wake_up_interruptible(&priv->dp_modem_change_wait); spin_unlock(&priv->dp_port_lock); } else if (opcode == DIGI_CMD_TRANSMIT_IDLE) { spin_lock(&priv->dp_port_lock); @@ -1829,48 +1532,14 @@ static int digi_read_oob_callback(struct urb *urb) } else if (opcode == DIGI_CMD_IFLUSH_FIFO) { wake_up_interruptible(&priv->dp_flush_wait); } + tty_kref_put(tty); } return 0; } -static int __init digi_init(void) -{ - int retval; - retval = usb_serial_register(&digi_acceleport_2_device); - if (retval) - goto failed_acceleport_2_device; - retval = usb_serial_register(&digi_acceleport_4_device); - if (retval) - goto failed_acceleport_4_device; - retval = usb_register(&digi_driver); - if (retval) - goto failed_usb_register; - info(DRIVER_VERSION ":" DRIVER_DESC); - return 0; -failed_usb_register: - usb_serial_deregister(&digi_acceleport_4_device); -failed_acceleport_4_device: - usb_serial_deregister(&digi_acceleport_2_device); -failed_acceleport_2_device: - return retval; -} - -static void __exit digi_exit (void) -{ - usb_deregister(&digi_driver); - usb_serial_deregister(&digi_acceleport_2_device); - usb_serial_deregister(&digi_acceleport_4_device); -} - - -module_init(digi_init); -module_exit(digi_exit); - +module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); |
