diff options
Diffstat (limited to 'drivers/usb/serial/generic.c')
-rw-r--r-- | drivers/usb/serial/generic.c | 59 |
1 files changed, 39 insertions, 20 deletions
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 1a134f9c64f3..3ae17840175c 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c | |||
@@ -1,6 +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) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) | 5 | * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) |
5 | * | 6 | * |
6 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
@@ -143,6 +144,7 @@ static void generic_cleanup(struct usb_serial_port *port) | |||
143 | { | 144 | { |
144 | struct usb_serial *serial = port->serial; | 145 | struct usb_serial *serial = port->serial; |
145 | unsigned long flags; | 146 | unsigned long flags; |
147 | int i; | ||
146 | 148 | ||
147 | dbg("%s - port %d", __func__, port->number); | 149 | dbg("%s - port %d", __func__, port->number); |
148 | 150 | ||
@@ -150,6 +152,8 @@ static void generic_cleanup(struct usb_serial_port *port) | |||
150 | /* shutdown any bulk transfers that might be going on */ | 152 | /* shutdown any bulk transfers that might be going on */ |
151 | if (port->bulk_out_size) { | 153 | if (port->bulk_out_size) { |
152 | usb_kill_urb(port->write_urb); | 154 | usb_kill_urb(port->write_urb); |
155 | for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) | ||
156 | usb_kill_urb(port->write_urbs[i]); | ||
153 | 157 | ||
154 | spin_lock_irqsave(&port->lock, flags); | 158 | spin_lock_irqsave(&port->lock, flags); |
155 | kfifo_reset_out(&port->write_fifo); | 159 | kfifo_reset_out(&port->write_fifo); |
@@ -258,46 +262,56 @@ err_urb: | |||
258 | * usb_serial_generic_write_start - kick off an URB write | 262 | * usb_serial_generic_write_start - kick off an URB write |
259 | * @port: Pointer to the &struct usb_serial_port data | 263 | * @port: Pointer to the &struct usb_serial_port data |
260 | * | 264 | * |
261 | * Returns the number of bytes queued on success. This will be zero if there | 265 | * Returns zero on success, or a negative errno value |
262 | * was nothing to send. Otherwise, it returns a negative errno value | ||
263 | */ | 266 | */ |
264 | static int usb_serial_generic_write_start(struct usb_serial_port *port) | 267 | static int usb_serial_generic_write_start(struct usb_serial_port *port) |
265 | { | 268 | { |
266 | int result; | 269 | struct urb *urb; |
267 | int count; | 270 | int count, result; |
268 | unsigned long flags; | 271 | unsigned long flags; |
272 | int i; | ||
269 | 273 | ||
274 | if (test_and_set_bit_lock(USB_SERIAL_WRITE_BUSY, &port->flags)) | ||
275 | return 0; | ||
276 | retry: | ||
270 | spin_lock_irqsave(&port->lock, flags); | 277 | spin_lock_irqsave(&port->lock, flags); |
271 | if (port->write_urb_busy || !kfifo_len(&port->write_fifo)) { | 278 | if (!port->write_urbs_free || !kfifo_len(&port->write_fifo)) { |
279 | clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags); | ||
272 | spin_unlock_irqrestore(&port->lock, flags); | 280 | spin_unlock_irqrestore(&port->lock, flags); |
273 | return 0; | 281 | return 0; |
274 | } | 282 | } |
275 | port->write_urb_busy = 1; | 283 | i = (int)find_first_bit(&port->write_urbs_free, |
284 | ARRAY_SIZE(port->write_urbs)); | ||
276 | spin_unlock_irqrestore(&port->lock, flags); | 285 | spin_unlock_irqrestore(&port->lock, flags); |
277 | 286 | ||
287 | urb = port->write_urbs[i]; | ||
278 | count = port->serial->type->prepare_write_buffer(port, | 288 | count = port->serial->type->prepare_write_buffer(port, |
279 | &port->write_urb->transfer_buffer, | 289 | &urb->transfer_buffer, |
280 | port->bulk_out_size, NULL, 0); | 290 | port->bulk_out_size, NULL, 0); |
281 | usb_serial_debug_data(debug, &port->dev, __func__, | 291 | urb->transfer_buffer_length = count; |
282 | count, port->write_urb->transfer_buffer); | 292 | usb_serial_debug_data(debug, &port->dev, __func__, count, |
283 | port->write_urb->transfer_buffer_length = count; | 293 | urb->transfer_buffer); |
284 | 294 | result = usb_submit_urb(urb, GFP_ATOMIC); | |
285 | /* send the data out the bulk port */ | ||
286 | result = usb_submit_urb(port->write_urb, GFP_ATOMIC); | ||
287 | if (result) { | 295 | if (result) { |
288 | dev_err(&port->dev, "%s - error submitting urb: %d\n", | 296 | dev_err(&port->dev, "%s - error submitting urb: %d\n", |
289 | __func__, result); | 297 | __func__, result); |
290 | /* don't have to grab the lock here, as we will | 298 | clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags); |
291 | retry if != 0 */ | ||
292 | port->write_urb_busy = 0; | ||
293 | return result; | 299 | return result; |
294 | } | 300 | } |
301 | clear_bit(i, &port->write_urbs_free); | ||
295 | 302 | ||
296 | spin_lock_irqsave(&port->lock, flags); | 303 | spin_lock_irqsave(&port->lock, flags); |
297 | port->tx_bytes += count; | 304 | port->tx_bytes += count; |
298 | spin_unlock_irqrestore(&port->lock, flags); | 305 | spin_unlock_irqrestore(&port->lock, flags); |
299 | 306 | ||
300 | return count; | 307 | /* Try sending off another urb, unless in irq context (in which case |
308 | * there will be no free urb). */ | ||
309 | if (!in_irq()) | ||
310 | goto retry; | ||
311 | |||
312 | clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags); | ||
313 | |||
314 | return 0; | ||
301 | } | 315 | } |
302 | 316 | ||
303 | /** | 317 | /** |
@@ -461,6 +475,7 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb) | |||
461 | unsigned long flags; | 475 | unsigned long flags; |
462 | struct usb_serial_port *port = urb->context; | 476 | struct usb_serial_port *port = urb->context; |
463 | int status = urb->status; | 477 | int status = urb->status; |
478 | int i; | ||
464 | 479 | ||
465 | dbg("%s - port %d", __func__, port->number); | 480 | dbg("%s - port %d", __func__, port->number); |
466 | 481 | ||
@@ -472,9 +487,13 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb) | |||
472 | port->tx_urbs--; | 487 | port->tx_urbs--; |
473 | spin_unlock_irqrestore(&port->lock, flags); | 488 | spin_unlock_irqrestore(&port->lock, flags); |
474 | } else { | 489 | } else { |
490 | for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) | ||
491 | if (port->write_urbs[i] == urb) | ||
492 | break; | ||
493 | |||
475 | spin_lock_irqsave(&port->lock, flags); | 494 | spin_lock_irqsave(&port->lock, flags); |
476 | port->tx_bytes -= urb->transfer_buffer_length; | 495 | port->tx_bytes -= urb->transfer_buffer_length; |
477 | port->write_urb_busy = 0; | 496 | set_bit(i, &port->write_urbs_free); |
478 | spin_unlock_irqrestore(&port->lock, flags); | 497 | spin_unlock_irqrestore(&port->lock, flags); |
479 | 498 | ||
480 | if (status) { | 499 | if (status) { |
@@ -576,7 +595,7 @@ int usb_serial_generic_resume(struct usb_serial *serial) | |||
576 | c++; | 595 | c++; |
577 | } | 596 | } |
578 | 597 | ||
579 | if (port->write_urb) { | 598 | if (port->bulk_out_size) { |
580 | r = usb_serial_generic_write_start(port); | 599 | r = usb_serial_generic_write_start(port); |
581 | if (r < 0) | 600 | if (r < 0) |
582 | c++; | 601 | c++; |