diff options
Diffstat (limited to 'drivers/usb/serial/generic.c')
-rw-r--r-- | drivers/usb/serial/generic.c | 144 |
1 files changed, 101 insertions, 43 deletions
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 4c5c23f1cae5..297665fdd16d 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * USB Serial Converter Generic functions | 2 | * USB Serial Converter Generic functions |
3 | * | 3 | * |
4 | * Copyright (C) 2010 - 2011 Johan Hovold (jhovold@gmail.com) | 4 | * Copyright (C) 2010 - 2013 Johan Hovold (jhovold@gmail.com) |
5 | * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) | 5 | * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
@@ -45,8 +45,6 @@ struct usb_serial_driver usb_serial_generic_device = { | |||
45 | }, | 45 | }, |
46 | .id_table = generic_device_ids, | 46 | .id_table = generic_device_ids, |
47 | .num_ports = 1, | 47 | .num_ports = 1, |
48 | .disconnect = usb_serial_generic_disconnect, | ||
49 | .release = usb_serial_generic_release, | ||
50 | .throttle = usb_serial_generic_throttle, | 48 | .throttle = usb_serial_generic_throttle, |
51 | .unthrottle = usb_serial_generic_unthrottle, | 49 | .unthrottle = usb_serial_generic_unthrottle, |
52 | .resume = usb_serial_generic_resume, | 50 | .resume = usb_serial_generic_resume, |
@@ -102,32 +100,23 @@ int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port | |||
102 | } | 100 | } |
103 | EXPORT_SYMBOL_GPL(usb_serial_generic_open); | 101 | EXPORT_SYMBOL_GPL(usb_serial_generic_open); |
104 | 102 | ||
105 | static void generic_cleanup(struct usb_serial_port *port) | 103 | void usb_serial_generic_close(struct usb_serial_port *port) |
106 | { | 104 | { |
107 | struct usb_serial *serial = port->serial; | ||
108 | unsigned long flags; | 105 | unsigned long flags; |
109 | int i; | 106 | int i; |
110 | 107 | ||
111 | if (serial->dev) { | 108 | if (port->bulk_out_size) { |
112 | /* shutdown any bulk transfers that might be going on */ | 109 | for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) |
113 | if (port->bulk_out_size) { | 110 | usb_kill_urb(port->write_urbs[i]); |
114 | for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) | ||
115 | usb_kill_urb(port->write_urbs[i]); | ||
116 | 111 | ||
117 | spin_lock_irqsave(&port->lock, flags); | 112 | spin_lock_irqsave(&port->lock, flags); |
118 | kfifo_reset_out(&port->write_fifo); | 113 | kfifo_reset_out(&port->write_fifo); |
119 | spin_unlock_irqrestore(&port->lock, flags); | 114 | spin_unlock_irqrestore(&port->lock, flags); |
120 | } | 115 | } |
121 | if (port->bulk_in_size) { | 116 | if (port->bulk_in_size) { |
122 | for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) | 117 | for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) |
123 | usb_kill_urb(port->read_urbs[i]); | 118 | usb_kill_urb(port->read_urbs[i]); |
124 | } | ||
125 | } | 119 | } |
126 | } | ||
127 | |||
128 | void usb_serial_generic_close(struct usb_serial_port *port) | ||
129 | { | ||
130 | generic_cleanup(port); | ||
131 | } | 120 | } |
132 | EXPORT_SYMBOL_GPL(usb_serial_generic_close); | 121 | EXPORT_SYMBOL_GPL(usb_serial_generic_close); |
133 | 122 | ||
@@ -272,8 +261,7 @@ static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port, | |||
272 | if (!test_and_clear_bit(index, &port->read_urbs_free)) | 261 | if (!test_and_clear_bit(index, &port->read_urbs_free)) |
273 | return 0; | 262 | return 0; |
274 | 263 | ||
275 | dev_dbg(&port->dev, "%s - port %d, urb %d\n", __func__, | 264 | dev_dbg(&port->dev, "%s - urb %d\n", __func__, index); |
276 | port->number, index); | ||
277 | 265 | ||
278 | res = usb_submit_urb(port->read_urbs[index], mem_flags); | 266 | res = usb_submit_urb(port->read_urbs[index], mem_flags); |
279 | if (res) { | 267 | if (res) { |
@@ -347,8 +335,8 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb) | |||
347 | } | 335 | } |
348 | set_bit(i, &port->read_urbs_free); | 336 | set_bit(i, &port->read_urbs_free); |
349 | 337 | ||
350 | dev_dbg(&port->dev, "%s - port %d, urb %d, len %d\n", | 338 | dev_dbg(&port->dev, "%s - urb %d, len %d\n", __func__, i, |
351 | __func__, port->number, i, urb->actual_length); | 339 | urb->actual_length); |
352 | 340 | ||
353 | if (urb->status) { | 341 | if (urb->status) { |
354 | dev_dbg(&port->dev, "%s - non-zero urb status: %d\n", | 342 | dev_dbg(&port->dev, "%s - non-zero urb status: %d\n", |
@@ -430,6 +418,91 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty) | |||
430 | } | 418 | } |
431 | EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle); | 419 | EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle); |
432 | 420 | ||
421 | static bool usb_serial_generic_msr_changed(struct tty_struct *tty, | ||
422 | unsigned long arg, struct async_icount *cprev) | ||
423 | { | ||
424 | struct usb_serial_port *port = tty->driver_data; | ||
425 | struct async_icount cnow; | ||
426 | unsigned long flags; | ||
427 | bool ret; | ||
428 | |||
429 | /* | ||
430 | * Use tty-port initialised flag to detect all hangups including the | ||
431 | * one generated at USB-device disconnect. | ||
432 | * | ||
433 | * FIXME: Remove hupping check once tty_port_hangup calls shutdown | ||
434 | * (which clears the initialised flag) before wake up. | ||
435 | */ | ||
436 | if (test_bit(TTY_HUPPING, &tty->flags)) | ||
437 | return true; | ||
438 | if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) | ||
439 | return true; | ||
440 | |||
441 | spin_lock_irqsave(&port->lock, flags); | ||
442 | cnow = port->icount; /* atomic copy*/ | ||
443 | spin_unlock_irqrestore(&port->lock, flags); | ||
444 | |||
445 | ret = ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) || | ||
446 | ((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) || | ||
447 | ((arg & TIOCM_CD) && (cnow.dcd != cprev->dcd)) || | ||
448 | ((arg & TIOCM_CTS) && (cnow.cts != cprev->cts)); | ||
449 | |||
450 | *cprev = cnow; | ||
451 | |||
452 | return ret; | ||
453 | } | ||
454 | |||
455 | int usb_serial_generic_tiocmiwait(struct tty_struct *tty, unsigned long arg) | ||
456 | { | ||
457 | struct usb_serial_port *port = tty->driver_data; | ||
458 | struct async_icount cnow; | ||
459 | unsigned long flags; | ||
460 | int ret; | ||
461 | |||
462 | spin_lock_irqsave(&port->lock, flags); | ||
463 | cnow = port->icount; /* atomic copy */ | ||
464 | spin_unlock_irqrestore(&port->lock, flags); | ||
465 | |||
466 | ret = wait_event_interruptible(port->port.delta_msr_wait, | ||
467 | usb_serial_generic_msr_changed(tty, arg, &cnow)); | ||
468 | if (!ret) { | ||
469 | if (test_bit(TTY_HUPPING, &tty->flags)) | ||
470 | ret = -EIO; | ||
471 | if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) | ||
472 | ret = -EIO; | ||
473 | } | ||
474 | |||
475 | return ret; | ||
476 | } | ||
477 | EXPORT_SYMBOL_GPL(usb_serial_generic_tiocmiwait); | ||
478 | |||
479 | int usb_serial_generic_get_icount(struct tty_struct *tty, | ||
480 | struct serial_icounter_struct *icount) | ||
481 | { | ||
482 | struct usb_serial_port *port = tty->driver_data; | ||
483 | struct async_icount cnow; | ||
484 | unsigned long flags; | ||
485 | |||
486 | spin_lock_irqsave(&port->lock, flags); | ||
487 | cnow = port->icount; /* atomic copy */ | ||
488 | spin_unlock_irqrestore(&port->lock, flags); | ||
489 | |||
490 | icount->cts = cnow.cts; | ||
491 | icount->dsr = cnow.dsr; | ||
492 | icount->rng = cnow.rng; | ||
493 | icount->dcd = cnow.dcd; | ||
494 | icount->tx = cnow.tx; | ||
495 | icount->rx = cnow.rx; | ||
496 | icount->frame = cnow.frame; | ||
497 | icount->parity = cnow.parity; | ||
498 | icount->overrun = cnow.overrun; | ||
499 | icount->brk = cnow.brk; | ||
500 | icount->buf_overrun = cnow.buf_overrun; | ||
501 | |||
502 | return 0; | ||
503 | } | ||
504 | EXPORT_SYMBOL_GPL(usb_serial_generic_get_icount); | ||
505 | |||
433 | #ifdef CONFIG_MAGIC_SYSRQ | 506 | #ifdef CONFIG_MAGIC_SYSRQ |
434 | int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch) | 507 | int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch) |
435 | { | 508 | { |
@@ -473,8 +546,7 @@ void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port, | |||
473 | { | 546 | { |
474 | struct tty_port *port = &usb_port->port; | 547 | struct tty_port *port = &usb_port->port; |
475 | 548 | ||
476 | dev_dbg(&usb_port->dev, "%s - port %d, status %d\n", __func__, | 549 | dev_dbg(&usb_port->dev, "%s - status %d\n", __func__, status); |
477 | usb_port->number, status); | ||
478 | 550 | ||
479 | if (status) | 551 | if (status) |
480 | wake_up_interruptible(&port->open_wait); | 552 | wake_up_interruptible(&port->open_wait); |
@@ -510,17 +582,3 @@ int usb_serial_generic_resume(struct usb_serial *serial) | |||
510 | return c ? -EIO : 0; | 582 | return c ? -EIO : 0; |
511 | } | 583 | } |
512 | EXPORT_SYMBOL_GPL(usb_serial_generic_resume); | 584 | EXPORT_SYMBOL_GPL(usb_serial_generic_resume); |
513 | |||
514 | void usb_serial_generic_disconnect(struct usb_serial *serial) | ||
515 | { | ||
516 | int i; | ||
517 | |||
518 | /* stop reads and writes on all ports */ | ||
519 | for (i = 0; i < serial->num_ports; ++i) | ||
520 | generic_cleanup(serial->port[i]); | ||
521 | } | ||
522 | EXPORT_SYMBOL_GPL(usb_serial_generic_disconnect); | ||
523 | |||
524 | void usb_serial_generic_release(struct usb_serial *serial) | ||
525 | { | ||
526 | } | ||