diff options
Diffstat (limited to 'drivers/usb/serial/generic.c')
-rw-r--r-- | drivers/usb/serial/generic.c | 83 |
1 files changed, 62 insertions, 21 deletions
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index e4db5ad2bc55..f7403576f99f 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 Johan Hovold (jhovold@gmail.com) | 4 | * Copyright (C) 2010 - 2011 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 |
@@ -132,7 +132,7 @@ int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port | |||
132 | 132 | ||
133 | /* if we have a bulk endpoint, start reading from it */ | 133 | /* if we have a bulk endpoint, start reading from it */ |
134 | if (port->bulk_in_size) | 134 | if (port->bulk_in_size) |
135 | result = usb_serial_generic_submit_read_urb(port, GFP_KERNEL); | 135 | result = usb_serial_generic_submit_read_urbs(port, GFP_KERNEL); |
136 | 136 | ||
137 | return result; | 137 | return result; |
138 | } | 138 | } |
@@ -157,8 +157,10 @@ static void generic_cleanup(struct usb_serial_port *port) | |||
157 | kfifo_reset_out(&port->write_fifo); | 157 | kfifo_reset_out(&port->write_fifo); |
158 | spin_unlock_irqrestore(&port->lock, flags); | 158 | spin_unlock_irqrestore(&port->lock, flags); |
159 | } | 159 | } |
160 | if (port->bulk_in_size) | 160 | if (port->bulk_in_size) { |
161 | usb_kill_urb(port->read_urb); | 161 | for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) |
162 | usb_kill_urb(port->read_urbs[i]); | ||
163 | } | ||
162 | } | 164 | } |
163 | } | 165 | } |
164 | 166 | ||
@@ -308,19 +310,52 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) | |||
308 | return chars; | 310 | return chars; |
309 | } | 311 | } |
310 | 312 | ||
311 | int usb_serial_generic_submit_read_urb(struct usb_serial_port *port, | 313 | static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port, |
314 | int index, gfp_t mem_flags) | ||
315 | { | ||
316 | int res; | ||
317 | |||
318 | if (!test_and_clear_bit(index, &port->read_urbs_free)) | ||
319 | return 0; | ||
320 | |||
321 | dbg("%s - port %d, urb %d\n", __func__, port->number, index); | ||
322 | |||
323 | res = usb_submit_urb(port->read_urbs[index], mem_flags); | ||
324 | if (res) { | ||
325 | if (res != -EPERM) { | ||
326 | dev_err(&port->dev, | ||
327 | "%s - usb_submit_urb failed: %d\n", | ||
328 | __func__, res); | ||
329 | } | ||
330 | set_bit(index, &port->read_urbs_free); | ||
331 | return res; | ||
332 | } | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | int usb_serial_generic_submit_read_urbs(struct usb_serial_port *port, | ||
312 | gfp_t mem_flags) | 338 | gfp_t mem_flags) |
313 | { | 339 | { |
314 | int result; | 340 | int res; |
341 | int i; | ||
315 | 342 | ||
316 | result = usb_submit_urb(port->read_urb, mem_flags); | 343 | dbg("%s - port %d", __func__, port->number); |
317 | if (result && result != -EPERM) { | 344 | |
318 | dev_err(&port->dev, "%s - error submitting urb: %d\n", | 345 | for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) { |
319 | __func__, result); | 346 | res = usb_serial_generic_submit_read_urb(port, i, mem_flags); |
347 | if (res) | ||
348 | goto err; | ||
320 | } | 349 | } |
321 | return result; | 350 | |
351 | return 0; | ||
352 | err: | ||
353 | for (; i >= 0; --i) | ||
354 | usb_kill_urb(port->read_urbs[i]); | ||
355 | |||
356 | return res; | ||
322 | } | 357 | } |
323 | EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urb); | 358 | EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urbs); |
324 | 359 | ||
325 | void usb_serial_generic_process_read_urb(struct urb *urb) | 360 | void usb_serial_generic_process_read_urb(struct urb *urb) |
326 | { | 361 | { |
@@ -356,14 +391,19 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb) | |||
356 | { | 391 | { |
357 | struct usb_serial_port *port = urb->context; | 392 | struct usb_serial_port *port = urb->context; |
358 | unsigned char *data = urb->transfer_buffer; | 393 | unsigned char *data = urb->transfer_buffer; |
359 | int status = urb->status; | ||
360 | unsigned long flags; | 394 | unsigned long flags; |
395 | int i; | ||
361 | 396 | ||
362 | dbg("%s - port %d", __func__, port->number); | 397 | for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) { |
398 | if (urb == port->read_urbs[i]) | ||
399 | break; | ||
400 | } | ||
401 | set_bit(i, &port->read_urbs_free); | ||
363 | 402 | ||
364 | if (unlikely(status != 0)) { | 403 | dbg("%s - port %d, urb %d, len %d\n", __func__, port->number, i, |
365 | dbg("%s - nonzero read bulk status received: %d", | 404 | urb->actual_length); |
366 | __func__, status); | 405 | if (urb->status) { |
406 | dbg("%s - non-zero urb status: %d\n", __func__, urb->status); | ||
367 | return; | 407 | return; |
368 | } | 408 | } |
369 | 409 | ||
@@ -376,7 +416,7 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb) | |||
376 | port->throttled = port->throttle_req; | 416 | port->throttled = port->throttle_req; |
377 | if (!port->throttled) { | 417 | if (!port->throttled) { |
378 | spin_unlock_irqrestore(&port->lock, flags); | 418 | spin_unlock_irqrestore(&port->lock, flags); |
379 | usb_serial_generic_submit_read_urb(port, GFP_ATOMIC); | 419 | usb_serial_generic_submit_read_urb(port, i, GFP_ATOMIC); |
380 | } else | 420 | } else |
381 | spin_unlock_irqrestore(&port->lock, flags); | 421 | spin_unlock_irqrestore(&port->lock, flags); |
382 | } | 422 | } |
@@ -443,7 +483,7 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty) | |||
443 | spin_unlock_irq(&port->lock); | 483 | spin_unlock_irq(&port->lock); |
444 | 484 | ||
445 | if (was_throttled) | 485 | if (was_throttled) |
446 | usb_serial_generic_submit_read_urb(port, GFP_KERNEL); | 486 | usb_serial_generic_submit_read_urbs(port, GFP_KERNEL); |
447 | } | 487 | } |
448 | EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle); | 488 | EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle); |
449 | 489 | ||
@@ -509,8 +549,9 @@ int usb_serial_generic_resume(struct usb_serial *serial) | |||
509 | if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) | 549 | if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) |
510 | continue; | 550 | continue; |
511 | 551 | ||
512 | if (port->read_urb) { | 552 | if (port->bulk_in_size) { |
513 | r = usb_submit_urb(port->read_urb, GFP_NOIO); | 553 | r = usb_serial_generic_submit_read_urbs(port, |
554 | GFP_NOIO); | ||
514 | if (r < 0) | 555 | if (r < 0) |
515 | c++; | 556 | c++; |
516 | } | 557 | } |