aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/usb-serial.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial/usb-serial.c')
-rw-r--r--drivers/usb/serial/usb-serial.c58
1 files changed, 38 insertions, 20 deletions
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 9c36f0ece20..a30135c7cfe 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
173void 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);
231bailout_mutex_unlock: 238bailout_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);
234bailout_kref_put: 243bailout_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
274static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count) 283static 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:
296static int serial_write_room (struct tty_struct *tty) 305static 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:
318static int serial_chars_in_buffer (struct tty_struct *tty) 327static 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;
479done: 488done:
@@ -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
503exit:
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
525exit:
526 return -EINVAL; 533 return -EINVAL;
527} 534}
528 535
529void 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 */
541void usb_serial_port_softint(struct usb_serial_port *port)
542{
543 schedule_work(&port->work);
544}
545
546static 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}