diff options
| -rw-r--r-- | drivers/usb/serial/generic.c | 59 | ||||
| -rw-r--r-- | drivers/usb/serial/usb-serial.c | 33 | ||||
| -rw-r--r-- | include/linux/usb/serial.h | 12 |
3 files changed, 84 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++; |
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 8249fd8381fb..941c2d409f85 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c | |||
| @@ -548,8 +548,12 @@ static void usb_serial_port_work(struct work_struct *work) | |||
| 548 | 548 | ||
| 549 | static void kill_traffic(struct usb_serial_port *port) | 549 | static void kill_traffic(struct usb_serial_port *port) |
| 550 | { | 550 | { |
| 551 | int i; | ||
| 552 | |||
| 551 | usb_kill_urb(port->read_urb); | 553 | usb_kill_urb(port->read_urb); |
| 552 | usb_kill_urb(port->write_urb); | 554 | usb_kill_urb(port->write_urb); |
| 555 | for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) | ||
| 556 | usb_kill_urb(port->write_urbs[i]); | ||
| 553 | /* | 557 | /* |
| 554 | * This is tricky. | 558 | * This is tricky. |
| 555 | * Some drivers submit the read_urb in the | 559 | * Some drivers submit the read_urb in the |
| @@ -568,6 +572,7 @@ static void kill_traffic(struct usb_serial_port *port) | |||
| 568 | static void port_release(struct device *dev) | 572 | static void port_release(struct device *dev) |
| 569 | { | 573 | { |
| 570 | struct usb_serial_port *port = to_usb_serial_port(dev); | 574 | struct usb_serial_port *port = to_usb_serial_port(dev); |
| 575 | int i; | ||
| 571 | 576 | ||
| 572 | dbg ("%s - %s", __func__, dev_name(dev)); | 577 | dbg ("%s - %s", __func__, dev_name(dev)); |
| 573 | 578 | ||
| @@ -582,6 +587,10 @@ static void port_release(struct device *dev) | |||
| 582 | usb_free_urb(port->write_urb); | 587 | usb_free_urb(port->write_urb); |
| 583 | usb_free_urb(port->interrupt_in_urb); | 588 | usb_free_urb(port->interrupt_in_urb); |
| 584 | usb_free_urb(port->interrupt_out_urb); | 589 | usb_free_urb(port->interrupt_out_urb); |
| 590 | for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) { | ||
| 591 | usb_free_urb(port->write_urbs[i]); | ||
| 592 | kfree(port->bulk_out_buffers[i]); | ||
| 593 | } | ||
| 585 | kfifo_free(&port->write_fifo); | 594 | kfifo_free(&port->write_fifo); |
| 586 | kfree(port->bulk_in_buffer); | 595 | kfree(port->bulk_in_buffer); |
| 587 | kfree(port->bulk_out_buffer); | 596 | kfree(port->bulk_out_buffer); |
| @@ -920,6 +929,8 @@ int usb_serial_probe(struct usb_interface *interface, | |||
| 920 | } | 929 | } |
| 921 | 930 | ||
| 922 | for (i = 0; i < num_bulk_out; ++i) { | 931 | for (i = 0; i < num_bulk_out; ++i) { |
| 932 | int j; | ||
| 933 | |||
| 923 | endpoint = bulk_out_endpoint[i]; | 934 | endpoint = bulk_out_endpoint[i]; |
| 924 | port = serial->port[i]; | 935 | port = serial->port[i]; |
| 925 | port->write_urb = usb_alloc_urb(0, GFP_KERNEL); | 936 | port->write_urb = usb_alloc_urb(0, GFP_KERNEL); |
| @@ -945,6 +956,28 @@ int usb_serial_probe(struct usb_interface *interface, | |||
| 945 | endpoint->bEndpointAddress), | 956 | endpoint->bEndpointAddress), |
| 946 | port->bulk_out_buffer, buffer_size, | 957 | port->bulk_out_buffer, buffer_size, |
| 947 | serial->type->write_bulk_callback, port); | 958 | serial->type->write_bulk_callback, port); |
| 959 | for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) { | ||
| 960 | set_bit(j, &port->write_urbs_free); | ||
| 961 | port->write_urbs[j] = usb_alloc_urb(0, GFP_KERNEL); | ||
| 962 | if (!port->write_urbs[j]) { | ||
| 963 | dev_err(&interface->dev, | ||
| 964 | "No free urbs available\n"); | ||
| 965 | goto probe_error; | ||
| 966 | } | ||
| 967 | port->bulk_out_buffers[j] = kmalloc(buffer_size, | ||
| 968 | GFP_KERNEL); | ||
| 969 | if (!port->bulk_out_buffers[j]) { | ||
| 970 | dev_err(&interface->dev, | ||
| 971 | "Couldn't allocate bulk_out_buffer\n"); | ||
| 972 | goto probe_error; | ||
| 973 | } | ||
| 974 | usb_fill_bulk_urb(port->write_urbs[j], dev, | ||
| 975 | usb_sndbulkpipe(dev, | ||
| 976 | endpoint->bEndpointAddress), | ||
| 977 | port->bulk_out_buffers[j], buffer_size, | ||
| 978 | serial->type->write_bulk_callback, | ||
| 979 | port); | ||
| 980 | } | ||
| 948 | } | 981 | } |
| 949 | 982 | ||
| 950 | if (serial->type->read_int_callback) { | 983 | if (serial->type->read_int_callback) { |
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index a4c99ea390e7..70b6d6b28997 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h | |||
| @@ -35,6 +35,9 @@ enum port_dev_state { | |||
| 35 | PORT_UNREGISTERING, | 35 | PORT_UNREGISTERING, |
| 36 | }; | 36 | }; |
| 37 | 37 | ||
| 38 | /* USB serial flags */ | ||
| 39 | #define USB_SERIAL_WRITE_BUSY 0 | ||
| 40 | |||
| 38 | /** | 41 | /** |
| 39 | * usb_serial_port: structure for the specific ports of a device. | 42 | * usb_serial_port: structure for the specific ports of a device. |
| 40 | * @serial: pointer back to the struct usb_serial owner of this port. | 43 | * @serial: pointer back to the struct usb_serial owner of this port. |
| @@ -60,10 +63,14 @@ enum port_dev_state { | |||
| 60 | * @write_urb: pointer to the bulk out struct urb for this port. | 63 | * @write_urb: pointer to the bulk out struct urb for this port. |
| 61 | * @write_fifo: kfifo used to buffer outgoing data | 64 | * @write_fifo: kfifo used to buffer outgoing data |
| 62 | * @write_urb_busy: port`s writing status | 65 | * @write_urb_busy: port`s writing status |
| 66 | * @bulk_out_buffers: pointers to the bulk out buffers for this port | ||
| 67 | * @write_urbs: pointers to the bulk out urbs for this port | ||
| 68 | * @write_urbs_free: status bitmap the for bulk out urbs | ||
| 63 | * @tx_bytes: number of bytes currently in host stack queues | 69 | * @tx_bytes: number of bytes currently in host stack queues |
| 64 | * @tx_urbs: number of urbs currently in host stack queues | 70 | * @tx_urbs: number of urbs currently in host stack queues |
| 65 | * @bulk_out_endpointAddress: endpoint address for the bulk out pipe for this | 71 | * @bulk_out_endpointAddress: endpoint address for the bulk out pipe for this |
| 66 | * port. | 72 | * port. |
| 73 | * @flags: usb serial port flags | ||
| 67 | * @write_wait: a wait_queue_head_t used by the port. | 74 | * @write_wait: a wait_queue_head_t used by the port. |
| 68 | * @work: work queue entry for the line discipline waking up. | 75 | * @work: work queue entry for the line discipline waking up. |
| 69 | * @throttled: nonzero if the read urb is inactive to throttle the device | 76 | * @throttled: nonzero if the read urb is inactive to throttle the device |
| @@ -98,11 +105,16 @@ struct usb_serial_port { | |||
| 98 | struct urb *write_urb; | 105 | struct urb *write_urb; |
| 99 | struct kfifo write_fifo; | 106 | struct kfifo write_fifo; |
| 100 | int write_urb_busy; | 107 | int write_urb_busy; |
| 108 | |||
| 109 | unsigned char *bulk_out_buffers[2]; | ||
| 110 | struct urb *write_urbs[2]; | ||
| 111 | unsigned long write_urbs_free; | ||
| 101 | __u8 bulk_out_endpointAddress; | 112 | __u8 bulk_out_endpointAddress; |
| 102 | 113 | ||
| 103 | int tx_bytes; | 114 | int tx_bytes; |
| 104 | int tx_urbs; | 115 | int tx_urbs; |
| 105 | 116 | ||
| 117 | unsigned long flags; | ||
| 106 | wait_queue_head_t write_wait; | 118 | wait_queue_head_t write_wait; |
| 107 | struct work_struct work; | 119 | struct work_struct work; |
| 108 | char throttled; | 120 | char throttled; |
