diff options
-rw-r--r-- | drivers/usb/mon/mon_bin.c | 51 | ||||
-rw-r--r-- | drivers/usb/mon/mon_text.c | 23 |
2 files changed, 62 insertions, 12 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); |
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 9f1a9227ebe6..047568ff223d 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/time.h> | 10 | #include <linux/time.h> |
11 | #include <linux/mutex.h> | 11 | #include <linux/mutex.h> |
12 | #include <linux/debugfs.h> | 12 | #include <linux/debugfs.h> |
13 | #include <linux/scatterlist.h> | ||
13 | #include <asm/uaccess.h> | 14 | #include <asm/uaccess.h> |
14 | 15 | ||
15 | #include "usb_mon.h" | 16 | #include "usb_mon.h" |
@@ -137,6 +138,8 @@ static inline char mon_text_get_setup(struct mon_event_text *ep, | |||
137 | static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, | 138 | static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, |
138 | int len, char ev_type, struct mon_bus *mbus) | 139 | int len, char ev_type, struct mon_bus *mbus) |
139 | { | 140 | { |
141 | void *src; | ||
142 | |||
140 | if (len <= 0) | 143 | if (len <= 0) |
141 | return 'L'; | 144 | return 'L'; |
142 | if (len >= DATA_MAX) | 145 | if (len >= DATA_MAX) |
@@ -150,10 +153,24 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, | |||
150 | return '>'; | 153 | return '>'; |
151 | } | 154 | } |
152 | 155 | ||
153 | if (urb->transfer_buffer == NULL) | 156 | if (urb->num_sgs == 0) { |
154 | return 'Z'; /* '0' would be not as pretty. */ | 157 | src = urb->transfer_buffer; |
158 | if (src == NULL) | ||
159 | return 'Z'; /* '0' would be not as pretty. */ | ||
160 | } else { | ||
161 | struct scatterlist *sg = urb->sg->sg; | ||
162 | |||
163 | /* If IOMMU coalescing occurred, we cannot trust sg_page */ | ||
164 | if (urb->sg->nents != urb->num_sgs || | ||
165 | PageHighMem(sg_page(sg))) | ||
166 | return 'D'; | ||
167 | |||
168 | /* For the text interface we copy only the first sg buffer */ | ||
169 | len = min_t(int, sg->length, len); | ||
170 | src = sg_virt(sg); | ||
171 | } | ||
155 | 172 | ||
156 | memcpy(ep->data, urb->transfer_buffer, len); | 173 | memcpy(ep->data, src, len); |
157 | return 0; | 174 | return 0; |
158 | } | 175 | } |
159 | 176 | ||