diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-10-05 01:18:40 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-10-05 01:18:40 +0000 |
commit | 012bb3e61e5eced6c610f9e036372bf0c8def2d1 (patch) | |
tree | 87efc733f9b164e8c85c0336f92c8fb7eff6d183 /drivers/usb/serial | |
parent | 625a1589d3d6464b5d90b8a0918789e3afffd220 (diff) |
Merge with Linux 2.4.0-test9. Please check DECstation, I had a number
of rejects to fixup while integrating Linus patches. I also found
that this kernel will only boot SMP on Origin; the UP kernel freeze
soon after bootup with SCSI timeout messages. I commit this anyway
since I found that the last CVS versions had the same problem.
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r-- | drivers/usb/serial/digi_acceleport.c | 4 | ||||
-rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 42 | ||||
-rw-r--r-- | drivers/usb/serial/keyspan.c | 4 | ||||
-rw-r--r-- | drivers/usb/serial/keyspan_pda.c | 141 | ||||
-rw-r--r-- | drivers/usb/serial/omninet.c | 163 | ||||
-rw-r--r-- | drivers/usb/serial/usb-serial.h | 36 | ||||
-rw-r--r-- | drivers/usb/serial/usbserial.c | 129 | ||||
-rw-r--r-- | drivers/usb/serial/visor.c | 255 | ||||
-rw-r--r-- | drivers/usb/serial/whiteheat.c | 35 |
9 files changed, 513 insertions, 296 deletions
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index f168b1bfc..8fabc8364 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -2014,7 +2014,7 @@ opcode, line, status, val ); } -int digi_init (void) +static int __init digi_init (void) { usb_serial_register (&digi_acceleport_2_device); usb_serial_register (&digi_acceleport_4_device); @@ -2022,7 +2022,7 @@ int digi_init (void) } -void digi_exit (void) +static void __exit digi_exit (void) { usb_serial_deregister (&digi_acceleport_2_device); usb_serial_deregister (&digi_acceleport_4_device); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index aa156ba8d..06c4a0506 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -12,6 +12,9 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (09/11/2000) gkh + * Removed DEBUG #ifdefs with call to usb_serial_debug_data + * * (07/19/2000) gkh * Added module_init and module_exit functions to handle the fact that this * driver is a loadable module now. @@ -331,26 +334,9 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user, first_byte = port->write_urb->transfer_buffer; *first_byte = 1 | ((count-data_offset) << 2) ; -#ifdef CONFIG_USB_SERIAL_DEBUG dbg("Bytes: %d, Control Byte: 0o%03o",count, first_byte[0]); - - if (count) { - int i; - printk (KERN_DEBUG __FILE__ ": data written - length = %d, data = ", count); - for (i = 0; i < count; ++i) { - printk ( "0x%02x ", first_byte[i]); - if (first_byte[i] > ' ' && first_byte[i] < '~') { - printk( "%c ", first_byte[i]); - } else { - printk( " "); - } - } - - - printk ( "\n"); - } - -#endif + usb_serial_debug_data (__FILE__, __FUNCTION__, count, first_byte); + /* send the data out the bulk port */ port->write_urb->transfer_buffer_length = count; @@ -429,23 +415,11 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb) return; } -#ifdef CONFIG_USB_SERIAL_DEBUG if (urb->actual_length > 2) { - printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length); - for (i = 0; i < urb->actual_length; ++i) { - printk ( "0x%.2x ", data[i]); - if (data[i] > ' ' && data[i] < '~') { - printk( "%c ", data[i]); - } else { - printk( " "); - } - } - printk ( "\n"); + usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); } else { dbg("Just status"); } -#endif - if (urb->actual_length > data_offset) { for (i = data_offset ; i < urb->actual_length ; ++i) { @@ -725,14 +699,14 @@ static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, uns } /* ftdi_sio_ioctl */ -int ftdi_sio_init (void) +static int __init ftdi_sio_init (void) { usb_serial_register (&ftdi_sio_device); return 0; } -void ftdi_sio_exit (void) +static void __exit ftdi_sio_exit (void) { usb_serial_deregister (&ftdi_sio_device); } diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 64a1f709e..7a1d02609 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -687,7 +687,7 @@ static void keyspan_shutdown (struct usb_serial *serial) } -int keyspan_init (void) +static int __init keyspan_init (void) { usb_serial_register (&keyspan_usa18x_pre_device); usb_serial_register (&keyspan_usa19_pre_device); @@ -703,7 +703,7 @@ int keyspan_init (void) } -void keyspan_exit (void) +static void __exit keyspan_exit (void) { usb_serial_deregister (&keyspan_usa18x_pre_device); usb_serial_deregister (&keyspan_usa19_pre_device); diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index e118e29b8..537ad80c9 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -12,6 +12,11 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (08/28/2000) gkh + * Added locks for SMP safeness. + * Fixed MOD_INC and MOD_DEC logic and the ability to open a port more + * than once. + * * (07/20/2000) borchers * - keyspan_pda_write no longer sleeps if it is called on interrupt time; * PPP and the line discipline with stty echo on can call write on @@ -416,6 +421,7 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user, int request_unthrottle = 0; int rc = 0; struct keyspan_pda_private *priv; + unsigned long flags; priv = (struct keyspan_pda_private *)(port->private); /* guess how much room is left in the device's ring buffer, and if we @@ -445,6 +451,7 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user, finished). Also, the tx process is not throttled. So we are ready to write. */ + spin_lock_irqsave (&port->port_lock, flags); count = (count > port->bulk_out_size) ? port->bulk_out_size : count; /* Check if we might overrun the Tx buffer. If so, ask the @@ -464,10 +471,12 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user, 2*HZ); if (rc < 0) { dbg(" roomquery failed"); + spin_unlock_irqrestore (&port->port_lock, flags); return rc; /* failed */ } if (rc == 0) { dbg(" roomquery returned 0 bytes"); + spin_unlock_irqrestore (&port->port_lock, flags); return -EIO; /* device didn't return any data */ } dbg(" roomquery says %d", room); @@ -484,8 +493,10 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user, /* now transfer data */ if (from_user) { if( copy_from_user(port->write_urb->transfer_buffer, - buf, count) ) + buf, count) ) { + spin_unlock_irqrestore (&port->port_lock, flags); return( -EFAULT ); + } } else { memcpy (port->write_urb->transfer_buffer, buf, count); @@ -495,8 +506,11 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user, priv->tx_room -= count; - if (usb_submit_urb(port->write_urb)) + if (usb_submit_urb(port->write_urb)) { dbg(" usb_submit_urb(write bulk) failed"); + spin_unlock_irqrestore (&port->port_lock, flags); + return (0); + } } else { /* There wasn't any room left, so we are throttled until @@ -509,6 +523,7 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user, queue_task( &priv->unthrottle_task, &tq_scheduler ); } + spin_unlock_irqrestore (&port->port_lock, flags); return (count); } @@ -568,61 +583,92 @@ static int keyspan_pda_open (struct usb_serial_port *port, struct file *filp) unsigned char room; int rc; struct keyspan_pda_private *priv; - priv = (struct keyspan_pda_private *)(port->private); + unsigned long flags; - if (port->active) { - return -EINVAL; - } - port->active = 1; + spin_lock_irqsave (&port->port_lock, flags); + + MOD_INC_USE_COUNT; + ++port->open_count; + + if (!port->active) { + port->active = 1; - /* find out how much room is in the Tx ring */ - rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - 6, /* write_room */ - USB_TYPE_VENDOR | USB_RECIP_INTERFACE - | USB_DIR_IN, - 0, /* value */ - 0, /* index */ - &room, - 1, - 2*HZ); - if (rc < 0) { - dbg(" roomquery failed"); - return rc; /* failed */ - } - if (rc == 0) { - dbg(" roomquery returned 0 bytes"); - return -EIO; /* device didn't return any data */ - } - priv->tx_room = room; - priv->tx_throttled = room ? 0 : 1; + /* find out how much room is in the Tx ring */ + spin_unlock_irqrestore (&port->port_lock, flags); + rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + 6, /* write_room */ + USB_TYPE_VENDOR | USB_RECIP_INTERFACE + | USB_DIR_IN, + 0, /* value */ + 0, /* index */ + &room, + 1, + 2*HZ); + spin_lock_irqsave (&port->port_lock, flags); + if (rc < 0) { + dbg(__FUNCTION__" - roomquery failed"); + goto error; + } + if (rc == 0) { + dbg(__FUNCTION__" - roomquery returned 0 bytes"); + rc = -EIO; + goto error; + } + priv = (struct keyspan_pda_private *)(port->private); + priv->tx_room = room; + priv->tx_throttled = room ? 0 : 1; - /* the normal serial device seems to always turn on DTR and RTS here, - so do the same */ - if (port->tty->termios->c_cflag & CBAUD) - keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2) ); - else - keyspan_pda_set_modem_info(serial, 0); + /* the normal serial device seems to always turn on DTR and RTS here, + so do the same */ + spin_unlock_irqrestore (&port->port_lock, flags); + if (port->tty->termios->c_cflag & CBAUD) + keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2) ); + else + keyspan_pda_set_modem_info(serial, 0); + + /*Start reading from the device*/ + if (usb_submit_urb(port->interrupt_in_urb)) + dbg(__FUNCTION__" - usb_submit_urb(read int) failed"); + } else { + spin_unlock_irqrestore (&port->port_lock, flags); + } - /*Start reading from the device*/ - if (usb_submit_urb(port->interrupt_in_urb)) - dbg(" usb_submit_urb(read int) failed"); return (0); +error: + --port->open_count; + port->active = 0; + MOD_DEC_USE_COUNT; + spin_unlock_irqrestore (&port->port_lock, flags); + return rc; } static void keyspan_pda_close(struct usb_serial_port *port, struct file *filp) { struct usb_serial *serial = port->serial; + unsigned long flags; - /* the normal serial device seems to always shut off DTR and RTS now */ - if (port->tty->termios->c_cflag & HUPCL) - keyspan_pda_set_modem_info(serial, 0); + spin_lock_irqsave (&port->port_lock, flags); - /* shutdown our bulk reads and writes */ - usb_unlink_urb (port->write_urb); - usb_unlink_urb (port->interrupt_in_urb); - port->active = 0; + --port->open_count; + MOD_DEC_USE_COUNT; + + if (port->open_count <= 0) { + /* the normal serial device seems to always shut off DTR and RTS now */ + spin_unlock_irqrestore (&port->port_lock, flags); + if (port->tty->termios->c_cflag & HUPCL) + keyspan_pda_set_modem_info(serial, 0); + spin_lock_irqsave (&port->port_lock, flags); + + /* shutdown our bulk reads and writes */ + usb_unlink_urb (port->write_urb); + usb_unlink_urb (port->interrupt_in_urb); + port->active = 0; + port->open_count = 0; + } + + spin_unlock_irqrestore (&port->port_lock, flags); } @@ -683,6 +729,11 @@ static int keyspan_pda_startup (struct usb_serial *serial) static void keyspan_pda_shutdown (struct usb_serial *serial) { + dbg (__FUNCTION__); + + while (serial->port[0].open_count > 0) { + keyspan_pda_close (&serial->port[0], NULL); + } kfree(serial->port[0].private); } @@ -728,7 +779,7 @@ struct usb_serial_device_type keyspan_pda_device = { }; -int keyspan_pda_init (void) +static int __init keyspan_pda_init (void) { usb_serial_register (&keyspan_pda_fake_device); usb_serial_register (&keyspan_pda_device); @@ -736,7 +787,7 @@ int keyspan_pda_init (void) } -void keyspan_pda_exit (void) +static void __exit keyspan_pda_exit (void) { usb_serial_deregister (&keyspan_pda_fake_device); usb_serial_deregister (&keyspan_pda_device); diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 7a68a0072..1d1bd088c 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -10,6 +10,12 @@ * * Please report both successes and troubles to the author at omninet@kroah.com * + * (08/28/2000) gkh + * Added locks for SMP safeness. + * Fixed MOD_INC and MOD_DEC logic and the ability to open a port more + * than once. + * Fixed potential race in omninet_write_bulk_callback + * * (07/19/2000) gkh * Added module_init and module_exit functions to handle the fact that this * driver is a loadable module now. @@ -54,6 +60,7 @@ static void omninet_read_bulk_callback (struct urb *urb); static void omninet_write_bulk_callback (struct urb *urb); static int omninet_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count); static int omninet_write_room (struct usb_serial_port *port); +static void omninet_shutdown (struct usb_serial *serial); /* All of the device info needed for the omni.net */ static __u16 zyxel_vendor_id = ZYXEL_VENDOR_ID; @@ -76,6 +83,7 @@ struct usb_serial_device_type zyxel_omninet_device = { write_room: omninet_write_room, read_bulk_callback: omninet_read_bulk_callback, write_bulk_callback: omninet_write_bulk_callback, + shutdown: omninet_shutdown, }; @@ -117,52 +125,87 @@ struct omninet_data static int omninet_open (struct usb_serial_port *port, struct file *filp) { - struct usb_serial *serial = port->serial; - struct usb_serial_port *wport = &serial->port[1]; - struct omninet_data *od; + struct usb_serial *serial; + struct usb_serial_port *wport; + struct omninet_data *od; + unsigned long flags; - dbg("omninet_open port %d", port->number); + if (port_paranoia_check (port, __FUNCTION__)) + return -ENODEV; - if (port->active) { - dbg ("device already open"); - return -EINVAL; - } - port->active = 1; + dbg(__FUNCTION__ " - port %d", port->number); - od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL ); + serial = get_usb_serial (port, __FUNCTION__); + if (!serial) + return -ENODEV; - if( !od ) - { - err("omninet_open: kmalloc(%d) failed.", sizeof(struct omninet_data)); - return -ENOMEM; - } + spin_lock_irqsave (&port->port_lock, flags); + + MOD_INC_USE_COUNT; + ++port->open_count; + + if (!port->active) { + port->active = 1; + + od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL ); + if( !od ) { + err(__FUNCTION__"- kmalloc(%d) failed.", sizeof(struct omninet_data)); + --port->open_count; + port->active = 0; + spin_unlock_irqrestore (&port->port_lock, flags); + MOD_DEC_USE_COUNT; + return -ENOMEM; + } - port->private = od; + port->private = od; + wport = &serial->port[1]; + wport->tty = port->tty; - /* Start reading from the device */ - if (usb_submit_urb(port->read_urb)) - dbg("usb_submit_urb(read bulk, %p) failed", port->read_urb); + /* Start reading from the device */ + if (usb_submit_urb(port->read_urb)) + dbg(__FUNCTION__" - read bulk (%p) failed", port->read_urb); + } - wport->tty = port->tty; + spin_unlock_irqrestore (&port->port_lock, flags); return (0); } static void omninet_close (struct usb_serial_port *port, struct file * filp) { - struct usb_serial *serial = port->serial; - struct usb_serial_port *wport = &serial->port[1]; - struct omninet_data *od = (struct omninet_data *) port->private; + struct usb_serial *serial; + struct usb_serial_port *wport; + struct omninet_data *od; + unsigned long flags; + + if (port_paranoia_check (port, __FUNCTION__)) + return; + + dbg(__FUNCTION__ " - port %d", port->number); - port->active = 0; + serial = get_usb_serial (port, __FUNCTION__); + if (!serial) + return; + + spin_lock_irqsave (&port->port_lock, flags); + --port->open_count; + MOD_DEC_USE_COUNT; - dbg("zyxel_close port %d", port->number); + if (port->open_count <= 0) { + od = (struct omninet_data *)port->private; + wport = &serial->port[1]; - usb_unlink_urb (wport->write_urb); - usb_unlink_urb (port->read_urb); + usb_unlink_urb (wport->write_urb); + usb_unlink_urb (port->read_urb); - if(od) kfree(od); + port->active = 0; + port->open_count = 0; + if (od) + kfree(od); + } + + spin_unlock_irqrestore (&port->port_lock, flags); } @@ -173,7 +216,7 @@ static void omninet_close (struct usb_serial_port *port, struct file * filp) static void omninet_read_bulk_callback (struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; - struct usb_serial *serial = port->serial; + struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); unsigned char *data = urb->transfer_buffer; struct omninet_header *header = (struct omninet_header *) &data[0]; @@ -182,22 +225,18 @@ static void omninet_read_bulk_callback (struct urb *urb) // dbg("omninet_read_bulk_callback"); - if (port_paranoia_check (port, "omninet_read_bulk_callback")) { - return; - } - - if (serial_paranoia_check (serial, "omninet_read_bulk_callback")) { + if (!serial) { + dbg(__FUNCTION__ " - bad serial pointer, exiting"); return; } if (urb->status) { - dbg("nonzero read bulk status received: %d", urb->status); + dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status); return; } #ifdef DEBUG - if(header->oh_xxx != 0x30) - { + if(header->oh_xxx != 0x30) { if (urb->actual_length) { printk (KERN_DEBUG __FILE__ ": omninet_read %d: ", header->oh_len); for (i = 0; i < (header->oh_len + OMNINET_HEADERLEN); i++) { @@ -208,8 +247,7 @@ static void omninet_read_bulk_callback (struct urb *urb) } #endif - if (urb->actual_length && header->oh_len) - { + if (urb->actual_length && header->oh_len) { for (i = 0; i < header->oh_len; i++) { tty_insert_flip_char(port->tty, data[OMNINET_DATAOFFSET + i], 0); } @@ -218,7 +256,7 @@ static void omninet_read_bulk_callback (struct urb *urb) /* Continue trying to always read */ if (usb_submit_urb(urb)) - dbg("failed resubmitting read urb"); + dbg(__FUNCTION__" - failed resubmitting read urb"); return; } @@ -230,6 +268,8 @@ static int omninet_write (struct usb_serial_port *port, int from_user, const uns struct omninet_data *od = (struct omninet_data *) port->private; struct omninet_header *header = (struct omninet_header *) wport->write_urb->transfer_buffer; + + unsigned long flags; /* #ifdef DEBUG int i; @@ -239,7 +279,7 @@ static int omninet_write (struct usb_serial_port *port, int from_user, const uns // dbg("omninet_write port %d", port->number); if (count == 0) { - dbg("write request of 0 bytes"); + dbg(__FUNCTION__" - write request of 0 bytes"); return (0); } /* @@ -255,10 +295,12 @@ static int omninet_write (struct usb_serial_port *port, int from_user, const uns #endif */ if (wport->write_urb->status == -EINPROGRESS) { - dbg ("already writing"); + dbg (__FUNCTION__" - already writing"); return (0); } + spin_lock_irqsave (&port->port_lock, flags); + count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count; if (from_user) { @@ -277,11 +319,15 @@ static int omninet_write (struct usb_serial_port *port, int from_user, const uns /* send the data out the bulk port, always 64 bytes */ wport->write_urb->transfer_buffer_length = 64; - if (usb_submit_urb(wport->write_urb)) - dbg("usb_submit_urb(write bulk) failed"); + if (usb_submit_urb(wport->write_urb)) { + dbg(__FUNCTION__" - usb_submit_urb(write bulk) failed"); + spin_unlock_irqrestore (&port->port_lock, flags); + return 0; + } // dbg("omninet_write returns %d", count); + spin_unlock_irqrestore (&port->port_lock, flags); return (count); } @@ -306,31 +352,26 @@ static void omninet_write_bulk_callback (struct urb *urb) /* struct omninet_header *header = (struct omninet_header *) urb->transfer_buffer; */ struct usb_serial_port *port = (struct usb_serial_port *) urb->context; struct usb_serial *serial; - struct tty_struct *tty; // dbg("omninet_write_bulk_callback, port %0x\n", port); - if (port_paranoia_check (port, "omninet_write_bulk_callback")) { + if (port_paranoia_check (port, __FUNCTION__)) { return; } serial = port->serial; - if (serial_paranoia_check (serial, "omninet_write_bulk_callback")) { + if (serial_paranoia_check (serial, __FUNCTION__)) { return; } if (urb->status) { - dbg("nonzero write bulk status received: %d", urb->status); + dbg(__FUNCTION__" - nonzero write bulk status received: %d", urb->status); return; } - tty = port->tty; - - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - - wake_up_interruptible(&tty->write_wait); + queue_task(&port->tqueue, &tq_immediate); + mark_bh(IMMEDIATE_BH); // dbg("omninet_write_bulk_callback, tty %0x\n", tty); @@ -338,14 +379,24 @@ static void omninet_write_bulk_callback (struct urb *urb) } -int omninet_init (void) +static void omninet_shutdown (struct usb_serial *serial) +{ + dbg (__FUNCTION__); + + while (serial->port[0].open_count > 0) { + omninet_close (&serial->port[0], NULL); + } +} + + +static int __init omninet_init (void) { usb_serial_register (&zyxel_omninet_device); return 0; } -void omninet_exit (void) +static void __exit omninet_exit (void) { usb_serial_deregister (&zyxel_omninet_device); } diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h index 10d57076c..b589decff 100644 --- a/drivers/usb/serial/usb-serial.h +++ b/drivers/usb/serial/usb-serial.h @@ -11,6 +11,13 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (09/11/2000) gkh + * Added usb_serial_debug_data function to help get rid of #DEBUG in the + * drivers. + * + * (08/28/2000) gkh + * Added port_lock to port structure. + * * (08/08/2000) gkh * Added open_count to port structure. * @@ -63,6 +70,7 @@ struct usb_serial_port { struct tq_struct tqueue; /* task queue for line discipline waking up */ int open_count; /* number of times this port has been opened */ + spinlock_t port_lock; void * private; /* data private to the specific port */ }; @@ -185,5 +193,33 @@ static inline int port_paranoia_check (struct usb_serial_port *port, const char return 0; } + +static inline struct usb_serial* get_usb_serial (struct usb_serial_port *port, const char *function) +{ + /* if no port was specified, or it fails a paranoia check */ + if (!port || + port_paranoia_check (port, function) || + serial_paranoia_check (port->serial, function)) { + /* then say that we dont have a valid usb_serial thing, which will + * end up genrating -ENODEV return values */ + return NULL; + } + + return port->serial; +} + + +static inline void usb_serial_debug_data (const char *file, const char *function, int size, const unsigned char *data) +{ +#ifdef CONFIG_USB_SERIAL_DEBUG + int i; + printk (KERN_DEBUG "%s: %s - length = %d, data = ", file, function, size); + for (i = 0; i < size; ++i) { + printk ("%.2x ", data[i]); + } + printk ("\n"); +#endif +} + #endif /* ifdef __LINUX_USB_SERIAL_H */ diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c index 735aecaed..86c8755b8 100644 --- a/drivers/usb/serial/usbserial.c +++ b/drivers/usb/serial/usbserial.c @@ -15,6 +15,14 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (09/11/2000) gkh + * Removed DEBUG #ifdefs with call to usb_serial_debug_data + * + * (08/28/2000) gkh + * Added port_lock to port structure. + * Added locks for SMP safeness to generic driver + * Fixed the ability to open a generic device's port more than once. + * * (07/23/2000) gkh * Added bulk_out_endpointAddress to port structure. * @@ -264,6 +272,7 @@ static int generic_write_room (struct usb_serial_port *port); static int generic_chars_in_buffer (struct usb_serial_port *port); static void generic_read_bulk_callback (struct urb *urb); static void generic_write_bulk_callback (struct urb *urb); +static void generic_shutdown (struct usb_serial *serial); #ifdef CONFIG_USB_SERIAL_GENERIC @@ -287,6 +296,7 @@ static struct usb_serial_device_type generic_device = { num_bulk_in: NUM_DONT_CARE, num_bulk_out: NUM_DONT_CARE, num_ports: 1, + shutdown: generic_shutdown, }; #endif @@ -321,21 +331,6 @@ static struct usb_serial *serial_table[SERIAL_TTY_MINORS] = {NULL, }; LIST_HEAD(usb_serial_driver_list); -static inline struct usb_serial* get_usb_serial (struct usb_serial_port *port, const char *function) -{ - /* if no port was specified, or it fails a paranoia check */ - if (!port || - port_paranoia_check (port, function) || - serial_paranoia_check (port->serial, function)) { - /* then say that we dont have a valid usb_serial thing, which will - * end up genrating -ENODEV return values */ - return NULL; - } - - return port->serial; -} - - static struct usb_serial *get_serial_by_minor (int minor) { return serial_table[minor]; @@ -697,47 +692,65 @@ static void serial_break (struct tty_struct *tty, int break_state) static int generic_open (struct usb_serial_port *port, struct file *filp) { struct usb_serial *serial = port->serial; + unsigned long flags; + + if (port_paranoia_check (port, __FUNCTION__)) + return -ENODEV; dbg(__FUNCTION__ " - port %d", port->number); - if (port->active) { - dbg (__FUNCTION__ " - device already open"); - return -EINVAL; - } - port->active = 1; - - /* if we have a bulk interrupt, start reading from it */ - if (serial->num_bulk_in) { - /*Start reading from the device*/ - if (usb_submit_urb(port->read_urb)) - dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed"); - } + spin_lock_irqsave (&port->port_lock, flags); + + ++port->open_count; + MOD_INC_USE_COUNT; + + if (!port->active) { + port->active = 1; - return (0); + /* if we have a bulk interrupt, start reading from it */ + if (serial->num_bulk_in) { + /*Start reading from the device*/ + if (usb_submit_urb(port->read_urb)) + dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed"); + } + } + + spin_unlock_irqrestore (&port->port_lock, flags); + + return 0; } static void generic_close (struct usb_serial_port *port, struct file * filp) { struct usb_serial *serial = port->serial; + unsigned long flags; dbg(__FUNCTION__ " - port %d", port->number); - - /* shutdown any bulk reads that might be going on */ - if (serial->num_bulk_out) { - usb_unlink_urb (port->write_urb); - } - if (serial->num_bulk_in) { - usb_unlink_urb (port->read_urb); + + spin_lock_irqsave (&port->port_lock, flags); + + --port->open_count; + + if (port->open_count <= 0) { + /* shutdown any bulk reads that might be going on */ + if (serial->num_bulk_out) + usb_unlink_urb (port->write_urb); + if (serial->num_bulk_in) + usb_unlink_urb (port->read_urb); + + port->active = 0; + port->open_count = 0; } - port->active = 0; + spin_unlock_irqrestore (&port->port_lock, flags); } static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count) { struct usb_serial *serial = port->serial; + unsigned long flags; dbg(__FUNCTION__ " - port %d", port->number); @@ -753,18 +766,10 @@ static int generic_write (struct usb_serial_port *port, int from_user, const uns return (0); } + spin_lock_irqsave (&port->port_lock, flags); count = (count > port->bulk_out_size) ? port->bulk_out_size : count; -#ifdef DEBUG - { - int i; - printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", count); - for (i = 0; i < count; ++i) { - printk ("%.2x ", buf[i]); - } - printk ("\n"); - } -#endif + usb_serial_debug_data (__FILE__, __FUNCTION__, count, buf); if (from_user) { copy_from_user(port->write_urb->transfer_buffer, buf, count); @@ -776,9 +781,13 @@ static int generic_write (struct usb_serial_port *port, int from_user, const uns /* send the data out the bulk port */ port->write_urb->transfer_buffer_length = count; - if (usb_submit_urb(port->write_urb)) + if (usb_submit_urb(port->write_urb)) { dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed"); + spin_unlock_irqrestore (&port->port_lock, flags); + return 0; + } + spin_unlock_irqrestore (&port->port_lock, flags); return (count); } @@ -839,15 +848,7 @@ static void generic_read_bulk_callback (struct urb *urb) return; } -#ifdef DEBUG - if (urb->actual_length) { - printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", urb->actual_length); - for (i = 0; i < urb->actual_length; ++i) { - printk ("%.2x ", data[i]); - } - printk ("\n"); - } -#endif + usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); tty = port->tty; if (urb->actual_length) { @@ -889,6 +890,21 @@ static void generic_write_bulk_callback (struct urb *urb) } +static void generic_shutdown (struct usb_serial *serial) +{ + int i; + + dbg (__FUNCTION__); + + /* stop reads and writes on all ports */ + for (i=0; i < serial->num_ports; ++i) { + while (serial->port[i].open_count > 0) { + generic_close (&serial->port[i], NULL); + } + } +} + + static void port_softint(void *private) { struct usb_serial_port *port = (struct usb_serial_port *)private; @@ -1127,6 +1143,7 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum) port->magic = USB_SERIAL_PORT_MAGIC; port->tqueue.routine = port_softint; port->tqueue.data = port; + spin_lock_init (&port->port_lock); } /* initialize the devfs nodes for this device and let the user know what ports we are bound to */ diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index bc0ea807a..4245c1386 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -11,6 +11,20 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (09/11/2000) gkh + * Got rid of always calling kmalloc for every urb we wrote out to the + * device. + * Added visor_read_callback so we can keep track of bytes in and out for + * those people who like to know the speed of their device. + * Removed DEBUG #ifdefs with call to usb_serial_debug_data + * + * (09/06/2000) gkh + * Fixed oops in visor_exit. Need to uncomment usb_unlink_urb call _after_ + * the host controller drivers set urb->dev = NULL when the urb is finished. + * + * (08/28/2000) gkh + * Added locks for SMP safeness. + * * (08/08/2000) gkh * Fixed endian problem in visor_startup. * Fixed MOD_INC and MOD_DEC logic and the ability to open a port more @@ -68,6 +82,7 @@ #include "visor.h" +#define MIN(a,b) (((a)<(b))?(a):(b)) /* function prototypes for a handspring visor */ static int visor_open (struct usb_serial_port *port, struct file *filp); @@ -79,7 +94,8 @@ static int visor_startup (struct usb_serial *serial); static void visor_shutdown (struct usb_serial *serial); static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios); -static void visor_write_bulk_callback (struct urb *urb); +static void visor_write_bulk_callback (struct urb *urb); +static void visor_read_bulk_callback (struct urb *urb); /* All of the device info needed for the Handspring Visor */ static __u16 handspring_vendor_id = HANDSPRING_VENDOR_ID; @@ -105,11 +121,16 @@ struct usb_serial_device_type handspring_device = { set_termios: visor_set_termios, write: visor_write, write_bulk_callback: visor_write_bulk_callback, + read_bulk_callback: visor_read_bulk_callback, }; -#define NUM_URBS 24 -static struct urb *write_urb_pool[NUM_URBS]; +#define NUM_URBS 24 +#define URB_TRANSFER_BUFFER_SIZE 64 +static struct urb *write_urb_pool[NUM_URBS]; +static spinlock_t write_urb_pool_lock; +static int bytes_in; +static int bytes_out; /****************************************************************************** @@ -117,39 +138,56 @@ static struct urb *write_urb_pool[NUM_URBS]; ******************************************************************************/ static int visor_open (struct usb_serial_port *port, struct file *filp) { - dbg(__FUNCTION__ " - port %d", port->number); + unsigned long flags; - if (port->active) { - dbg (__FUNCTION__ " - device already open"); - return -EINVAL; - } + if (port_paranoia_check (port, __FUNCTION__)) + return -ENODEV; + + dbg(__FUNCTION__ " - port %d", port->number); + spin_lock_irqsave (&port->port_lock, flags); + ++port->open_count; MOD_INC_USE_COUNT; if (!port->active) { port->active = 1; + bytes_in = 0; + bytes_out = 0; /*Start reading from the device*/ if (usb_submit_urb(port->read_urb)) dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed"); } + spin_unlock_irqrestore (&port->port_lock, flags); + return 0; } static void visor_close (struct usb_serial_port *port, struct file * filp) { - struct usb_serial *serial = port->serial; - unsigned char *transfer_buffer = kmalloc (0x12, GFP_KERNEL); + struct usb_serial *serial; + unsigned char *transfer_buffer; + unsigned long flags; + + if (port_paranoia_check (port, __FUNCTION__)) + return; dbg(__FUNCTION__ " - port %d", port->number); + serial = get_usb_serial (port, __FUNCTION__); + if (!serial) + return; + + spin_lock_irqsave (&port->port_lock, flags); + --port->open_count; MOD_DEC_USE_COUNT; if (port->open_count <= 0) { + transfer_buffer = kmalloc (0x12, GFP_KERNEL); if (!transfer_buffer) { err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12); } else { @@ -163,73 +201,79 @@ static void visor_close (struct usb_serial_port *port, struct file * filp) usb_unlink_urb (port->read_urb); port->active = 0; port->open_count = 0; + } + spin_unlock_irqrestore (&port->port_lock, flags); + + /* Uncomment the following line if you want to see some statistics in your syslog */ + /* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */ } static int visor_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count) { struct usb_serial *serial = port->serial; - struct urb *urb = NULL; - unsigned char *buffer = NULL; + struct urb *urb; + const unsigned char *current_position = buf; + unsigned long flags; int status; int i; + int bytes_sent = 0; + int transfer_size; dbg(__FUNCTION__ " - port %d", port->number); - if (count == 0) { - dbg(__FUNCTION__ " - write request of 0 bytes"); - return 0; - } - - /* try to find a free urb in our list of them */ - for (i = 0; i < NUM_URBS; ++i) { - if (write_urb_pool[i]->status != -EINPROGRESS) { - urb = write_urb_pool[i]; - break; - } - } - if (urb == NULL) { - dbg (__FUNCTION__ " - no free urbs"); - return 0; - } - - count = (count > port->bulk_out_size) ? port->bulk_out_size : count; - -#ifdef DEBUG - printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", count); - for (i = 0; i < count; ++i) { - printk ("%.2x ", buf[i]); - } - printk ("\n"); -#endif - - if (urb->transfer_buffer != NULL) - kfree(urb->transfer_buffer); - buffer = kmalloc (count, GFP_KERNEL); - if (buffer == NULL) { - err(__FUNCTION__" no more kernel memory..."); - return 0; - } + usb_serial_debug_data (__FILE__, __FUNCTION__, count, buf); - if (from_user) { - copy_from_user(buffer, buf, count); + while (count > 0) { + /* try to find a free urb in our list of them */ + urb = NULL; + spin_lock_irqsave (&write_urb_pool_lock, flags); + for (i = 0; i < NUM_URBS; ++i) { + if (write_urb_pool[i]->status != -EINPROGRESS) { + urb = write_urb_pool[i]; + break; + } + } + spin_unlock_irqrestore (&write_urb_pool_lock, flags); + if (urb == NULL) { + dbg (__FUNCTION__ " - no more free urbs"); + goto exit; + } + if (urb->transfer_buffer == NULL) { + urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); + if (urb->transfer_buffer == NULL) { + err(__FUNCTION__" no more kernel memory..."); + goto exit; + } + } + + transfer_size = MIN (count, URB_TRANSFER_BUFFER_SIZE); + if (from_user) + copy_from_user (urb->transfer_buffer, current_position, transfer_size); + else + memcpy (urb->transfer_buffer, current_position, transfer_size); + + count = (count > port->bulk_out_size) ? port->bulk_out_size : count; + + /* build up our urb */ + FILL_BULK_URB (urb, serial->dev, usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), + urb->transfer_buffer, transfer_size, visor_write_bulk_callback, port); + urb->transfer_flags |= USB_QUEUE_BULK; + + /* send it down the pipe */ + status = usb_submit_urb(urb); + if (status) + dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status); + + current_position += transfer_size; + bytes_sent += transfer_size; + count -= transfer_size; + bytes_out += transfer_size; } - else { - memcpy (buffer, buf, count); - } - - /* build up our urb */ - FILL_BULK_URB (urb, serial->dev, usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), - buffer, count, visor_write_bulk_callback, port); - urb->transfer_flags |= USB_QUEUE_BULK; - /* send it down the pipe */ - status = usb_submit_urb(urb); - if (status) - dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status); - - return (count); +exit: + return bytes_sent; } @@ -254,23 +298,70 @@ static void visor_write_bulk_callback (struct urb *urb) } +static void visor_read_bulk_callback (struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct tty_struct *tty; + unsigned char *data = urb->transfer_buffer; + int i; + + if (port_paranoia_check (port, __FUNCTION__)) + return; + + dbg(__FUNCTION__ " - port %d", port->number); + + if (urb->status) { + dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status); + return; + } + + usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); + + tty = port->tty; + if (urb->actual_length) { + for (i = 0; i < urb->actual_length ; ++i) { + tty_insert_flip_char(tty, data[i], 0); + } + tty_flip_buffer_push(tty); + bytes_in += urb->actual_length; + } + + /* Continue trying to always read */ + if (usb_submit_urb(urb)) + dbg(__FUNCTION__ " - failed resubmitting read urb"); + return; +} + + static void visor_throttle (struct usb_serial_port *port) { + unsigned long flags; + dbg(__FUNCTION__ " - port %d", port->number); + spin_lock_irqsave (&port->port_lock, flags); + usb_unlink_urb (port->read_urb); + spin_unlock_irqrestore (&port->port_lock, flags); + return; } static void visor_unthrottle (struct usb_serial_port *port) { + unsigned long flags; + dbg(__FUNCTION__ " - port %d", port->number); + spin_lock_irqsave (&port->port_lock, flags); + if (usb_submit_urb (port->read_urb)) dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed"); + spin_unlock_irqrestore (&port->port_lock, flags); + return; } @@ -337,7 +428,7 @@ static int visor_startup (struct usb_serial *serial) kfree (transfer_buffer); /* continue on with initialization */ - return (0); + return 0; } @@ -429,39 +520,57 @@ static void visor_set_termios (struct usb_serial_port *port, struct termios *old } -int visor_init (void) +static int __init visor_init (void) { + struct urb *urb; int i; usb_serial_register (&handspring_device); - /* create our write urb pool */ + /* create our write urb pool and transfer buffers */ + spin_lock_init (&write_urb_pool_lock); for (i = 0; i < NUM_URBS; ++i) { - struct urb *urb = usb_alloc_urb(0); + urb = usb_alloc_urb(0); + write_urb_pool[i] = urb; if (urb == NULL) { err("No more urbs???"); continue; } + urb->transfer_buffer = NULL; - write_urb_pool[i] = urb; + urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); + if (!urb->transfer_buffer) { + err (__FUNCTION__ " - out of memory for urb buffers."); + continue; + } } return 0; } -void visor_exit (void) +static void __exit visor_exit (void) { int i; + unsigned long flags; usb_serial_deregister (&handspring_device); - + + spin_lock_irqsave (&write_urb_pool_lock, flags); + for (i = 0; i < NUM_URBS; ++i) { - usb_unlink_urb(write_urb_pool[i]); - if (write_urb_pool[i]->transfer_buffer) - kfree(write_urb_pool[i]->transfer_buffer); - usb_free_urb (write_urb_pool[i]); + if (write_urb_pool[i]) { + /* FIXME - uncomment the following usb_unlink_urb call when + * the host controllers get fixed to set urb->dev = NULL after + * the urb is finished. Otherwise this call oopses. */ + /* usb_unlink_urb(write_urb_pool[i]); */ + if (write_urb_pool[i]->transfer_buffer) + kfree(write_urb_pool[i]->transfer_buffer); + usb_free_urb (write_urb_pool[i]); + } } + + spin_unlock_irqrestore (&write_urb_pool_lock, flags); } diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 7ec405501..7302b729a 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -11,6 +11,9 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (09/11/2000) gkh + * Removed DEBUG #ifdefs with call to usb_serial_debug_data + * * (07/19/2000) gkh * Added module_init and module_exit functions to handle the fact that this * driver is a loadable module now. @@ -130,11 +133,6 @@ static inline void set_break (struct usb_serial_port *port, unsigned char brk); *****************************************************************************/ static void command_port_write_callback (struct urb *urb) { - unsigned char *data = urb->transfer_buffer; -#ifdef DEBUG - int i; -#endif - dbg (__FUNCTION__); if (urb->status) { @@ -142,15 +140,7 @@ static void command_port_write_callback (struct urb *urb) return; } -#ifdef DEBUG - if (urb->actual_length) { - printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", urb->actual_length); - for (i = 0; i < urb->actual_length; ++i) { - printk ("%.2x ", data[i]); - } - printk ("\n"); - } -#endif + usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, urb->transfer_buffer); return; } @@ -160,9 +150,6 @@ static void command_port_read_callback (struct urb *urb) { struct whiteheat_private *info = (struct whiteheat_private *)urb->context; unsigned char *data = urb->transfer_buffer; -#ifdef DEBUG - int i; -#endif dbg (__FUNCTION__); @@ -171,15 +158,7 @@ static void command_port_read_callback (struct urb *urb) return; } -#ifdef DEBUG - if (urb->actual_length) { - printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", urb->actual_length); - for (i = 0; i < urb->actual_length; ++i) { - printk ("%.2x ", data[i]); - } - printk ("\n"); - } -#endif + usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); /* right now, if the command is COMMAND_COMPLETE, just flip the bit saying the command finished */ /* in the future we're going to have to pay attention to the actual command that completed */ @@ -531,7 +510,7 @@ static inline void set_break (struct usb_serial_port *port, unsigned char brk) } -int whiteheat_init (void) +static int __init whiteheat_init (void) { usb_serial_register (&whiteheat_fake_device); usb_serial_register (&whiteheat_device); @@ -539,7 +518,7 @@ int whiteheat_init (void) } -void whiteheat_exit (void) +static void __exit whiteheat_exit (void) { usb_serial_deregister (&whiteheat_fake_device); usb_serial_deregister (&whiteheat_device); |