diff options
Diffstat (limited to 'drivers/usb/mon/mon_bin.c')
-rw-r--r-- | drivers/usb/mon/mon_bin.c | 59 |
1 files changed, 49 insertions, 10 deletions
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index 10f3205798e8..ddf7f9a1b336 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c | |||
@@ -16,6 +16,8 @@ | |||
16 | #include <linux/compat.h> | 16 | #include <linux/compat.h> |
17 | #include <linux/mm.h> | 17 | #include <linux/mm.h> |
18 | #include <linux/smp_lock.h> | 18 | #include <linux/smp_lock.h> |
19 | #include <linux/scatterlist.h> | ||
20 | #include <linux/slab.h> | ||
19 | 21 | ||
20 | #include <asm/uaccess.h> | 22 | #include <asm/uaccess.h> |
21 | 23 | ||
@@ -221,7 +223,7 @@ static void mon_free_buff(struct mon_pgmap *map, int npages); | |||
221 | /* | 223 | /* |
222 | * This is a "chunked memcpy". It does not manipulate any counters. | 224 | * This is a "chunked memcpy". It does not manipulate any counters. |
223 | */ | 225 | */ |
224 | static void mon_copy_to_buff(const struct mon_reader_bin *this, | 226 | static unsigned int mon_copy_to_buff(const struct mon_reader_bin *this, |
225 | unsigned int off, const unsigned char *from, unsigned int length) | 227 | unsigned int off, const unsigned char *from, unsigned int length) |
226 | { | 228 | { |
227 | unsigned int step_len; | 229 | unsigned int step_len; |
@@ -246,6 +248,7 @@ static void mon_copy_to_buff(const struct mon_reader_bin *this, | |||
246 | from += step_len; | 248 | from += step_len; |
247 | length -= step_len; | 249 | length -= step_len; |
248 | } | 250 | } |
251 | return off; | ||
249 | } | 252 | } |
250 | 253 | ||
251 | /* | 254 | /* |
@@ -394,14 +397,44 @@ static inline char mon_bin_get_setup(unsigned char *setupb, | |||
394 | return 0; | 397 | return 0; |
395 | } | 398 | } |
396 | 399 | ||
397 | static char mon_bin_get_data(const struct mon_reader_bin *rp, | 400 | static unsigned int mon_bin_get_data(const struct mon_reader_bin *rp, |
398 | unsigned int offset, struct urb *urb, unsigned int length) | 401 | unsigned int offset, struct urb *urb, unsigned int length, |
402 | char *flag) | ||
399 | { | 403 | { |
404 | int i; | ||
405 | struct scatterlist *sg; | ||
406 | unsigned int this_len; | ||
407 | |||
408 | *flag = 0; | ||
409 | if (urb->num_sgs == 0) { | ||
410 | if (urb->transfer_buffer == NULL) { | ||
411 | *flag = 'Z'; | ||
412 | return length; | ||
413 | } | ||
414 | mon_copy_to_buff(rp, offset, urb->transfer_buffer, length); | ||
415 | length = 0; | ||
400 | 416 | ||
401 | if (urb->transfer_buffer == NULL) | 417 | } else { |
402 | return 'Z'; | 418 | /* If IOMMU coalescing occurred, we cannot trust sg_page */ |
403 | mon_copy_to_buff(rp, offset, urb->transfer_buffer, length); | 419 | if (urb->sg->nents != urb->num_sgs) { |
404 | return 0; | 420 | *flag = 'D'; |
421 | return length; | ||
422 | } | ||
423 | |||
424 | /* Copy up to the first non-addressable segment */ | ||
425 | for_each_sg(urb->sg->sg, sg, urb->num_sgs, i) { | ||
426 | if (length == 0 || PageHighMem(sg_page(sg))) | ||
427 | break; | ||
428 | this_len = min_t(unsigned int, sg->length, length); | ||
429 | offset = mon_copy_to_buff(rp, offset, sg_virt(sg), | ||
430 | this_len); | ||
431 | length -= this_len; | ||
432 | } | ||
433 | if (i == 0) | ||
434 | *flag = 'D'; | ||
435 | } | ||
436 | |||
437 | return length; | ||
405 | } | 438 | } |
406 | 439 | ||
407 | static void mon_bin_get_isodesc(const struct mon_reader_bin *rp, | 440 | static void mon_bin_get_isodesc(const struct mon_reader_bin *rp, |
@@ -428,8 +461,8 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, | |||
428 | char ev_type, int status) | 461 | char ev_type, int status) |
429 | { | 462 | { |
430 | const struct usb_endpoint_descriptor *epd = &urb->ep->desc; | 463 | const struct usb_endpoint_descriptor *epd = &urb->ep->desc; |
431 | unsigned long flags; | ||
432 | struct timeval ts; | 464 | struct timeval ts; |
465 | unsigned long flags; | ||
433 | unsigned int urb_length; | 466 | unsigned int urb_length; |
434 | unsigned int offset; | 467 | unsigned int offset; |
435 | unsigned int length; | 468 | unsigned int length; |
@@ -536,8 +569,9 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, | |||
536 | } | 569 | } |
537 | 570 | ||
538 | if (length != 0) { | 571 | if (length != 0) { |
539 | ep->flag_data = mon_bin_get_data(rp, offset, urb, length); | 572 | length = mon_bin_get_data(rp, offset, urb, length, |
540 | if (ep->flag_data != 0) { /* Yes, it's 0x00, not '0' */ | 573 | &ep->flag_data); |
574 | if (length > 0) { | ||
541 | delta = (ep->len_cap + PKT_ALIGN-1) & ~(PKT_ALIGN-1); | 575 | delta = (ep->len_cap + PKT_ALIGN-1) & ~(PKT_ALIGN-1); |
542 | ep->len_cap -= length; | 576 | ep->len_cap -= length; |
543 | delta -= (ep->len_cap + PKT_ALIGN-1) & ~(PKT_ALIGN-1); | 577 | delta -= (ep->len_cap + PKT_ALIGN-1) & ~(PKT_ALIGN-1); |
@@ -567,10 +601,13 @@ static void mon_bin_complete(void *data, struct urb *urb, int status) | |||
567 | static void mon_bin_error(void *data, struct urb *urb, int error) | 601 | static void mon_bin_error(void *data, struct urb *urb, int error) |
568 | { | 602 | { |
569 | struct mon_reader_bin *rp = data; | 603 | struct mon_reader_bin *rp = data; |
604 | struct timeval ts; | ||
570 | unsigned long flags; | 605 | unsigned long flags; |
571 | unsigned int offset; | 606 | unsigned int offset; |
572 | struct mon_bin_hdr *ep; | 607 | struct mon_bin_hdr *ep; |
573 | 608 | ||
609 | do_gettimeofday(&ts); | ||
610 | |||
574 | spin_lock_irqsave(&rp->b_lock, flags); | 611 | spin_lock_irqsave(&rp->b_lock, flags); |
575 | 612 | ||
576 | offset = mon_buff_area_alloc(rp, PKT_SIZE); | 613 | offset = mon_buff_area_alloc(rp, PKT_SIZE); |
@@ -590,6 +627,8 @@ static void mon_bin_error(void *data, struct urb *urb, int error) | |||
590 | ep->devnum = urb->dev->devnum; | 627 | ep->devnum = urb->dev->devnum; |
591 | ep->busnum = urb->dev->bus->busnum; | 628 | ep->busnum = urb->dev->bus->busnum; |
592 | ep->id = (unsigned long) urb; | 629 | ep->id = (unsigned long) urb; |
630 | ep->ts_sec = ts.tv_sec; | ||
631 | ep->ts_usec = ts.tv_usec; | ||
593 | ep->status = error; | 632 | ep->status = error; |
594 | 633 | ||
595 | ep->flag_setup = '-'; | 634 | ep->flag_setup = '-'; |