diff options
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r-- | drivers/usb/serial/Kconfig | 18 | ||||
-rw-r--r-- | drivers/usb/serial/airprime.c | 2 | ||||
-rw-r--r-- | drivers/usb/serial/console.c | 56 | ||||
-rw-r--r-- | drivers/usb/serial/cp2101.c | 1 | ||||
-rw-r--r-- | drivers/usb/serial/cyberjack.c | 2 | ||||
-rw-r--r-- | drivers/usb/serial/cypress_m8.c | 2 | ||||
-rw-r--r-- | drivers/usb/serial/empeg.c | 2 | ||||
-rw-r--r-- | drivers/usb/serial/ftdi_sio.c | 13 | ||||
-rw-r--r-- | drivers/usb/serial/ftdi_sio.h | 6 | ||||
-rw-r--r-- | drivers/usb/serial/garmin_gps.c | 2 | ||||
-rw-r--r-- | drivers/usb/serial/generic.c | 4 | ||||
-rw-r--r-- | drivers/usb/serial/io_edgeport.c | 48 | ||||
-rw-r--r-- | drivers/usb/serial/ipaq.c | 2 | ||||
-rw-r--r-- | drivers/usb/serial/ipw.c | 2 | ||||
-rw-r--r-- | drivers/usb/serial/ir-usb.c | 2 | ||||
-rw-r--r-- | drivers/usb/serial/keyspan.c | 2 | ||||
-rw-r--r-- | drivers/usb/serial/kl5kusb105.c | 3 | ||||
-rw-r--r-- | drivers/usb/serial/omninet.c | 2 | ||||
-rw-r--r-- | drivers/usb/serial/option.c | 139 | ||||
-rw-r--r-- | drivers/usb/serial/pl2303.c | 4 | ||||
-rw-r--r-- | drivers/usb/serial/usb-serial.c | 58 | ||||
-rw-r--r-- | drivers/usb/serial/usb-serial.h | 5 | ||||
-rw-r--r-- | drivers/usb/serial/visor.c | 2 | ||||
-rw-r--r-- | drivers/usb/serial/whiteheat.c | 8 |
24 files changed, 271 insertions, 114 deletions
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 5c60be521561..8bd44fda5eaf 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig | |||
@@ -417,7 +417,7 @@ config USB_SERIAL_MCT_U232 | |||
417 | Magic Control Technology Corp. (U232 is one of the model numbers). | 417 | Magic Control Technology Corp. (U232 is one of the model numbers). |
418 | 418 | ||
419 | This driver also works with Sitecom U232-P25 and D-Link DU-H3SP USB | 419 | This driver also works with Sitecom U232-P25 and D-Link DU-H3SP USB |
420 | BAY devices. | 420 | BAY, Belkin F5U109, and Belkin F5U409 devices. |
421 | 421 | ||
422 | To compile this driver as a module, choose M here: the | 422 | To compile this driver as a module, choose M here: the |
423 | module will be called mct_u232. | 423 | module will be called mct_u232. |
@@ -491,16 +491,22 @@ config USB_SERIAL_XIRCOM | |||
491 | module will be called keyspan_pda. | 491 | module will be called keyspan_pda. |
492 | 492 | ||
493 | config USB_SERIAL_OPTION | 493 | config USB_SERIAL_OPTION |
494 | tristate "USB Option PCMCIA serial driver" | 494 | tristate "USB driver for GSM modems" |
495 | depends on USB_SERIAL && USB_OHCI_HCD && PCCARD | 495 | depends on USB_SERIAL |
496 | help | 496 | help |
497 | Say Y here if you want to use an Option card. This is a | 497 | Say Y here if you have an "Option" GSM PCMCIA card |
498 | GSM card, controlled by three serial ports which are connected | 498 | (or an OEM version: branded Huawei, Audiovox, or Novatel). |
499 | via an OHCI adapter located on a PC card. | 499 | |
500 | These cards feature a built-in OHCI-USB adapter and an | ||
501 | internally-connected GSM modem. The USB bus is not | ||
502 | accessible externally. | ||
500 | 503 | ||
501 | To compile this driver as a module, choose M here: the | 504 | To compile this driver as a module, choose M here: the |
502 | module will be called option. | 505 | module will be called option. |
503 | 506 | ||
507 | If this driver doesn't recognize your device, | ||
508 | it might be accessible via the FTDI_SIO driver. | ||
509 | |||
504 | config USB_SERIAL_OMNINET | 510 | config USB_SERIAL_OMNINET |
505 | tristate "USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)" | 511 | tristate "USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)" |
506 | depends on USB_SERIAL && EXPERIMENTAL | 512 | depends on USB_SERIAL && EXPERIMENTAL |
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index 694b205f9b73..94b9ba0ff875 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c | |||
@@ -16,9 +16,11 @@ | |||
16 | #include "usb-serial.h" | 16 | #include "usb-serial.h" |
17 | 17 | ||
18 | static struct usb_device_id id_table [] = { | 18 | static struct usb_device_id id_table [] = { |
19 | { USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */ | ||
19 | { USB_DEVICE(0xf3d, 0x0112) }, /* AirPrime CDMA Wireless PC Card */ | 20 | { USB_DEVICE(0xf3d, 0x0112) }, /* AirPrime CDMA Wireless PC Card */ |
20 | { USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */ | 21 | { USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */ |
21 | { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless Aircard 580 */ | 22 | { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless Aircard 580 */ |
23 | { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ | ||
22 | { }, | 24 | { }, |
23 | }; | 25 | }; |
24 | MODULE_DEVICE_TABLE(usb, id_table); | 26 | MODULE_DEVICE_TABLE(usb, id_table); |
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index 8023bb7279b1..f3404e10afb4 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c | |||
@@ -202,7 +202,7 @@ static void usb_console_write(struct console *co, const char *buf, unsigned coun | |||
202 | struct usb_serial *serial; | 202 | struct usb_serial *serial; |
203 | int retval = -ENODEV; | 203 | int retval = -ENODEV; |
204 | 204 | ||
205 | if (!port) | 205 | if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED) |
206 | return; | 206 | return; |
207 | serial = port->serial; | 207 | serial = port->serial; |
208 | 208 | ||
@@ -213,17 +213,38 @@ static void usb_console_write(struct console *co, const char *buf, unsigned coun | |||
213 | 213 | ||
214 | if (!port->open_count) { | 214 | if (!port->open_count) { |
215 | dbg ("%s - port not opened", __FUNCTION__); | 215 | dbg ("%s - port not opened", __FUNCTION__); |
216 | goto exit; | 216 | return; |
217 | } | 217 | } |
218 | 218 | ||
219 | /* pass on to the driver specific version of this function if it is available */ | 219 | while (count) { |
220 | if (serial->type->write) | 220 | unsigned int i; |
221 | retval = serial->type->write(port, buf, count); | 221 | unsigned int lf; |
222 | else | 222 | /* search for LF so we can insert CR if necessary */ |
223 | retval = usb_serial_generic_write(port, buf, count); | 223 | for (i=0, lf=0 ; i < count ; i++) { |
224 | 224 | if (*(buf + i) == 10) { | |
225 | exit: | 225 | lf = 1; |
226 | dbg("%s - return value (if we had one): %d", __FUNCTION__, retval); | 226 | i++; |
227 | break; | ||
228 | } | ||
229 | } | ||
230 | /* pass on to the driver specific version of this function if it is available */ | ||
231 | if (serial->type->write) | ||
232 | retval = serial->type->write(port, buf, i); | ||
233 | else | ||
234 | retval = usb_serial_generic_write(port, buf, i); | ||
235 | dbg("%s - return value : %d", __FUNCTION__, retval); | ||
236 | if (lf) { | ||
237 | /* append CR after LF */ | ||
238 | unsigned char cr = 13; | ||
239 | if (serial->type->write) | ||
240 | retval = serial->type->write(port, &cr, 1); | ||
241 | else | ||
242 | retval = usb_serial_generic_write(port, &cr, 1); | ||
243 | dbg("%s - return value : %d", __FUNCTION__, retval); | ||
244 | } | ||
245 | buf += i; | ||
246 | count -= i; | ||
247 | } | ||
227 | } | 248 | } |
228 | 249 | ||
229 | static struct console usbcons = { | 250 | static struct console usbcons = { |
@@ -234,6 +255,14 @@ static struct console usbcons = { | |||
234 | .index = -1, | 255 | .index = -1, |
235 | }; | 256 | }; |
236 | 257 | ||
258 | void usb_serial_console_disconnect(struct usb_serial *serial) | ||
259 | { | ||
260 | if (serial && serial->port && serial->port[0] && serial->port[0] == usbcons_info.port) { | ||
261 | usb_serial_console_exit(); | ||
262 | usb_serial_put(serial); | ||
263 | } | ||
264 | } | ||
265 | |||
237 | void usb_serial_console_init (int serial_debug, int minor) | 266 | void usb_serial_console_init (int serial_debug, int minor) |
238 | { | 267 | { |
239 | debug = serial_debug; | 268 | debug = serial_debug; |
@@ -259,6 +288,11 @@ void usb_serial_console_init (int serial_debug, int minor) | |||
259 | 288 | ||
260 | void usb_serial_console_exit (void) | 289 | void usb_serial_console_exit (void) |
261 | { | 290 | { |
262 | unregister_console(&usbcons); | 291 | if (usbcons_info.port) { |
292 | unregister_console(&usbcons); | ||
293 | if (usbcons_info.port->open_count) | ||
294 | usbcons_info.port->open_count--; | ||
295 | usbcons_info.port = NULL; | ||
296 | } | ||
263 | } | 297 | } |
264 | 298 | ||
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index e0c2acdb3f06..f8c0cb287736 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c | |||
@@ -59,6 +59,7 @@ static struct usb_device_id id_table [] = { | |||
59 | { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */ | 59 | { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */ |
60 | { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */ | 60 | { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */ |
61 | { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */ | 61 | { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */ |
62 | { USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */ | ||
62 | { USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */ | 63 | { USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */ |
63 | { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */ | 64 | { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */ |
64 | { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */ | 65 | { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */ |
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index 2357b1d102d7..1fd5c5a9f2ef 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c | |||
@@ -469,7 +469,7 @@ static void cyberjack_write_bulk_callback (struct urb *urb, struct pt_regs *regs | |||
469 | 469 | ||
470 | exit: | 470 | exit: |
471 | spin_unlock(&priv->lock); | 471 | spin_unlock(&priv->lock); |
472 | schedule_work(&port->work); | 472 | usb_serial_port_softint(port); |
473 | } | 473 | } |
474 | 474 | ||
475 | static int __init cyberjack_init (void) | 475 | static int __init cyberjack_init (void) |
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 7212fbe3b6f2..5de76efe1b37 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c | |||
@@ -824,7 +824,7 @@ send: | |||
824 | priv->bytes_out += count; /* do not count the line control and size bytes */ | 824 | priv->bytes_out += count; /* do not count the line control and size bytes */ |
825 | spin_unlock_irqrestore(&priv->lock, flags); | 825 | spin_unlock_irqrestore(&priv->lock, flags); |
826 | 826 | ||
827 | schedule_work(&port->work); | 827 | usb_serial_port_softint(port); |
828 | } /* cypress_send */ | 828 | } /* cypress_send */ |
829 | 829 | ||
830 | 830 | ||
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 63f7c78a1152..afca1eae5fb5 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c | |||
@@ -335,7 +335,7 @@ static void empeg_write_bulk_callback (struct urb *urb, struct pt_regs *regs) | |||
335 | return; | 335 | return; |
336 | } | 336 | } |
337 | 337 | ||
338 | schedule_work(&port->work); | 338 | usb_serial_port_softint(port); |
339 | } | 339 | } |
340 | 340 | ||
341 | 341 | ||
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 986d7622273d..b2bfea7c815a 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c | |||
@@ -500,6 +500,7 @@ static struct usb_device_id id_table_combined [] = { | |||
500 | { USB_DEVICE(ICOM_ID1_VID, ICOM_ID1_PID) }, | 500 | { USB_DEVICE(ICOM_ID1_VID, ICOM_ID1_PID) }, |
501 | { USB_DEVICE(PAPOUCH_VID, PAPOUCH_TMU_PID) }, | 501 | { USB_DEVICE(PAPOUCH_VID, PAPOUCH_TMU_PID) }, |
502 | { USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) }, | 502 | { USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) }, |
503 | { USB_DEVICE(FTDI_VID, FTDI_YEI_SERVOCENTER31_PID) }, | ||
503 | { }, /* Optional parameter entry */ | 504 | { }, /* Optional parameter entry */ |
504 | { } /* Terminating entry */ | 505 | { } /* Terminating entry */ |
505 | }; | 506 | }; |
@@ -1261,7 +1262,6 @@ static void ftdi_shutdown (struct usb_serial *serial) | |||
1261 | 1262 | ||
1262 | static int ftdi_open (struct usb_serial_port *port, struct file *filp) | 1263 | static int ftdi_open (struct usb_serial_port *port, struct file *filp) |
1263 | { /* ftdi_open */ | 1264 | { /* ftdi_open */ |
1264 | struct termios tmp_termios; | ||
1265 | struct usb_device *dev = port->serial->dev; | 1265 | struct usb_device *dev = port->serial->dev; |
1266 | struct ftdi_private *priv = usb_get_serial_port_data(port); | 1266 | struct ftdi_private *priv = usb_get_serial_port_data(port); |
1267 | unsigned long flags; | 1267 | unsigned long flags; |
@@ -1271,8 +1271,8 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) | |||
1271 | 1271 | ||
1272 | dbg("%s", __FUNCTION__); | 1272 | dbg("%s", __FUNCTION__); |
1273 | 1273 | ||
1274 | 1274 | if (port->tty) | |
1275 | port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; | 1275 | port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; |
1276 | 1276 | ||
1277 | /* No error checking for this (will get errors later anyway) */ | 1277 | /* No error checking for this (will get errors later anyway) */ |
1278 | /* See ftdi_sio.h for description of what is reset */ | 1278 | /* See ftdi_sio.h for description of what is reset */ |
@@ -1286,7 +1286,8 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) | |||
1286 | This is same behaviour as serial.c/rs_open() - Kuba */ | 1286 | This is same behaviour as serial.c/rs_open() - Kuba */ |
1287 | 1287 | ||
1288 | /* ftdi_set_termios will send usb control messages */ | 1288 | /* ftdi_set_termios will send usb control messages */ |
1289 | ftdi_set_termios(port, &tmp_termios); | 1289 | if (port->tty) |
1290 | ftdi_set_termios(port, NULL); | ||
1290 | 1291 | ||
1291 | /* FIXME: Flow control might be enabled, so it should be checked - | 1292 | /* FIXME: Flow control might be enabled, so it should be checked - |
1292 | we have no control of defaults! */ | 1293 | we have no control of defaults! */ |
@@ -1472,7 +1473,7 @@ static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs) | |||
1472 | return; | 1473 | return; |
1473 | } | 1474 | } |
1474 | 1475 | ||
1475 | schedule_work(&port->work); | 1476 | usb_serial_port_softint(port); |
1476 | } /* ftdi_write_bulk_callback */ | 1477 | } /* ftdi_write_bulk_callback */ |
1477 | 1478 | ||
1478 | 1479 | ||
@@ -1867,7 +1868,7 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ | |||
1867 | err("%s urb failed to set baudrate", __FUNCTION__); | 1868 | err("%s urb failed to set baudrate", __FUNCTION__); |
1868 | } | 1869 | } |
1869 | /* Ensure RTS and DTR are raised when baudrate changed from 0 */ | 1870 | /* Ensure RTS and DTR are raised when baudrate changed from 0 */ |
1870 | if ((old_termios->c_cflag & CBAUD) == B0) { | 1871 | if (!old_termios || (old_termios->c_cflag & CBAUD) == B0) { |
1871 | set_mctrl(port, TIOCM_DTR | TIOCM_RTS); | 1872 | set_mctrl(port, TIOCM_DTR | TIOCM_RTS); |
1872 | } | 1873 | } |
1873 | } | 1874 | } |
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index d69a917e768f..6ab2ac845bd7 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h | |||
@@ -436,6 +436,12 @@ | |||
436 | */ | 436 | */ |
437 | #define FTDI_ACG_HFDUAL_PID 0xDD20 /* HF Dual ISO Reader (RFID) */ | 437 | #define FTDI_ACG_HFDUAL_PID 0xDD20 /* HF Dual ISO Reader (RFID) */ |
438 | 438 | ||
439 | /* | ||
440 | * Yost Engineering, Inc. products (www.yostengineering.com). | ||
441 | * PID 0xE050 submitted by Aaron Prose. | ||
442 | */ | ||
443 | #define FTDI_YEI_SERVOCENTER31_PID 0xE050 /* YEI ServoCenter3.1 USB */ | ||
444 | |||
439 | /* Commands */ | 445 | /* Commands */ |
440 | #define FTDI_SIO_RESET 0 /* Reset the port */ | 446 | #define FTDI_SIO_RESET 0 /* Reset the port */ |
441 | #define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ | 447 | #define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ |
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 5ec9bf5bac8d..04767759cf8a 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c | |||
@@ -1012,7 +1012,7 @@ static void garmin_write_bulk_callback (struct urb *urb, struct pt_regs *regs) | |||
1012 | garmin_data_p->flags |= CLEAR_HALT_REQUIRED; | 1012 | garmin_data_p->flags |= CLEAR_HALT_REQUIRED; |
1013 | } | 1013 | } |
1014 | 1014 | ||
1015 | schedule_work(&port->work); | 1015 | usb_serial_port_softint(port); |
1016 | } | 1016 | } |
1017 | 1017 | ||
1018 | 1018 | ||
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index c62cc2876519..07a478c59fb2 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c | |||
@@ -299,9 +299,7 @@ void usb_serial_generic_write_bulk_callback (struct urb *urb, struct pt_regs *re | |||
299 | return; | 299 | return; |
300 | } | 300 | } |
301 | 301 | ||
302 | usb_serial_port_softint((void *)port); | 302 | usb_serial_port_softint(port); |
303 | |||
304 | schedule_work(&port->work); | ||
305 | } | 303 | } |
306 | EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback); | 304 | EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback); |
307 | 305 | ||
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index b606c5968102..b85d2156dfdc 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c | |||
@@ -142,7 +142,7 @@ struct edgeport_port { | |||
142 | 142 | ||
143 | /* This structure holds all of the individual device information */ | 143 | /* This structure holds all of the individual device information */ |
144 | struct edgeport_serial { | 144 | struct edgeport_serial { |
145 | char name[MAX_NAME_LEN+1]; /* string name of this device */ | 145 | char name[MAX_NAME_LEN+2]; /* string name of this device */ |
146 | 146 | ||
147 | struct edge_manuf_descriptor manuf_descriptor; /* the manufacturer descriptor */ | 147 | struct edge_manuf_descriptor manuf_descriptor; /* the manufacturer descriptor */ |
148 | struct edge_boot_descriptor boot_descriptor; /* the boot firmware descriptor */ | 148 | struct edge_boot_descriptor boot_descriptor; /* the boot firmware descriptor */ |
@@ -270,7 +270,7 @@ static void get_manufacturing_desc (struct edgeport_serial *edge_serial); | |||
270 | static void get_boot_desc (struct edgeport_serial *edge_serial); | 270 | static void get_boot_desc (struct edgeport_serial *edge_serial); |
271 | static void load_application_firmware (struct edgeport_serial *edge_serial); | 271 | static void load_application_firmware (struct edgeport_serial *edge_serial); |
272 | 272 | ||
273 | static void unicode_to_ascii (char *string, __le16 *unicode, int unicode_size); | 273 | static void unicode_to_ascii(char *string, int buflen, __le16 *unicode, int unicode_size); |
274 | 274 | ||
275 | 275 | ||
276 | // ************************************************************************ | 276 | // ************************************************************************ |
@@ -373,7 +373,7 @@ static void update_edgeport_E2PROM (struct edgeport_serial *edge_serial) | |||
373 | * Get string descriptor from device * | 373 | * Get string descriptor from device * |
374 | * * | 374 | * * |
375 | ************************************************************************/ | 375 | ************************************************************************/ |
376 | static int get_string (struct usb_device *dev, int Id, char *string) | 376 | static int get_string (struct usb_device *dev, int Id, char *string, int buflen) |
377 | { | 377 | { |
378 | struct usb_string_descriptor StringDesc; | 378 | struct usb_string_descriptor StringDesc; |
379 | struct usb_string_descriptor *pStringDesc; | 379 | struct usb_string_descriptor *pStringDesc; |
@@ -395,7 +395,7 @@ static int get_string (struct usb_device *dev, int Id, char *string) | |||
395 | return 0; | 395 | return 0; |
396 | } | 396 | } |
397 | 397 | ||
398 | unicode_to_ascii(string, pStringDesc->wData, pStringDesc->bLength/2-1); | 398 | unicode_to_ascii(string, buflen, pStringDesc->wData, pStringDesc->bLength/2); |
399 | 399 | ||
400 | kfree(pStringDesc); | 400 | kfree(pStringDesc); |
401 | return strlen(string); | 401 | return strlen(string); |
@@ -2564,16 +2564,20 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio | |||
2564 | * ASCII range, but it's only for debugging... | 2564 | * ASCII range, but it's only for debugging... |
2565 | * NOTE: expects the unicode in LE format | 2565 | * NOTE: expects the unicode in LE format |
2566 | ****************************************************************************/ | 2566 | ****************************************************************************/ |
2567 | static void unicode_to_ascii (char *string, __le16 *unicode, int unicode_size) | 2567 | static void unicode_to_ascii(char *string, int buflen, __le16 *unicode, int unicode_size) |
2568 | { | 2568 | { |
2569 | int i; | 2569 | int i; |
2570 | 2570 | ||
2571 | if (unicode_size <= 0) | 2571 | if (buflen <= 0) /* never happens, but... */ |
2572 | return; | 2572 | return; |
2573 | --buflen; /* space for nul */ | ||
2573 | 2574 | ||
2574 | for (i = 0; i < unicode_size; ++i) | 2575 | for (i = 0; i < unicode_size; i++) { |
2576 | if (i >= buflen) | ||
2577 | break; | ||
2575 | string[i] = (char)(le16_to_cpu(unicode[i])); | 2578 | string[i] = (char)(le16_to_cpu(unicode[i])); |
2576 | string[unicode_size] = 0x00; | 2579 | } |
2580 | string[i] = 0x00; | ||
2577 | } | 2581 | } |
2578 | 2582 | ||
2579 | 2583 | ||
@@ -2603,11 +2607,17 @@ static void get_manufacturing_desc (struct edgeport_serial *edge_serial) | |||
2603 | dbg(" BoardRev: %d", edge_serial->manuf_descriptor.BoardRev); | 2607 | dbg(" BoardRev: %d", edge_serial->manuf_descriptor.BoardRev); |
2604 | dbg(" NumPorts: %d", edge_serial->manuf_descriptor.NumPorts); | 2608 | dbg(" NumPorts: %d", edge_serial->manuf_descriptor.NumPorts); |
2605 | dbg(" DescDate: %d/%d/%d", edge_serial->manuf_descriptor.DescDate[0], edge_serial->manuf_descriptor.DescDate[1], edge_serial->manuf_descriptor.DescDate[2]+1900); | 2609 | dbg(" DescDate: %d/%d/%d", edge_serial->manuf_descriptor.DescDate[0], edge_serial->manuf_descriptor.DescDate[1], edge_serial->manuf_descriptor.DescDate[2]+1900); |
2606 | unicode_to_ascii (string, edge_serial->manuf_descriptor.SerialNumber, edge_serial->manuf_descriptor.SerNumLength/2-1); | 2610 | unicode_to_ascii(string, sizeof(string), |
2611 | edge_serial->manuf_descriptor.SerialNumber, | ||
2612 | edge_serial->manuf_descriptor.SerNumLength/2); | ||
2607 | dbg(" SerialNumber: %s", string); | 2613 | dbg(" SerialNumber: %s", string); |
2608 | unicode_to_ascii (string, edge_serial->manuf_descriptor.AssemblyNumber, edge_serial->manuf_descriptor.AssemblyNumLength/2-1); | 2614 | unicode_to_ascii(string, sizeof(string), |
2615 | edge_serial->manuf_descriptor.AssemblyNumber, | ||
2616 | edge_serial->manuf_descriptor.AssemblyNumLength/2); | ||
2609 | dbg(" AssemblyNumber: %s", string); | 2617 | dbg(" AssemblyNumber: %s", string); |
2610 | unicode_to_ascii (string, edge_serial->manuf_descriptor.OemAssyNumber, edge_serial->manuf_descriptor.OemAssyNumLength/2-1); | 2618 | unicode_to_ascii(string, sizeof(string), |
2619 | edge_serial->manuf_descriptor.OemAssyNumber, | ||
2620 | edge_serial->manuf_descriptor.OemAssyNumLength/2); | ||
2611 | dbg(" OemAssyNumber: %s", string); | 2621 | dbg(" OemAssyNumber: %s", string); |
2612 | dbg(" UartType: %d", edge_serial->manuf_descriptor.UartType); | 2622 | dbg(" UartType: %d", edge_serial->manuf_descriptor.UartType); |
2613 | dbg(" IonPid: %d", edge_serial->manuf_descriptor.IonPid); | 2623 | dbg(" IonPid: %d", edge_serial->manuf_descriptor.IonPid); |
@@ -2720,7 +2730,7 @@ static int edge_startup (struct usb_serial *serial) | |||
2720 | struct edgeport_serial *edge_serial; | 2730 | struct edgeport_serial *edge_serial; |
2721 | struct edgeport_port *edge_port; | 2731 | struct edgeport_port *edge_port; |
2722 | struct usb_device *dev; | 2732 | struct usb_device *dev; |
2723 | int i; | 2733 | int i, j; |
2724 | 2734 | ||
2725 | dev = serial->dev; | 2735 | dev = serial->dev; |
2726 | 2736 | ||
@@ -2735,11 +2745,11 @@ static int edge_startup (struct usb_serial *serial) | |||
2735 | usb_set_serial_data(serial, edge_serial); | 2745 | usb_set_serial_data(serial, edge_serial); |
2736 | 2746 | ||
2737 | /* get the name for the device from the device */ | 2747 | /* get the name for the device from the device */ |
2738 | if ( (i = get_string(dev, dev->descriptor.iManufacturer, &edge_serial->name[0])) != 0) { | 2748 | i = get_string(dev, dev->descriptor.iManufacturer, |
2739 | edge_serial->name[i-1] = ' '; | 2749 | &edge_serial->name[0], MAX_NAME_LEN+1); |
2740 | } | 2750 | edge_serial->name[i++] = ' '; |
2741 | 2751 | get_string(dev, dev->descriptor.iProduct, | |
2742 | get_string(dev, dev->descriptor.iProduct, &edge_serial->name[i]); | 2752 | &edge_serial->name[i], MAX_NAME_LEN+2 - i); |
2743 | 2753 | ||
2744 | dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name); | 2754 | dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name); |
2745 | 2755 | ||
@@ -2784,6 +2794,10 @@ static int edge_startup (struct usb_serial *serial) | |||
2784 | edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL); | 2794 | edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL); |
2785 | if (edge_port == NULL) { | 2795 | if (edge_port == NULL) { |
2786 | dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__); | 2796 | dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__); |
2797 | for (j = 0; j < i; ++j) { | ||
2798 | kfree (usb_get_serial_port_data(serial->port[j])); | ||
2799 | usb_set_serial_port_data(serial->port[j], NULL); | ||
2800 | } | ||
2787 | usb_set_serial_data(serial, NULL); | 2801 | usb_set_serial_data(serial, NULL); |
2788 | kfree(edge_serial); | 2802 | kfree(edge_serial); |
2789 | return -ENOMEM; | 2803 | return -ENOMEM; |
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 9a5c97989562..9da6d2a8f2b0 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c | |||
@@ -870,7 +870,7 @@ static void ipaq_write_bulk_callback(struct urb *urb, struct pt_regs *regs) | |||
870 | spin_unlock_irqrestore(&write_list_lock, flags); | 870 | spin_unlock_irqrestore(&write_list_lock, flags); |
871 | } | 871 | } |
872 | 872 | ||
873 | schedule_work(&port->work); | 873 | usb_serial_port_softint(port); |
874 | } | 874 | } |
875 | 875 | ||
876 | static int ipaq_write_room(struct usb_serial_port *port) | 876 | static int ipaq_write_room(struct usb_serial_port *port) |
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index e760a70242c1..a4a0bfeaab00 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c | |||
@@ -376,7 +376,7 @@ static void ipw_write_bulk_callback(struct urb *urb, struct pt_regs *regs) | |||
376 | if (urb->status) | 376 | if (urb->status) |
377 | dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); | 377 | dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); |
378 | 378 | ||
379 | schedule_work(&port->work); | 379 | usb_serial_port_softint(port); |
380 | } | 380 | } |
381 | 381 | ||
382 | static int ipw_write(struct usb_serial_port *port, const unsigned char *buf, int count) | 382 | static int ipw_write(struct usb_serial_port *port, const unsigned char *buf, int count) |
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 426182ddc42a..9432c7302275 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c | |||
@@ -408,7 +408,7 @@ static void ir_write_bulk_callback (struct urb *urb, struct pt_regs *regs) | |||
408 | urb->actual_length, | 408 | urb->actual_length, |
409 | urb->transfer_buffer); | 409 | urb->transfer_buffer); |
410 | 410 | ||
411 | schedule_work(&port->work); | 411 | usb_serial_port_softint(port); |
412 | } | 412 | } |
413 | 413 | ||
414 | static void ir_read_bulk_callback (struct urb *urb, struct pt_regs *regs) | 414 | static void ir_read_bulk_callback (struct urb *urb, struct pt_regs *regs) |
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 052b735c4fbd..2cf6ade704e4 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c | |||
@@ -481,7 +481,7 @@ static void usa2x_outdat_callback(struct urb *urb, struct pt_regs *regs) | |||
481 | dbg ("%s - urb %d", __FUNCTION__, urb == p_priv->out_urbs[1]); | 481 | dbg ("%s - urb %d", __FUNCTION__, urb == p_priv->out_urbs[1]); |
482 | 482 | ||
483 | if (port->open_count) | 483 | if (port->open_count) |
484 | schedule_work(&port->work); | 484 | usb_serial_port_softint(port); |
485 | } | 485 | } |
486 | 486 | ||
487 | static void usa26_inack_callback(struct urb *urb, struct pt_regs *regs) | 487 | static void usa26_inack_callback(struct urb *urb, struct pt_regs *regs) |
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 78335a5f7743..65d79f630fa4 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c | |||
@@ -569,8 +569,7 @@ static void klsi_105_write_bulk_callback ( struct urb *urb, struct pt_regs *regs | |||
569 | return; | 569 | return; |
570 | } | 570 | } |
571 | 571 | ||
572 | /* from generic_write_bulk_callback */ | 572 | usb_serial_port_softint(port); |
573 | schedule_work(&port->work); | ||
574 | } /* klsi_105_write_bulk_completion_callback */ | 573 | } /* klsi_105_write_bulk_completion_callback */ |
575 | 574 | ||
576 | 575 | ||
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 238033a87092..6dcdb5f598b8 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c | |||
@@ -320,7 +320,7 @@ static void omninet_write_bulk_callback (struct urb *urb, struct pt_regs *regs) | |||
320 | return; | 320 | return; |
321 | } | 321 | } |
322 | 322 | ||
323 | schedule_work(&port->work); | 323 | usb_serial_port_softint(port); |
324 | } | 324 | } |
325 | 325 | ||
326 | 326 | ||
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 5cf2b80add7a..b0861b61bba7 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | Option Card (PCMCIA to) USB to Serial Driver | 2 | USB Driver for GSM modems |
3 | 3 | ||
4 | Copyright (C) 2005 Matthias Urlichs <smurf@smurf.noris.de> | 4 | Copyright (C) 2005 Matthias Urlichs <smurf@smurf.noris.de> |
5 | 5 | ||
@@ -28,15 +28,34 @@ | |||
28 | 2005-09-10 v0.4.3 added HUAWEI E600 card and Audiovox AirCard | 28 | 2005-09-10 v0.4.3 added HUAWEI E600 card and Audiovox AirCard |
29 | 2005-09-20 v0.4.4 increased recv buffer size: the card sometimes | 29 | 2005-09-20 v0.4.4 increased recv buffer size: the card sometimes |
30 | wants to send >2000 bytes. | 30 | wants to send >2000 bytes. |
31 | 2006-04-10 v0.4.2 fixed two array overrun errors :-/ | 31 | 2006-04-10 v0.5 fixed two array overrun errors :-/ |
32 | 2006-04-21 v0.5.1 added support for Sierra Wireless MC8755 | ||
33 | 2006-05-15 v0.6 re-enable multi-port support | ||
34 | 2006-06-01 v0.6.1 add COBRA | ||
35 | 2006-06-01 v0.6.2 add backwards-compatibility stuff | ||
36 | 2006-06-01 v0.6.3 add Novatel Wireless | ||
37 | 2006-06-01 v0.7 Option => GSM | ||
32 | 38 | ||
33 | Work sponsored by: Sigos GmbH, Germany <info@sigos.de> | 39 | Work sponsored by: Sigos GmbH, Germany <info@sigos.de> |
34 | 40 | ||
41 | This driver exists because the "normal" serial driver doesn't work too well | ||
42 | with GSM modems. Issues: | ||
43 | - data loss -- one single Receive URB is not nearly enough | ||
44 | - nonstandard flow (Option devices) and multiplex (Sierra) control | ||
45 | - controlling the baud rate doesn't make sense | ||
46 | |||
47 | This driver is named "option" because the most common device it's | ||
48 | used for is a PC-Card (with an internal OHCI-USB interface, behind | ||
49 | which the GSM interface sits), made by Option Inc. | ||
50 | |||
51 | Some of the "one port" devices actually exhibit multiple USB instances | ||
52 | on the USB bus. This is not a bug, these ports are used for different | ||
53 | device features. | ||
35 | */ | 54 | */ |
36 | 55 | ||
37 | #define DRIVER_VERSION "v0.4" | 56 | #define DRIVER_VERSION "v0.7.0" |
38 | #define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>" | 57 | #define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>" |
39 | #define DRIVER_DESC "Option Card (PC-Card to) USB to Serial Driver" | 58 | #define DRIVER_DESC "USB Driver for GSM modems" |
40 | 59 | ||
41 | #include <linux/config.h> | 60 | #include <linux/config.h> |
42 | #include <linux/kernel.h> | 61 | #include <linux/kernel.h> |
@@ -74,22 +93,45 @@ static int option_tiocmset(struct usb_serial_port *port, struct file *file, | |||
74 | static int option_send_setup(struct usb_serial_port *port); | 93 | static int option_send_setup(struct usb_serial_port *port); |
75 | 94 | ||
76 | /* Vendor and product IDs */ | 95 | /* Vendor and product IDs */ |
77 | #define OPTION_VENDOR_ID 0x0AF0 | 96 | #define OPTION_VENDOR_ID 0x0AF0 |
78 | #define HUAWEI_VENDOR_ID 0x12D1 | 97 | #define HUAWEI_VENDOR_ID 0x12D1 |
79 | #define AUDIOVOX_VENDOR_ID 0x0F3D | 98 | #define AUDIOVOX_VENDOR_ID 0x0F3D |
80 | 99 | #define SIERRAWIRELESS_VENDOR_ID 0x1199 | |
81 | #define OPTION_PRODUCT_OLD 0x5000 | 100 | #define NOVATELWIRELESS_VENDOR_ID 0x1410 |
82 | #define OPTION_PRODUCT_FUSION 0x6000 | 101 | |
83 | #define OPTION_PRODUCT_FUSION2 0x6300 | 102 | #define OPTION_PRODUCT_OLD 0x5000 |
84 | #define HUAWEI_PRODUCT_E600 0x1001 | 103 | #define OPTION_PRODUCT_FUSION 0x6000 |
85 | #define AUDIOVOX_PRODUCT_AIRCARD 0x0112 | 104 | #define OPTION_PRODUCT_FUSION2 0x6300 |
105 | #define OPTION_PRODUCT_COBRA 0x6500 | ||
106 | #define HUAWEI_PRODUCT_E600 0x1001 | ||
107 | #define AUDIOVOX_PRODUCT_AIRCARD 0x0112 | ||
108 | #define SIERRAWIRELESS_PRODUCT_MC8755 0x6802 | ||
109 | #define NOVATELWIRELESS_PRODUCT_U740 0x1400 | ||
86 | 110 | ||
87 | static struct usb_device_id option_ids[] = { | 111 | static struct usb_device_id option_ids[] = { |
88 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) }, | 112 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) }, |
89 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) }, | 113 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) }, |
90 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) }, | 114 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) }, |
115 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) }, | ||
91 | { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, | 116 | { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, |
92 | { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, | 117 | { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, |
118 | { USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) }, | ||
119 | { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) }, | ||
120 | { } /* Terminating entry */ | ||
121 | }; | ||
122 | |||
123 | static struct usb_device_id option_ids1[] = { | ||
124 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) }, | ||
125 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) }, | ||
126 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) }, | ||
127 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) }, | ||
128 | { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, | ||
129 | { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, | ||
130 | { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) }, | ||
131 | { } /* Terminating entry */ | ||
132 | }; | ||
133 | static struct usb_device_id option_ids3[] = { | ||
134 | { USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) }, | ||
93 | { } /* Terminating entry */ | 135 | { } /* Terminating entry */ |
94 | }; | 136 | }; |
95 | 137 | ||
@@ -111,12 +153,39 @@ static struct usb_serial_driver option_3port_device = { | |||
111 | .owner = THIS_MODULE, | 153 | .owner = THIS_MODULE, |
112 | .name = "option", | 154 | .name = "option", |
113 | }, | 155 | }, |
114 | .description = "Option 3G data card", | 156 | .description = "GSM modem (3-port)", |
115 | .id_table = option_ids, | 157 | .id_table = option_ids3, |
116 | .num_interrupt_in = NUM_DONT_CARE, | 158 | .num_interrupt_in = NUM_DONT_CARE, |
117 | .num_bulk_in = NUM_DONT_CARE, | 159 | .num_bulk_in = NUM_DONT_CARE, |
118 | .num_bulk_out = NUM_DONT_CARE, | 160 | .num_bulk_out = NUM_DONT_CARE, |
119 | .num_ports = 1, /* 3, but the card reports its ports separately */ | 161 | .num_ports = 3, |
162 | .open = option_open, | ||
163 | .close = option_close, | ||
164 | .write = option_write, | ||
165 | .write_room = option_write_room, | ||
166 | .chars_in_buffer = option_chars_in_buffer, | ||
167 | .throttle = option_rx_throttle, | ||
168 | .unthrottle = option_rx_unthrottle, | ||
169 | .set_termios = option_set_termios, | ||
170 | .break_ctl = option_break_ctl, | ||
171 | .tiocmget = option_tiocmget, | ||
172 | .tiocmset = option_tiocmset, | ||
173 | .attach = option_startup, | ||
174 | .shutdown = option_shutdown, | ||
175 | .read_int_callback = option_instat_callback, | ||
176 | }; | ||
177 | |||
178 | static struct usb_serial_driver option_1port_device = { | ||
179 | .driver = { | ||
180 | .owner = THIS_MODULE, | ||
181 | .name = "option", | ||
182 | }, | ||
183 | .description = "GSM modem (1-port)", | ||
184 | .id_table = option_ids1, | ||
185 | .num_interrupt_in = NUM_DONT_CARE, | ||
186 | .num_bulk_in = NUM_DONT_CARE, | ||
187 | .num_bulk_out = NUM_DONT_CARE, | ||
188 | .num_ports = 1, | ||
120 | .open = option_open, | 189 | .open = option_open, |
121 | .close = option_close, | 190 | .close = option_close, |
122 | .write = option_write, | 191 | .write = option_write, |
@@ -170,6 +239,9 @@ struct option_port_private { | |||
170 | static int __init option_init(void) | 239 | static int __init option_init(void) |
171 | { | 240 | { |
172 | int retval; | 241 | int retval; |
242 | retval = usb_serial_register(&option_1port_device); | ||
243 | if (retval) | ||
244 | goto failed_1port_device_register; | ||
173 | retval = usb_serial_register(&option_3port_device); | 245 | retval = usb_serial_register(&option_3port_device); |
174 | if (retval) | 246 | if (retval) |
175 | goto failed_3port_device_register; | 247 | goto failed_3port_device_register; |
@@ -184,6 +256,8 @@ static int __init option_init(void) | |||
184 | failed_driver_register: | 256 | failed_driver_register: |
185 | usb_serial_deregister (&option_3port_device); | 257 | usb_serial_deregister (&option_3port_device); |
186 | failed_3port_device_register: | 258 | failed_3port_device_register: |
259 | usb_serial_deregister (&option_1port_device); | ||
260 | failed_1port_device_register: | ||
187 | return retval; | 261 | return retval; |
188 | } | 262 | } |
189 | 263 | ||
@@ -191,6 +265,7 @@ static void __exit option_exit(void) | |||
191 | { | 265 | { |
192 | usb_deregister (&option_driver); | 266 | usb_deregister (&option_driver); |
193 | usb_serial_deregister (&option_3port_device); | 267 | usb_serial_deregister (&option_3port_device); |
268 | usb_serial_deregister (&option_1port_device); | ||
194 | } | 269 | } |
195 | 270 | ||
196 | module_init(option_init); | 271 | module_init(option_init); |
@@ -365,8 +440,7 @@ static void option_outdat_callback(struct urb *urb, struct pt_regs *regs) | |||
365 | 440 | ||
366 | port = (struct usb_serial_port *) urb->context; | 441 | port = (struct usb_serial_port *) urb->context; |
367 | 442 | ||
368 | if (port->open_count) | 443 | usb_serial_port_softint(port); |
369 | schedule_work(&port->work); | ||
370 | } | 444 | } |
371 | 445 | ||
372 | static void option_instat_callback(struct urb *urb, struct pt_regs *regs) | 446 | static void option_instat_callback(struct urb *urb, struct pt_regs *regs) |
@@ -573,27 +647,30 @@ static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint, | |||
573 | /* Setup urbs */ | 647 | /* Setup urbs */ |
574 | static void option_setup_urbs(struct usb_serial *serial) | 648 | static void option_setup_urbs(struct usb_serial *serial) |
575 | { | 649 | { |
576 | int j; | 650 | int i,j; |
577 | struct usb_serial_port *port; | 651 | struct usb_serial_port *port; |
578 | struct option_port_private *portdata; | 652 | struct option_port_private *portdata; |
579 | 653 | ||
580 | dbg("%s", __FUNCTION__); | 654 | dbg("%s", __FUNCTION__); |
581 | 655 | ||
582 | port = serial->port[0]; | 656 | |
583 | portdata = usb_get_serial_port_data(port); | 657 | for (i = 0; i < serial->num_ports; i++) { |
658 | port = serial->port[i]; | ||
659 | portdata = usb_get_serial_port_data(port); | ||
584 | 660 | ||
585 | /* Do indat endpoints first */ | 661 | /* Do indat endpoints first */ |
586 | for (j = 0; j < N_IN_URB; ++j) { | 662 | for (j = 0; j < N_IN_URB; ++j) { |
587 | portdata->in_urbs[j] = option_setup_urb (serial, | 663 | portdata->in_urbs[j] = option_setup_urb (serial, |
588 | port->bulk_in_endpointAddress, USB_DIR_IN, port, | 664 | port->bulk_in_endpointAddress, USB_DIR_IN, port, |
589 | portdata->in_buffer[j], IN_BUFLEN, option_indat_callback); | 665 | portdata->in_buffer[j], IN_BUFLEN, option_indat_callback); |
590 | } | 666 | } |
591 | 667 | ||
592 | /* outdat endpoints */ | 668 | /* outdat endpoints */ |
593 | for (j = 0; j < N_OUT_URB; ++j) { | 669 | for (j = 0; j < N_OUT_URB; ++j) { |
594 | portdata->out_urbs[j] = option_setup_urb (serial, | 670 | portdata->out_urbs[j] = option_setup_urb (serial, |
595 | port->bulk_out_endpointAddress, USB_DIR_OUT, port, | 671 | port->bulk_out_endpointAddress, USB_DIR_OUT, port, |
596 | portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback); | 672 | portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback); |
673 | } | ||
597 | } | 674 | } |
598 | } | 675 | } |
599 | 676 | ||
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index c96714bb1cb8..d88704387202 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c | |||
@@ -314,7 +314,7 @@ static void pl2303_send(struct usb_serial_port *port) | |||
314 | // TODO: reschedule pl2303_send | 314 | // TODO: reschedule pl2303_send |
315 | } | 315 | } |
316 | 316 | ||
317 | schedule_work(&port->work); | 317 | usb_serial_port_softint(port); |
318 | } | 318 | } |
319 | 319 | ||
320 | static int pl2303_write_room(struct usb_serial_port *port) | 320 | static int pl2303_write_room(struct usb_serial_port *port) |
@@ -600,7 +600,7 @@ static void pl2303_close (struct usb_serial_port *port, struct file *filp) | |||
600 | unsigned int c_cflag; | 600 | unsigned int c_cflag; |
601 | int bps; | 601 | int bps; |
602 | long timeout; | 602 | long timeout; |
603 | wait_queue_t wait; \ | 603 | wait_queue_t wait; |
604 | 604 | ||
605 | dbg("%s - port %d", __FUNCTION__, port->number); | 605 | dbg("%s - port %d", __FUNCTION__, port->number); |
606 | 606 | ||
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 9c36f0ece20f..a30135c7cfe6 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c | |||
@@ -162,12 +162,19 @@ static void destroy_serial(struct kref *kref) | |||
162 | } | 162 | } |
163 | } | 163 | } |
164 | 164 | ||
165 | flush_scheduled_work(); /* port->work */ | ||
166 | |||
165 | usb_put_dev(serial->dev); | 167 | usb_put_dev(serial->dev); |
166 | 168 | ||
167 | /* free up any memory that we allocated */ | 169 | /* free up any memory that we allocated */ |
168 | kfree (serial); | 170 | kfree (serial); |
169 | } | 171 | } |
170 | 172 | ||
173 | void usb_serial_put(struct usb_serial *serial) | ||
174 | { | ||
175 | kref_put(&serial->kref, destroy_serial); | ||
176 | } | ||
177 | |||
171 | /***************************************************************************** | 178 | /***************************************************************************** |
172 | * Driver tty interface functions | 179 | * Driver tty interface functions |
173 | *****************************************************************************/ | 180 | *****************************************************************************/ |
@@ -201,12 +208,12 @@ static int serial_open (struct tty_struct *tty, struct file * filp) | |||
201 | 208 | ||
202 | ++port->open_count; | 209 | ++port->open_count; |
203 | 210 | ||
204 | if (port->open_count == 1) { | 211 | /* set up our port structure making the tty driver |
212 | * remember our port object, and us it */ | ||
213 | tty->driver_data = port; | ||
214 | port->tty = tty; | ||
205 | 215 | ||
206 | /* set up our port structure making the tty driver | 216 | if (port->open_count == 1) { |
207 | * remember our port object, and us it */ | ||
208 | tty->driver_data = port; | ||
209 | port->tty = tty; | ||
210 | 217 | ||
211 | /* lock this module before we call it | 218 | /* lock this module before we call it |
212 | * this may fail, which means we must bail out, | 219 | * this may fail, which means we must bail out, |
@@ -230,9 +237,11 @@ bailout_module_put: | |||
230 | module_put(serial->type->driver.owner); | 237 | module_put(serial->type->driver.owner); |
231 | bailout_mutex_unlock: | 238 | bailout_mutex_unlock: |
232 | port->open_count = 0; | 239 | port->open_count = 0; |
240 | tty->driver_data = NULL; | ||
241 | port->tty = NULL; | ||
233 | mutex_unlock(&port->mutex); | 242 | mutex_unlock(&port->mutex); |
234 | bailout_kref_put: | 243 | bailout_kref_put: |
235 | kref_put(&serial->kref, destroy_serial); | 244 | usb_serial_put(serial); |
236 | return retval; | 245 | return retval; |
237 | } | 246 | } |
238 | 247 | ||
@@ -268,7 +277,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp) | |||
268 | } | 277 | } |
269 | 278 | ||
270 | mutex_unlock(&port->mutex); | 279 | mutex_unlock(&port->mutex); |
271 | kref_put(&port->serial->kref, destroy_serial); | 280 | usb_serial_put(port->serial); |
272 | } | 281 | } |
273 | 282 | ||
274 | static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count) | 283 | static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count) |
@@ -276,7 +285,7 @@ static int serial_write (struct tty_struct * tty, const unsigned char *buf, int | |||
276 | struct usb_serial_port *port = tty->driver_data; | 285 | struct usb_serial_port *port = tty->driver_data; |
277 | int retval = -EINVAL; | 286 | int retval = -EINVAL; |
278 | 287 | ||
279 | if (!port) | 288 | if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED) |
280 | goto exit; | 289 | goto exit; |
281 | 290 | ||
282 | dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count); | 291 | dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count); |
@@ -296,7 +305,7 @@ exit: | |||
296 | static int serial_write_room (struct tty_struct *tty) | 305 | static int serial_write_room (struct tty_struct *tty) |
297 | { | 306 | { |
298 | struct usb_serial_port *port = tty->driver_data; | 307 | struct usb_serial_port *port = tty->driver_data; |
299 | int retval = -EINVAL; | 308 | int retval = -ENODEV; |
300 | 309 | ||
301 | if (!port) | 310 | if (!port) |
302 | goto exit; | 311 | goto exit; |
@@ -318,7 +327,7 @@ exit: | |||
318 | static int serial_chars_in_buffer (struct tty_struct *tty) | 327 | static int serial_chars_in_buffer (struct tty_struct *tty) |
319 | { | 328 | { |
320 | struct usb_serial_port *port = tty->driver_data; | 329 | struct usb_serial_port *port = tty->driver_data; |
321 | int retval = -EINVAL; | 330 | int retval = -ENODEV; |
322 | 331 | ||
323 | if (!port) | 332 | if (!port) |
324 | goto exit; | 333 | goto exit; |
@@ -473,7 +482,7 @@ static int serial_read_proc (char *page, char **start, off_t off, int count, int | |||
473 | begin += length; | 482 | begin += length; |
474 | length = 0; | 483 | length = 0; |
475 | } | 484 | } |
476 | kref_put(&serial->kref, destroy_serial); | 485 | usb_serial_put(serial); |
477 | } | 486 | } |
478 | *eof = 1; | 487 | *eof = 1; |
479 | done: | 488 | done: |
@@ -488,19 +497,18 @@ static int serial_tiocmget (struct tty_struct *tty, struct file *file) | |||
488 | struct usb_serial_port *port = tty->driver_data; | 497 | struct usb_serial_port *port = tty->driver_data; |
489 | 498 | ||
490 | if (!port) | 499 | if (!port) |
491 | goto exit; | 500 | return -ENODEV; |
492 | 501 | ||
493 | dbg("%s - port %d", __FUNCTION__, port->number); | 502 | dbg("%s - port %d", __FUNCTION__, port->number); |
494 | 503 | ||
495 | if (!port->open_count) { | 504 | if (!port->open_count) { |
496 | dbg("%s - port not open", __FUNCTION__); | 505 | dbg("%s - port not open", __FUNCTION__); |
497 | goto exit; | 506 | return -ENODEV; |
498 | } | 507 | } |
499 | 508 | ||
500 | if (port->serial->type->tiocmget) | 509 | if (port->serial->type->tiocmget) |
501 | return port->serial->type->tiocmget(port, file); | 510 | return port->serial->type->tiocmget(port, file); |
502 | 511 | ||
503 | exit: | ||
504 | return -EINVAL; | 512 | return -EINVAL; |
505 | } | 513 | } |
506 | 514 | ||
@@ -510,23 +518,32 @@ static int serial_tiocmset (struct tty_struct *tty, struct file *file, | |||
510 | struct usb_serial_port *port = tty->driver_data; | 518 | struct usb_serial_port *port = tty->driver_data; |
511 | 519 | ||
512 | if (!port) | 520 | if (!port) |
513 | goto exit; | 521 | return -ENODEV; |
514 | 522 | ||
515 | dbg("%s - port %d", __FUNCTION__, port->number); | 523 | dbg("%s - port %d", __FUNCTION__, port->number); |
516 | 524 | ||
517 | if (!port->open_count) { | 525 | if (!port->open_count) { |
518 | dbg("%s - port not open", __FUNCTION__); | 526 | dbg("%s - port not open", __FUNCTION__); |
519 | goto exit; | 527 | return -ENODEV; |
520 | } | 528 | } |
521 | 529 | ||
522 | if (port->serial->type->tiocmset) | 530 | if (port->serial->type->tiocmset) |
523 | return port->serial->type->tiocmset(port, file, set, clear); | 531 | return port->serial->type->tiocmset(port, file, set, clear); |
524 | 532 | ||
525 | exit: | ||
526 | return -EINVAL; | 533 | return -EINVAL; |
527 | } | 534 | } |
528 | 535 | ||
529 | void usb_serial_port_softint(void *private) | 536 | /* |
537 | * We would be calling tty_wakeup here, but unfortunately some line | ||
538 | * disciplines have an annoying habit of calling tty->write from | ||
539 | * the write wakeup callback (e.g. n_hdlc.c). | ||
540 | */ | ||
541 | void usb_serial_port_softint(struct usb_serial_port *port) | ||
542 | { | ||
543 | schedule_work(&port->work); | ||
544 | } | ||
545 | |||
546 | static void usb_serial_port_work(void *private) | ||
530 | { | 547 | { |
531 | struct usb_serial_port *port = private; | 548 | struct usb_serial_port *port = private; |
532 | struct tty_struct *tty; | 549 | struct tty_struct *tty; |
@@ -789,7 +806,7 @@ int usb_serial_probe(struct usb_interface *interface, | |||
789 | port->serial = serial; | 806 | port->serial = serial; |
790 | spin_lock_init(&port->lock); | 807 | spin_lock_init(&port->lock); |
791 | mutex_init(&port->mutex); | 808 | mutex_init(&port->mutex); |
792 | INIT_WORK(&port->work, usb_serial_port_softint, port); | 809 | INIT_WORK(&port->work, usb_serial_port_work, port); |
793 | serial->port[i] = port; | 810 | serial->port[i] = port; |
794 | } | 811 | } |
795 | 812 | ||
@@ -985,6 +1002,7 @@ void usb_serial_disconnect(struct usb_interface *interface) | |||
985 | struct device *dev = &interface->dev; | 1002 | struct device *dev = &interface->dev; |
986 | struct usb_serial_port *port; | 1003 | struct usb_serial_port *port; |
987 | 1004 | ||
1005 | usb_serial_console_disconnect(serial); | ||
988 | dbg ("%s", __FUNCTION__); | 1006 | dbg ("%s", __FUNCTION__); |
989 | 1007 | ||
990 | usb_set_intfdata (interface, NULL); | 1008 | usb_set_intfdata (interface, NULL); |
@@ -996,7 +1014,7 @@ void usb_serial_disconnect(struct usb_interface *interface) | |||
996 | } | 1014 | } |
997 | /* let the last holder of this object | 1015 | /* let the last holder of this object |
998 | * cause it to be cleaned up */ | 1016 | * cause it to be cleaned up */ |
999 | kref_put(&serial->kref, destroy_serial); | 1017 | usb_serial_put(serial); |
1000 | } | 1018 | } |
1001 | dev_info(dev, "device disconnected\n"); | 1019 | dev_info(dev, "device disconnected\n"); |
1002 | } | 1020 | } |
diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h index dc89d8710460..d53ea9b11e81 100644 --- a/drivers/usb/serial/usb-serial.h +++ b/drivers/usb/serial/usb-serial.h | |||
@@ -236,7 +236,7 @@ struct usb_serial_driver { | |||
236 | 236 | ||
237 | extern int usb_serial_register(struct usb_serial_driver *driver); | 237 | extern int usb_serial_register(struct usb_serial_driver *driver); |
238 | extern void usb_serial_deregister(struct usb_serial_driver *driver); | 238 | extern void usb_serial_deregister(struct usb_serial_driver *driver); |
239 | extern void usb_serial_port_softint(void *private); | 239 | extern void usb_serial_port_softint(struct usb_serial_port *port); |
240 | 240 | ||
241 | extern int usb_serial_probe(struct usb_interface *iface, const struct usb_device_id *id); | 241 | extern int usb_serial_probe(struct usb_interface *iface, const struct usb_device_id *id); |
242 | extern void usb_serial_disconnect(struct usb_interface *iface); | 242 | extern void usb_serial_disconnect(struct usb_interface *iface); |
@@ -248,13 +248,16 @@ extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit); | |||
248 | #ifdef CONFIG_USB_SERIAL_CONSOLE | 248 | #ifdef CONFIG_USB_SERIAL_CONSOLE |
249 | extern void usb_serial_console_init (int debug, int minor); | 249 | extern void usb_serial_console_init (int debug, int minor); |
250 | extern void usb_serial_console_exit (void); | 250 | extern void usb_serial_console_exit (void); |
251 | extern void usb_serial_console_disconnect(struct usb_serial *serial); | ||
251 | #else | 252 | #else |
252 | static inline void usb_serial_console_init (int debug, int minor) { } | 253 | static inline void usb_serial_console_init (int debug, int minor) { } |
253 | static inline void usb_serial_console_exit (void) { } | 254 | static inline void usb_serial_console_exit (void) { } |
255 | static inline void usb_serial_console_disconnect(struct usb_serial *serial) {} | ||
254 | #endif | 256 | #endif |
255 | 257 | ||
256 | /* Functions needed by other parts of the usbserial core */ | 258 | /* Functions needed by other parts of the usbserial core */ |
257 | extern struct usb_serial *usb_serial_get_by_index (unsigned int minor); | 259 | extern struct usb_serial *usb_serial_get_by_index (unsigned int minor); |
260 | extern void usb_serial_put(struct usb_serial *serial); | ||
258 | extern int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp); | 261 | extern int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp); |
259 | extern int usb_serial_generic_write (struct usb_serial_port *port, const unsigned char *buf, int count); | 262 | extern int usb_serial_generic_write (struct usb_serial_port *port, const unsigned char *buf, int count); |
260 | extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp); | 263 | extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp); |
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index f5c3841d4843..9e89b8d54f72 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c | |||
@@ -480,7 +480,7 @@ static void visor_write_bulk_callback (struct urb *urb, struct pt_regs *regs) | |||
480 | --priv->outstanding_urbs; | 480 | --priv->outstanding_urbs; |
481 | spin_unlock_irqrestore(&priv->lock, flags); | 481 | spin_unlock_irqrestore(&priv->lock, flags); |
482 | 482 | ||
483 | schedule_work(&port->work); | 483 | usb_serial_port_softint(port); |
484 | } | 484 | } |
485 | 485 | ||
486 | 486 | ||
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index f806553cd9a4..5b06fa366098 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c | |||
@@ -388,7 +388,7 @@ static int whiteheat_attach (struct usb_serial *serial) | |||
388 | if (ret) { | 388 | if (ret) { |
389 | err("%s: Couldn't send command [%d]", serial->type->description, ret); | 389 | err("%s: Couldn't send command [%d]", serial->type->description, ret); |
390 | goto no_firmware; | 390 | goto no_firmware; |
391 | } else if (alen != sizeof(command)) { | 391 | } else if (alen != 2) { |
392 | err("%s: Send command incomplete [%d]", serial->type->description, alen); | 392 | err("%s: Send command incomplete [%d]", serial->type->description, alen); |
393 | goto no_firmware; | 393 | goto no_firmware; |
394 | } | 394 | } |
@@ -400,7 +400,7 @@ static int whiteheat_attach (struct usb_serial *serial) | |||
400 | if (ret) { | 400 | if (ret) { |
401 | err("%s: Couldn't get results [%d]", serial->type->description, ret); | 401 | err("%s: Couldn't get results [%d]", serial->type->description, ret); |
402 | goto no_firmware; | 402 | goto no_firmware; |
403 | } else if (alen != sizeof(result)) { | 403 | } else if (alen != sizeof(*hw_info) + 1) { |
404 | err("%s: Get results incomplete [%d]", serial->type->description, alen); | 404 | err("%s: Get results incomplete [%d]", serial->type->description, alen); |
405 | goto no_firmware; | 405 | goto no_firmware; |
406 | } else if (result[0] != command[0]) { | 406 | } else if (result[0] != command[0]) { |
@@ -1089,9 +1089,7 @@ static void whiteheat_write_callback(struct urb *urb, struct pt_regs *regs) | |||
1089 | return; | 1089 | return; |
1090 | } | 1090 | } |
1091 | 1091 | ||
1092 | usb_serial_port_softint((void *)port); | 1092 | usb_serial_port_softint(port); |
1093 | |||
1094 | schedule_work(&port->work); | ||
1095 | } | 1093 | } |
1096 | 1094 | ||
1097 | 1095 | ||