aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/mon/mon_bin.c51
-rw-r--r--drivers/usb/mon/mon_text.c23
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 */
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);
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,
137static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, 138static 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