aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver Neukum <oneukum@suse.de>2007-05-04 03:23:40 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-05-23 02:45:51 -0400
commit9d33efd9a791041bbe3a9e879925ef8fbb94d812 (patch)
tree28a53c2f115e21a25dc3d1747aca22b395792237
parent2adb80e9c52f35a4d63783b98d48386c38c90484 (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>
-rw-r--r--drivers/usb/misc/ldusb.c35
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
253resubmit: 259resubmit:
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);
262exit: 270exit:
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
489unlock_exit: 515unlock_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);