diff options
author | Oliver Neukum <oneukum@suse.de> | 2007-05-04 03:23:40 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-05-23 02:45:51 -0400 |
commit | 9d33efd9a791041bbe3a9e879925ef8fbb94d812 (patch) | |
tree | 28a53c2f115e21a25dc3d1747aca22b395792237 /drivers/usb/misc | |
parent | 2adb80e9c52f35a4d63783b98d48386c38c90484 (diff) |
USB: ldusb bugfix
This patch fixes a problem reported with consecutive reads in the ldusb
driver.
Signed-off-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/misc')
-rw-r--r-- | drivers/usb/misc/ldusb.c | 35 |
1 files changed, 31 insertions, 4 deletions
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index 11555bde655b..7bad49404762 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c | |||
@@ -165,6 +165,8 @@ struct ld_usb { | |||
165 | size_t interrupt_in_endpoint_size; | 165 | size_t interrupt_in_endpoint_size; |
166 | int interrupt_in_running; | 166 | int interrupt_in_running; |
167 | int interrupt_in_done; | 167 | int interrupt_in_done; |
168 | int buffer_overflow; | ||
169 | spinlock_t rbsl; | ||
168 | 170 | ||
169 | char* interrupt_out_buffer; | 171 | char* interrupt_out_buffer; |
170 | struct usb_endpoint_descriptor* interrupt_out_endpoint; | 172 | struct usb_endpoint_descriptor* interrupt_out_endpoint; |
@@ -230,10 +232,12 @@ static void ld_usb_interrupt_in_callback(struct urb *urb) | |||
230 | } else { | 232 | } else { |
231 | dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n", | 233 | dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n", |
232 | __FUNCTION__, urb->status); | 234 | __FUNCTION__, urb->status); |
235 | spin_lock(&dev->rbsl); | ||
233 | goto resubmit; /* maybe we can recover */ | 236 | goto resubmit; /* maybe we can recover */ |
234 | } | 237 | } |
235 | } | 238 | } |
236 | 239 | ||
240 | spin_lock(&dev->rbsl); | ||
237 | if (urb->actual_length > 0) { | 241 | if (urb->actual_length > 0) { |
238 | next_ring_head = (dev->ring_head+1) % ring_buffer_size; | 242 | next_ring_head = (dev->ring_head+1) % ring_buffer_size; |
239 | if (next_ring_head != dev->ring_tail) { | 243 | if (next_ring_head != dev->ring_tail) { |
@@ -244,21 +248,25 @@ static void ld_usb_interrupt_in_callback(struct urb *urb) | |||
244 | dev->ring_head = next_ring_head; | 248 | dev->ring_head = next_ring_head; |
245 | dbg_info(&dev->intf->dev, "%s: received %d bytes\n", | 249 | dbg_info(&dev->intf->dev, "%s: received %d bytes\n", |
246 | __FUNCTION__, urb->actual_length); | 250 | __FUNCTION__, urb->actual_length); |
247 | } else | 251 | } else { |
248 | dev_warn(&dev->intf->dev, | 252 | dev_warn(&dev->intf->dev, |
249 | "Ring buffer overflow, %d bytes dropped\n", | 253 | "Ring buffer overflow, %d bytes dropped\n", |
250 | urb->actual_length); | 254 | urb->actual_length); |
255 | dev->buffer_overflow = 1; | ||
256 | } | ||
251 | } | 257 | } |
252 | 258 | ||
253 | resubmit: | 259 | resubmit: |
254 | /* resubmit if we're still running */ | 260 | /* resubmit if we're still running */ |
255 | if (dev->interrupt_in_running && dev->intf) { | 261 | if (dev->interrupt_in_running && !dev->buffer_overflow && dev->intf) { |
256 | retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC); | 262 | retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC); |
257 | if (retval) | 263 | if (retval) { |
258 | dev_err(&dev->intf->dev, | 264 | dev_err(&dev->intf->dev, |
259 | "usb_submit_urb failed (%d)\n", retval); | 265 | "usb_submit_urb failed (%d)\n", retval); |
266 | dev->buffer_overflow = 1; | ||
267 | } | ||
260 | } | 268 | } |
261 | 269 | spin_unlock(&dev->rbsl); | |
262 | exit: | 270 | exit: |
263 | dev->interrupt_in_done = 1; | 271 | dev->interrupt_in_done = 1; |
264 | wake_up_interruptible(&dev->read_wait); | 272 | wake_up_interruptible(&dev->read_wait); |
@@ -330,6 +338,7 @@ static int ld_usb_open(struct inode *inode, struct file *file) | |||
330 | /* initialize in direction */ | 338 | /* initialize in direction */ |
331 | dev->ring_head = 0; | 339 | dev->ring_head = 0; |
332 | dev->ring_tail = 0; | 340 | dev->ring_tail = 0; |
341 | dev->buffer_overflow = 0; | ||
333 | usb_fill_int_urb(dev->interrupt_in_urb, | 342 | usb_fill_int_urb(dev->interrupt_in_urb, |
334 | interface_to_usbdev(interface), | 343 | interface_to_usbdev(interface), |
335 | usb_rcvintpipe(interface_to_usbdev(interface), | 344 | usb_rcvintpipe(interface_to_usbdev(interface), |
@@ -439,6 +448,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count, | |||
439 | size_t *actual_buffer; | 448 | size_t *actual_buffer; |
440 | size_t bytes_to_read; | 449 | size_t bytes_to_read; |
441 | int retval = 0; | 450 | int retval = 0; |
451 | int rv; | ||
442 | 452 | ||
443 | dev = file->private_data; | 453 | dev = file->private_data; |
444 | 454 | ||
@@ -460,7 +470,10 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count, | |||
460 | } | 470 | } |
461 | 471 | ||
462 | /* wait for data */ | 472 | /* wait for data */ |
473 | spin_lock_irq(&dev->rbsl); | ||
463 | if (dev->ring_head == dev->ring_tail) { | 474 | if (dev->ring_head == dev->ring_tail) { |
475 | dev->interrupt_in_done = 0; | ||
476 | spin_unlock_irq(&dev->rbsl); | ||
464 | if (file->f_flags & O_NONBLOCK) { | 477 | if (file->f_flags & O_NONBLOCK) { |
465 | retval = -EAGAIN; | 478 | retval = -EAGAIN; |
466 | goto unlock_exit; | 479 | goto unlock_exit; |
@@ -468,6 +481,8 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count, | |||
468 | retval = wait_event_interruptible(dev->read_wait, dev->interrupt_in_done); | 481 | retval = wait_event_interruptible(dev->read_wait, dev->interrupt_in_done); |
469 | if (retval < 0) | 482 | if (retval < 0) |
470 | goto unlock_exit; | 483 | goto unlock_exit; |
484 | } else { | ||
485 | spin_unlock_irq(&dev->rbsl); | ||
471 | } | 486 | } |
472 | 487 | ||
473 | /* actual_buffer contains actual_length + interrupt_in_buffer */ | 488 | /* actual_buffer contains actual_length + interrupt_in_buffer */ |
@@ -486,6 +501,17 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count, | |||
486 | 501 | ||
487 | retval = bytes_to_read; | 502 | retval = bytes_to_read; |
488 | 503 | ||
504 | spin_lock_irq(&dev->rbsl); | ||
505 | if (dev->buffer_overflow) { | ||
506 | dev->buffer_overflow = 0; | ||
507 | spin_unlock_irq(&dev->rbsl); | ||
508 | rv = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL); | ||
509 | if (rv < 0) | ||
510 | dev->buffer_overflow = 1; | ||
511 | } else { | ||
512 | spin_unlock_irq(&dev->rbsl); | ||
513 | } | ||
514 | |||
489 | unlock_exit: | 515 | unlock_exit: |
490 | /* unlock the device */ | 516 | /* unlock the device */ |
491 | up(&dev->sem); | 517 | up(&dev->sem); |
@@ -635,6 +661,7 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id * | |||
635 | goto exit; | 661 | goto exit; |
636 | } | 662 | } |
637 | init_MUTEX(&dev->sem); | 663 | init_MUTEX(&dev->sem); |
664 | spin_lock_init(&dev->rbsl); | ||
638 | dev->intf = intf; | 665 | dev->intf = intf; |
639 | init_waitqueue_head(&dev->read_wait); | 666 | init_waitqueue_head(&dev->read_wait); |
640 | init_waitqueue_head(&dev->write_wait); | 667 | init_waitqueue_head(&dev->write_wait); |