diff options
Diffstat (limited to 'drivers/usb/serial/usb-serial.c')
-rw-r--r-- | drivers/usb/serial/usb-serial.c | 58 |
1 files changed, 38 insertions, 20 deletions
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 | } |