aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/mon/mon_bin.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/mon/mon_bin.c')
-rw-r--r--drivers/usb/mon/mon_bin.c51
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 */
224static void mon_copy_to_buff(const struct mon_reader_bin *this, 225static 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
397static char mon_bin_get_data(const struct mon_reader_bin *rp, 399static 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
407static void mon_bin_get_isodesc(const struct mon_reader_bin *rp, 439static 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);