]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * The USB Monitor, inspired by Dave Harding's USBMon. | |
3 | * | |
4 | * This is a text format reader. | |
5 | */ | |
6 | ||
7 | #include <linux/kernel.h> | |
8 | #include <linux/list.h> | |
9 | #include <linux/usb.h> | |
10 | #include <linux/time.h> | |
11 | #include <asm/uaccess.h> | |
12 | ||
13 | #include "usb_mon.h" | |
14 | ||
15 | /* | |
16 | * No, we do not want arbitrarily long data strings. | |
17 | * Use the binary interface if you want to capture bulk data! | |
18 | */ | |
19 | #define DATA_MAX 32 | |
20 | ||
21 | /* | |
22 | * This limit exists to prevent OOMs when the user process stops reading. | |
23 | */ | |
24 | #define EVENT_MAX 25 | |
25 | ||
26 | #define PRINTF_DFL 120 | |
27 | ||
28 | struct mon_event_text { | |
29 | struct list_head e_link; | |
30 | int type; /* submit, complete, etc. */ | |
31 | unsigned int pipe; /* Pipe */ | |
32 | unsigned long id; /* From pointer, most of the time */ | |
33 | unsigned int tstamp; | |
34 | int length; /* Depends on type: xfer length or act length */ | |
35 | int status; | |
36 | char data_flag; | |
37 | unsigned char data[DATA_MAX]; | |
38 | }; | |
39 | ||
40 | #define SLAB_NAME_SZ 30 | |
41 | struct mon_reader_text { | |
42 | kmem_cache_t *e_slab; | |
43 | int nevents; | |
44 | struct list_head e_list; | |
45 | struct mon_reader r; /* In C, parent class can be placed anywhere */ | |
46 | ||
47 | wait_queue_head_t wait; | |
48 | int printf_size; | |
49 | char *printf_buf; | |
50 | struct semaphore printf_lock; | |
51 | ||
52 | char slab_name[SLAB_NAME_SZ]; | |
53 | }; | |
54 | ||
55 | static void mon_text_ctor(void *, kmem_cache_t *, unsigned long); | |
56 | static void mon_text_dtor(void *, kmem_cache_t *, unsigned long); | |
57 | ||
58 | /* | |
59 | * mon_text_submit | |
60 | * mon_text_complete | |
61 | * | |
62 | * May be called from an interrupt. | |
63 | * | |
64 | * This is called with the whole mon_bus locked, so no additional lock. | |
65 | */ | |
66 | ||
67 | static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, | |
68 | int len, char ev_type) | |
69 | { | |
70 | int pipe = urb->pipe; | |
71 | unsigned char *data; | |
72 | ||
73 | /* | |
74 | * The check to see if it's safe to poke at data has an enormous | |
75 | * number of corner cases, but it seems that the following is | |
76 | * more or less safe. | |
77 | * | |
78 | * We do not even try to look transfer_buffer, because it can | |
79 | * contain non-NULL garbage in case the upper level promised to | |
80 | * set DMA for the HCD. | |
81 | */ | |
82 | if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) | |
83 | return 'D'; | |
84 | ||
85 | if (len <= 0) | |
86 | return 'L'; | |
87 | ||
88 | if ((data = urb->transfer_buffer) == NULL) | |
89 | return 'Z'; /* '0' would be not as pretty. */ | |
90 | ||
91 | /* | |
92 | * Bulk is easy to shortcut reliably. | |
93 | * XXX Control needs setup packet taken. | |
94 | * XXX Other pipe types need consideration. Currently, we overdo it | |
95 | * and collect garbage for them: better more than less. | |
96 | */ | |
97 | if (usb_pipebulk(pipe) || usb_pipecontrol(pipe)) { | |
98 | if (usb_pipein(pipe)) { | |
99 | if (ev_type == 'S') | |
100 | return '<'; | |
101 | } else { | |
102 | if (ev_type == 'C') | |
103 | return '>'; | |
104 | } | |
105 | } | |
106 | ||
107 | if (len >= DATA_MAX) | |
108 | len = DATA_MAX; | |
109 | memcpy(ep->data, urb->transfer_buffer, len); | |
110 | return 0; | |
111 | } | |
112 | ||
113 | static inline unsigned int mon_get_timestamp(void) | |
114 | { | |
115 | struct timeval tval; | |
116 | unsigned int stamp; | |
117 | ||
118 | do_gettimeofday(&tval); | |
119 | stamp = tval.tv_sec & 0xFFFF; /* 2^32 = 4294967296. Limit to 4096s. */ | |
120 | stamp = stamp * 1000000 + tval.tv_usec; | |
121 | return stamp; | |
122 | } | |
123 | ||
124 | static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, | |
125 | char ev_type) | |
126 | { | |
127 | struct mon_event_text *ep; | |
128 | unsigned int stamp; | |
129 | ||
130 | stamp = mon_get_timestamp(); | |
131 | ||
132 | if (rp->nevents >= EVENT_MAX || | |
133 | (ep = kmem_cache_alloc(rp->e_slab, SLAB_ATOMIC)) == NULL) { | |
134 | rp->r.m_bus->cnt_text_lost++; | |
135 | return; | |
136 | } | |
137 | ||
138 | ep->type = ev_type; | |
139 | ep->pipe = urb->pipe; | |
140 | ep->id = (unsigned long) urb; | |
141 | ep->tstamp = stamp; | |
142 | ep->length = (ev_type == 'S') ? | |
143 | urb->transfer_buffer_length : urb->actual_length; | |
144 | /* Collecting status makes debugging sense for submits, too */ | |
145 | ep->status = urb->status; | |
146 | ||
147 | ep->data_flag = mon_text_get_data(ep, urb, ep->length, ev_type); | |
148 | ||
149 | rp->nevents++; | |
150 | list_add_tail(&ep->e_link, &rp->e_list); | |
151 | wake_up(&rp->wait); | |
152 | } | |
153 | ||
154 | static void mon_text_submit(void *data, struct urb *urb) | |
155 | { | |
156 | struct mon_reader_text *rp = data; | |
157 | mon_text_event(rp, urb, 'S'); | |
158 | } | |
159 | ||
160 | static void mon_text_complete(void *data, struct urb *urb) | |
161 | { | |
162 | struct mon_reader_text *rp = data; | |
163 | mon_text_event(rp, urb, 'C'); | |
164 | } | |
165 | ||
166 | /* | |
167 | * Fetch next event from the circular buffer. | |
168 | */ | |
169 | static struct mon_event_text *mon_text_fetch(struct mon_reader_text *rp, | |
170 | struct mon_bus *mbus) | |
171 | { | |
172 | struct list_head *p; | |
173 | unsigned long flags; | |
174 | ||
175 | spin_lock_irqsave(&mbus->lock, flags); | |
176 | if (list_empty(&rp->e_list)) { | |
177 | spin_unlock_irqrestore(&mbus->lock, flags); | |
178 | return NULL; | |
179 | } | |
180 | p = rp->e_list.next; | |
181 | list_del(p); | |
182 | --rp->nevents; | |
183 | spin_unlock_irqrestore(&mbus->lock, flags); | |
184 | return list_entry(p, struct mon_event_text, e_link); | |
185 | } | |
186 | ||
187 | /* | |
188 | */ | |
189 | static int mon_text_open(struct inode *inode, struct file *file) | |
190 | { | |
191 | struct mon_bus *mbus; | |
192 | struct usb_bus *ubus; | |
193 | struct mon_reader_text *rp; | |
194 | int rc; | |
195 | ||
196 | down(&mon_lock); | |
197 | mbus = inode->u.generic_ip; | |
198 | ubus = mbus->u_bus; | |
199 | ||
200 | rp = kmalloc(sizeof(struct mon_reader_text), GFP_KERNEL); | |
201 | if (rp == NULL) { | |
202 | rc = -ENOMEM; | |
203 | goto err_alloc; | |
204 | } | |
205 | memset(rp, 0, sizeof(struct mon_reader_text)); | |
206 | INIT_LIST_HEAD(&rp->e_list); | |
207 | init_waitqueue_head(&rp->wait); | |
208 | init_MUTEX(&rp->printf_lock); | |
209 | ||
210 | rp->printf_size = PRINTF_DFL; | |
211 | rp->printf_buf = kmalloc(rp->printf_size, GFP_KERNEL); | |
212 | if (rp->printf_buf == NULL) { | |
213 | rc = -ENOMEM; | |
214 | goto err_alloc_pr; | |
215 | } | |
216 | ||
217 | rp->r.m_bus = mbus; | |
218 | rp->r.r_data = rp; | |
219 | rp->r.rnf_submit = mon_text_submit; | |
220 | rp->r.rnf_complete = mon_text_complete; | |
221 | ||
222 | snprintf(rp->slab_name, SLAB_NAME_SZ, "mon%dt_%lx", ubus->busnum, | |
223 | (long)rp); | |
224 | rp->e_slab = kmem_cache_create(rp->slab_name, | |
225 | sizeof(struct mon_event_text), sizeof(long), 0, | |
226 | mon_text_ctor, mon_text_dtor); | |
227 | if (rp->e_slab == NULL) { | |
228 | rc = -ENOMEM; | |
229 | goto err_slab; | |
230 | } | |
231 | ||
232 | mon_reader_add(mbus, &rp->r); | |
233 | ||
234 | file->private_data = rp; | |
235 | up(&mon_lock); | |
236 | return 0; | |
237 | ||
238 | // err_busy: | |
239 | // kmem_cache_destroy(rp->e_slab); | |
240 | err_slab: | |
241 | kfree(rp->printf_buf); | |
242 | err_alloc_pr: | |
243 | kfree(rp); | |
244 | err_alloc: | |
245 | up(&mon_lock); | |
246 | return rc; | |
247 | } | |
248 | ||
249 | /* | |
250 | * For simplicity, we read one record in one system call and throw out | |
251 | * what does not fit. This means that the following does not work: | |
252 | * dd if=/dbg/usbmon/0t bs=10 | |
253 | * Also, we do not allow seeks and do not bother advancing the offset. | |
254 | */ | |
255 | static ssize_t mon_text_read(struct file *file, char __user *buf, | |
256 | size_t nbytes, loff_t *ppos) | |
257 | { | |
258 | struct mon_reader_text *rp = file->private_data; | |
259 | struct mon_bus *mbus = rp->r.m_bus; | |
260 | DECLARE_WAITQUEUE(waita, current); | |
261 | struct mon_event_text *ep; | |
262 | int cnt, limit; | |
263 | char *pbuf; | |
264 | char udir, utype; | |
265 | int data_len, i; | |
266 | ||
267 | add_wait_queue(&rp->wait, &waita); | |
268 | set_current_state(TASK_INTERRUPTIBLE); | |
269 | while ((ep = mon_text_fetch(rp, mbus)) == NULL) { | |
270 | if (file->f_flags & O_NONBLOCK) { | |
271 | set_current_state(TASK_RUNNING); | |
272 | remove_wait_queue(&rp->wait, &waita); | |
273 | return -EWOULDBLOCK; /* Same as EAGAIN in Linux */ | |
274 | } | |
275 | /* | |
276 | * We do not count nwaiters, because ->release is supposed | |
277 | * to be called when all openers are gone only. | |
278 | */ | |
279 | schedule(); | |
280 | if (signal_pending(current)) { | |
281 | remove_wait_queue(&rp->wait, &waita); | |
282 | return -EINTR; | |
283 | } | |
284 | set_current_state(TASK_INTERRUPTIBLE); | |
285 | } | |
286 | set_current_state(TASK_RUNNING); | |
287 | remove_wait_queue(&rp->wait, &waita); | |
288 | ||
289 | down(&rp->printf_lock); | |
290 | cnt = 0; | |
291 | pbuf = rp->printf_buf; | |
292 | limit = rp->printf_size; | |
293 | ||
294 | udir = usb_pipein(ep->pipe) ? 'i' : 'o'; | |
295 | switch (usb_pipetype(ep->pipe)) { | |
296 | case PIPE_ISOCHRONOUS: utype = 'Z'; break; | |
297 | case PIPE_INTERRUPT: utype = 'I'; break; | |
298 | case PIPE_CONTROL: utype = 'C'; break; | |
299 | default: /* PIPE_BULK */ utype = 'B'; | |
300 | } | |
301 | cnt += snprintf(pbuf + cnt, limit - cnt, | |
302 | "%lx %u %c %c%c:%03u:%02u %d %d", | |
303 | ep->id, ep->tstamp, ep->type, | |
304 | utype, udir, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe), | |
305 | ep->status, ep->length); | |
306 | ||
307 | if ((data_len = ep->length) > 0) { | |
308 | if (ep->data_flag == 0) { | |
309 | cnt += snprintf(pbuf + cnt, limit - cnt, " ="); | |
310 | if (data_len >= DATA_MAX) | |
311 | data_len = DATA_MAX; | |
312 | for (i = 0; i < data_len; i++) { | |
313 | if (i % 4 == 0) { | |
314 | cnt += snprintf(pbuf + cnt, limit - cnt, | |
315 | " "); | |
316 | } | |
317 | cnt += snprintf(pbuf + cnt, limit - cnt, | |
318 | "%02x", ep->data[i]); | |
319 | } | |
320 | cnt += snprintf(pbuf + cnt, limit - cnt, "\n"); | |
321 | } else { | |
322 | cnt += snprintf(pbuf + cnt, limit - cnt, | |
323 | " %c\n", ep->data_flag); | |
324 | } | |
325 | } else { | |
326 | cnt += snprintf(pbuf + cnt, limit - cnt, "\n"); | |
327 | } | |
328 | ||
329 | if (copy_to_user(buf, rp->printf_buf, cnt)) | |
330 | cnt = -EFAULT; | |
331 | up(&rp->printf_lock); | |
332 | kmem_cache_free(rp->e_slab, ep); | |
333 | return cnt; | |
334 | } | |
335 | ||
336 | static int mon_text_release(struct inode *inode, struct file *file) | |
337 | { | |
338 | struct mon_reader_text *rp = file->private_data; | |
339 | struct mon_bus *mbus; | |
340 | /* unsigned long flags; */ | |
341 | struct list_head *p; | |
342 | struct mon_event_text *ep; | |
343 | ||
344 | down(&mon_lock); | |
345 | mbus = inode->u.generic_ip; | |
346 | ||
347 | if (mbus->nreaders <= 0) { | |
348 | printk(KERN_ERR TAG ": consistency error on close\n"); | |
349 | up(&mon_lock); | |
350 | return 0; | |
351 | } | |
352 | mon_reader_del(mbus, &rp->r); | |
353 | ||
354 | /* | |
355 | * In theory, e_list is protected by mbus->lock. However, | |
356 | * after mon_reader_del has finished, the following is the case: | |
357 | * - we are not on reader list anymore, so new events won't be added; | |
358 | * - whole mbus may be dropped if it was orphaned. | |
359 | * So, we better not touch mbus. | |
360 | */ | |
361 | /* spin_lock_irqsave(&mbus->lock, flags); */ | |
362 | while (!list_empty(&rp->e_list)) { | |
363 | p = rp->e_list.next; | |
364 | ep = list_entry(p, struct mon_event_text, e_link); | |
365 | list_del(p); | |
366 | --rp->nevents; | |
367 | kmem_cache_free(rp->e_slab, ep); | |
368 | } | |
369 | /* spin_unlock_irqrestore(&mbus->lock, flags); */ | |
370 | ||
371 | kmem_cache_destroy(rp->e_slab); | |
372 | kfree(rp->printf_buf); | |
373 | kfree(rp); | |
374 | ||
375 | up(&mon_lock); | |
376 | return 0; | |
377 | } | |
378 | ||
379 | struct file_operations mon_fops_text = { | |
380 | .owner = THIS_MODULE, | |
381 | .open = mon_text_open, | |
382 | .llseek = no_llseek, | |
383 | .read = mon_text_read, | |
384 | /* .write = mon_text_write, */ | |
385 | /* .poll = mon_text_poll, */ | |
386 | /* .ioctl = mon_text_ioctl, */ | |
387 | .release = mon_text_release, | |
388 | }; | |
389 | ||
390 | /* | |
391 | * Slab interface: constructor. | |
392 | */ | |
393 | static void mon_text_ctor(void *mem, kmem_cache_t *slab, unsigned long sflags) | |
394 | { | |
395 | /* | |
396 | * Nothing to initialize. No, really! | |
397 | * So, we fill it with garbage to emulate a reused object. | |
398 | */ | |
399 | memset(mem, 0xe5, sizeof(struct mon_event_text)); | |
400 | } | |
401 | ||
402 | static void mon_text_dtor(void *mem, kmem_cache_t *slab, unsigned long sflags) | |
403 | { | |
404 | ; | |
405 | } |