diff options
Diffstat (limited to 'drivers/usb/mon/mon_text.c')
-rw-r--r-- | drivers/usb/mon/mon_text.c | 30 |
1 files changed, 24 insertions, 6 deletions
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 9f1a9227ebe6..4d0be130f49b 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c | |||
@@ -7,9 +7,11 @@ | |||
7 | #include <linux/kernel.h> | 7 | #include <linux/kernel.h> |
8 | #include <linux/list.h> | 8 | #include <linux/list.h> |
9 | #include <linux/usb.h> | 9 | #include <linux/usb.h> |
10 | #include <linux/slab.h> | ||
10 | #include <linux/time.h> | 11 | #include <linux/time.h> |
11 | #include <linux/mutex.h> | 12 | #include <linux/mutex.h> |
12 | #include <linux/debugfs.h> | 13 | #include <linux/debugfs.h> |
14 | #include <linux/scatterlist.h> | ||
13 | #include <asm/uaccess.h> | 15 | #include <asm/uaccess.h> |
14 | 16 | ||
15 | #include "usb_mon.h" | 17 | #include "usb_mon.h" |
@@ -137,6 +139,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, | 139 | 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) | 140 | int len, char ev_type, struct mon_bus *mbus) |
139 | { | 141 | { |
142 | void *src; | ||
143 | |||
140 | if (len <= 0) | 144 | if (len <= 0) |
141 | return 'L'; | 145 | return 'L'; |
142 | if (len >= DATA_MAX) | 146 | if (len >= DATA_MAX) |
@@ -150,10 +154,24 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, | |||
150 | return '>'; | 154 | return '>'; |
151 | } | 155 | } |
152 | 156 | ||
153 | if (urb->transfer_buffer == NULL) | 157 | if (urb->num_sgs == 0) { |
154 | return 'Z'; /* '0' would be not as pretty. */ | 158 | src = urb->transfer_buffer; |
159 | if (src == NULL) | ||
160 | return 'Z'; /* '0' would be not as pretty. */ | ||
161 | } else { | ||
162 | struct scatterlist *sg = urb->sg->sg; | ||
163 | |||
164 | /* If IOMMU coalescing occurred, we cannot trust sg_page */ | ||
165 | if (urb->sg->nents != urb->num_sgs || | ||
166 | PageHighMem(sg_page(sg))) | ||
167 | return 'D'; | ||
155 | 168 | ||
156 | memcpy(ep->data, urb->transfer_buffer, len); | 169 | /* For the text interface we copy only the first sg buffer */ |
170 | len = min_t(int, sg->length, len); | ||
171 | src = sg_virt(sg); | ||
172 | } | ||
173 | |||
174 | memcpy(ep->data, src, len); | ||
157 | return 0; | 175 | return 0; |
158 | } | 176 | } |
159 | 177 | ||
@@ -163,7 +181,7 @@ static inline unsigned int mon_get_timestamp(void) | |||
163 | unsigned int stamp; | 181 | unsigned int stamp; |
164 | 182 | ||
165 | do_gettimeofday(&tval); | 183 | do_gettimeofday(&tval); |
166 | stamp = tval.tv_sec & 0xFFFF; /* 2^32 = 4294967296. Limit to 4096s. */ | 184 | stamp = tval.tv_sec & 0xFFF; /* 2^32 = 4294967296. Limit to 4096s. */ |
167 | stamp = stamp * 1000000 + tval.tv_usec; | 185 | stamp = stamp * 1000000 + tval.tv_usec; |
168 | return stamp; | 186 | return stamp; |
169 | } | 187 | } |
@@ -256,12 +274,12 @@ static void mon_text_error(void *data, struct urb *urb, int error) | |||
256 | 274 | ||
257 | ep->type = 'E'; | 275 | ep->type = 'E'; |
258 | ep->id = (unsigned long) urb; | 276 | ep->id = (unsigned long) urb; |
259 | ep->busnum = 0; | 277 | ep->busnum = urb->dev->bus->busnum; |
260 | ep->devnum = urb->dev->devnum; | 278 | ep->devnum = urb->dev->devnum; |
261 | ep->epnum = usb_endpoint_num(&urb->ep->desc); | 279 | ep->epnum = usb_endpoint_num(&urb->ep->desc); |
262 | ep->xfertype = usb_endpoint_type(&urb->ep->desc); | 280 | ep->xfertype = usb_endpoint_type(&urb->ep->desc); |
263 | ep->is_in = usb_urb_dir_in(urb); | 281 | ep->is_in = usb_urb_dir_in(urb); |
264 | ep->tstamp = 0; | 282 | ep->tstamp = mon_get_timestamp(); |
265 | ep->length = 0; | 283 | ep->length = 0; |
266 | ep->status = error; | 284 | ep->status = error; |
267 | 285 | ||