diff options
Diffstat (limited to 'drivers/usb/mon/mon_bin.c')
-rw-r--r-- | drivers/usb/mon/mon_bin.c | 51 |
1 files changed, 42 insertions, 9 deletions
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index 10f3205798e8..385ec0520167 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c | |||
@@ -16,6 +16,7 @@ | |||
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> | ||
19 | 20 | ||
20 | #include <asm/uaccess.h> | 21 | #include <asm/uaccess.h> |
21 | 22 | ||
@@ -221,7 +222,7 @@ static void mon_free_buff(struct mon_pgmap *map, int npages); | |||
221 | /* | 222 | /* |
222 | * This is a "chunked memcpy". It does not manipulate any counters. | 223 | * This is a "chunked memcpy". It does not manipulate any counters. |
223 | */ | 224 | */ |
224 | static void mon_copy_to_buff(const struct mon_reader_bin *this, | 225 | static unsigned int mon_copy_to_buff(const struct mon_reader_bin *this, |
225 | unsigned int off, const unsigned char *from, unsigned int length) | 226 | unsigned int off, const unsigned char *from, unsigned int length) |
226 | { | 227 | { |
227 | unsigned int step_len; | 228 | unsigned int step_len; |
@@ -246,6 +247,7 @@ static void mon_copy_to_buff(const struct mon_reader_bin *this, | |||
246 | from += step_len; | 247 | from += step_len; |
247 | length -= step_len; | 248 | length -= step_len; |
248 | } | 249 | } |
250 | return off; | ||
249 | } | 251 | } |
250 | 252 | ||
251 | /* | 253 | /* |
@@ -394,14 +396,44 @@ static inline char mon_bin_get_setup(unsigned char *setupb, | |||
394 | return 0; | 396 | return 0; |
395 | } | 397 | } |
396 | 398 | ||
397 | static char mon_bin_get_data(const struct mon_reader_bin *rp, | 399 | static unsigned int mon_bin_get_data(const struct mon_reader_bin *rp, |
398 | unsigned int offset, struct urb *urb, unsigned int length) | 400 | unsigned int offset, struct urb *urb, unsigned int length, |
401 | char *flag) | ||
399 | { | 402 | { |
403 | int i; | ||
404 | struct scatterlist *sg; | ||
405 | unsigned int this_len; | ||
406 | |||
407 | *flag = 0; | ||
408 | if (urb->num_sgs == 0) { | ||
409 | if (urb->transfer_buffer == NULL) { | ||
410 | *flag = 'Z'; | ||
411 | return length; | ||
412 | } | ||
413 | mon_copy_to_buff(rp, offset, urb->transfer_buffer, length); | ||
414 | length = 0; | ||
400 | 415 | ||
401 | if (urb->transfer_buffer == NULL) | 416 | } else { |
402 | return 'Z'; | 417 | /* If IOMMU coalescing occurred, we cannot trust sg_page */ |
403 | mon_copy_to_buff(rp, offset, urb->transfer_buffer, length); | 418 | if (urb->sg->nents != urb->num_sgs) { |
404 | return 0; | 419 | *flag = 'D'; |
420 | return length; | ||
421 | } | ||
422 | |||
423 | /* Copy up to the first non-addressable segment */ | ||
424 | for_each_sg(urb->sg->sg, sg, urb->num_sgs, i) { | ||
425 | if (length == 0 || PageHighMem(sg_page(sg))) | ||
426 | break; | ||
427 | this_len = min_t(unsigned int, sg->length, length); | ||
428 | offset = mon_copy_to_buff(rp, offset, sg_virt(sg), | ||
429 | this_len); | ||
430 | length -= this_len; | ||
431 | } | ||
432 | if (i == 0) | ||
433 | *flag = 'D'; | ||
434 | } | ||
435 | |||
436 | return length; | ||
405 | } | 437 | } |
406 | 438 | ||
407 | static void mon_bin_get_isodesc(const struct mon_reader_bin *rp, | 439 | static void mon_bin_get_isodesc(const struct mon_reader_bin *rp, |
@@ -536,8 +568,9 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, | |||
536 | } | 568 | } |
537 | 569 | ||
538 | if (length != 0) { | 570 | if (length != 0) { |
539 | ep->flag_data = mon_bin_get_data(rp, offset, urb, length); | 571 | length = mon_bin_get_data(rp, offset, urb, length, |
540 | if (ep->flag_data != 0) { /* Yes, it's 0x00, not '0' */ | 572 | &ep->flag_data); |
573 | if (length > 0) { | ||
541 | delta = (ep->len_cap + PKT_ALIGN-1) & ~(PKT_ALIGN-1); | 574 | delta = (ep->len_cap + PKT_ALIGN-1) & ~(PKT_ALIGN-1); |
542 | ep->len_cap -= length; | 575 | ep->len_cap -= length; |
543 | delta -= (ep->len_cap + PKT_ALIGN-1) & ~(PKT_ALIGN-1); | 576 | delta -= (ep->len_cap + PKT_ALIGN-1) & ~(PKT_ALIGN-1); |