aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorPete Zaitcev <zaitcev@redhat.com>2010-11-16 23:51:19 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2010-11-30 19:44:54 -0500
commitb17ea167c5fb50dcd5dce5b874a467f04eec886d (patch)
tree5a4714f6612e52e051d9b4495b3150466b3d3499 /drivers
parent4f6838436915fdc281173bfd5bef6d8ab5cb1a7f (diff)
usbmon: correct length for isochronous
Usually the usbmon returns the amount of data specified in urb->transfer_buffer_length for output submissions and urb->actual_length for input callbacks. However, for Isochronous input transfers, this is not enough, since the returned data buffer may contain "holes". One easy way to fix this is to use urb->transfer_buffer_length, but this often transfers a whole lot of unused data, so we find how much was actually used instead. Original patch by Márton Németh. See also kernel bug 22182. Signed-off-by: Pete Zaitcev <zaitcev@redhat.com> Signed-off-by: Márton Németh <nm127@freemail.hu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/mon/mon_bin.c34
1 files changed, 31 insertions, 3 deletions
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
index 44cb37b5a4dc..a4cae2ea5cbf 100644
--- a/drivers/usb/mon/mon_bin.c
+++ b/drivers/usb/mon/mon_bin.c
@@ -437,6 +437,28 @@ static unsigned int mon_bin_get_data(const struct mon_reader_bin *rp,
437 return length; 437 return length;
438} 438}
439 439
440/*
441 * This is the look-ahead pass in case of 'C Zi', when actual_length cannot
442 * be used to determine the length of the whole contiguous buffer.
443 */
444static unsigned int mon_bin_collate_isodesc(const struct mon_reader_bin *rp,
445 struct urb *urb, unsigned int ndesc)
446{
447 struct usb_iso_packet_descriptor *fp;
448 unsigned int length;
449
450 length = 0;
451 fp = urb->iso_frame_desc;
452 while (ndesc-- != 0) {
453 if (fp->actual_length != 0) {
454 if (fp->offset + fp->actual_length > length)
455 length = fp->offset + fp->actual_length;
456 }
457 fp++;
458 }
459 return length;
460}
461
440static void mon_bin_get_isodesc(const struct mon_reader_bin *rp, 462static void mon_bin_get_isodesc(const struct mon_reader_bin *rp,
441 unsigned int offset, struct urb *urb, char ev_type, unsigned int ndesc) 463 unsigned int offset, struct urb *urb, char ev_type, unsigned int ndesc)
442{ 464{
@@ -479,6 +501,10 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
479 /* 501 /*
480 * Find the maximum allowable length, then allocate space. 502 * Find the maximum allowable length, then allocate space.
481 */ 503 */
504 urb_length = (ev_type == 'S') ?
505 urb->transfer_buffer_length : urb->actual_length;
506 length = urb_length;
507
482 if (usb_endpoint_xfer_isoc(epd)) { 508 if (usb_endpoint_xfer_isoc(epd)) {
483 if (urb->number_of_packets < 0) { 509 if (urb->number_of_packets < 0) {
484 ndesc = 0; 510 ndesc = 0;
@@ -487,14 +513,16 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
487 } else { 513 } else {
488 ndesc = urb->number_of_packets; 514 ndesc = urb->number_of_packets;
489 } 515 }
516 if (ev_type == 'C' && usb_urb_dir_in(urb))
517 length = mon_bin_collate_isodesc(rp, urb, ndesc);
490 } else { 518 } else {
491 ndesc = 0; 519 ndesc = 0;
492 } 520 }
493 lendesc = ndesc*sizeof(struct mon_bin_isodesc); 521 lendesc = ndesc*sizeof(struct mon_bin_isodesc);
494 522
495 urb_length = (ev_type == 'S') ? 523 /* not an issue unless there's a subtle bug in a HCD somewhere */
496 urb->transfer_buffer_length : urb->actual_length; 524 if (length >= urb->transfer_buffer_length)
497 length = urb_length; 525 length = urb->transfer_buffer_length;
498 526
499 if (length >= rp->b_size/5) 527 if (length >= rp->b_size/5)
500 length = rp->b_size/5; 528 length = rp->b_size/5;