aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/mon
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/usb/mon
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/usb/mon')
-rw-r--r--drivers/usb/mon/Kconfig22
-rw-r--r--drivers/usb/mon/Makefile7
-rw-r--r--drivers/usb/mon/mon_main.c377
-rw-r--r--drivers/usb/mon/mon_stat.c74
-rw-r--r--drivers/usb/mon/mon_text.c405
-rw-r--r--drivers/usb/mon/usb_mon.h51
6 files changed, 936 insertions, 0 deletions
diff --git a/drivers/usb/mon/Kconfig b/drivers/usb/mon/Kconfig
new file mode 100644
index 000000000000..4e6152aa5f19
--- /dev/null
+++ b/drivers/usb/mon/Kconfig
@@ -0,0 +1,22 @@
1#
2# USB Monitor configuration
3#
4
5# In normal life, it makes little sense to have usbmon as a module, and in fact
6# it is harmful, because there is no way to autoload the module.
7# The 'm' option is allowed for hackers who debug the usbmon itself,
8# and for those who have usbcore as a module.
9config USB_MON
10 tristate "USB Monitor"
11 depends on USB
12 default y
13 help
14 If you say Y here, a component which captures the USB traffic
15 between peripheral-specific drivers and HC drivers will be built.
16 The USB_MON is similar in spirit and may be compatible with Dave
17 Harding's USBMon.
18
19 This is somewhat experimental at this time, but it should be safe,
20 as long as you aren't building this as a module and then removing it.
21
22 If unsure, say Y. Do not say M.
diff --git a/drivers/usb/mon/Makefile b/drivers/usb/mon/Makefile
new file mode 100644
index 000000000000..3cff8d444bb1
--- /dev/null
+++ b/drivers/usb/mon/Makefile
@@ -0,0 +1,7 @@
1#
2# Makefile for USB Core files and filesystem
3#
4
5usbmon-objs := mon_main.o mon_stat.o mon_text.o
6
7obj-$(CONFIG_USB_MON) += usbmon.o
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
new file mode 100644
index 000000000000..aa9d00808e4e
--- /dev/null
+++ b/drivers/usb/mon/mon_main.c
@@ -0,0 +1,377 @@
1/*
2 * The USB Monitor, inspired by Dave Harding's USBMon.
3 *
4 * mon_main.c: Main file, module initiation and exit, registrations, etc.
5 */
6
7#include <linux/kernel.h>
8#include <linux/module.h>
9#include <linux/usb.h>
10#include <linux/debugfs.h>
11#include <linux/smp_lock.h>
12
13#include "usb_mon.h"
14#include "../core/hcd.h"
15
16static void mon_submit(struct usb_bus *ubus, struct urb *urb);
17static void mon_complete(struct usb_bus *ubus, struct urb *urb);
18static void mon_stop(struct mon_bus *mbus);
19static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus);
20static void mon_bus_drop(struct kref *r);
21static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus);
22
23DECLARE_MUTEX(mon_lock);
24
25static struct dentry *mon_dir; /* /dbg/usbmon */
26static LIST_HEAD(mon_buses); /* All buses we know: struct mon_bus */
27
28/*
29 * Link a reader into the bus.
30 *
31 * This must be called with mon_lock taken because of mbus->ref.
32 */
33void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r)
34{
35 unsigned long flags;
36 struct usb_bus *ubus;
37
38 spin_lock_irqsave(&mbus->lock, flags);
39 if (mbus->nreaders == 0) {
40 ubus = mbus->u_bus;
41 if (ubus->monitored) {
42 /*
43 * Something is really broken, refuse to go on and
44 * possibly corrupt ops pointers or worse.
45 */
46 printk(KERN_ERR TAG ": bus %d is already monitored\n",
47 ubus->busnum);
48 spin_unlock_irqrestore(&mbus->lock, flags);
49 return;
50 }
51 ubus->monitored = 1;
52 }
53 mbus->nreaders++;
54 list_add_tail(&r->r_link, &mbus->r_list);
55 spin_unlock_irqrestore(&mbus->lock, flags);
56
57 kref_get(&mbus->ref);
58}
59
60/*
61 * Unlink reader from the bus.
62 *
63 * This is called with mon_lock taken, so we can decrement mbus->ref.
64 */
65void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r)
66{
67 unsigned long flags;
68
69 spin_lock_irqsave(&mbus->lock, flags);
70 list_del(&r->r_link);
71 --mbus->nreaders;
72 if (mbus->nreaders == 0)
73 mon_stop(mbus);
74 spin_unlock_irqrestore(&mbus->lock, flags);
75
76 kref_put(&mbus->ref, mon_bus_drop);
77}
78
79/*
80 */
81static void mon_submit(struct usb_bus *ubus, struct urb *urb)
82{
83 struct mon_bus *mbus;
84 unsigned long flags;
85 struct list_head *pos;
86 struct mon_reader *r;
87
88 mbus = ubus->mon_bus;
89 if (mbus == NULL)
90 goto out_unlocked;
91
92 spin_lock_irqsave(&mbus->lock, flags);
93 if (mbus->nreaders == 0)
94 goto out_locked;
95
96 list_for_each (pos, &mbus->r_list) {
97 r = list_entry(pos, struct mon_reader, r_link);
98 r->rnf_submit(r->r_data, urb);
99 }
100
101 spin_unlock_irqrestore(&mbus->lock, flags);
102 return;
103
104out_locked:
105 spin_unlock_irqrestore(&mbus->lock, flags);
106out_unlocked:
107 return;
108}
109
110/*
111 */
112static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int err)
113{
114 struct mon_bus *mbus;
115
116 mbus = ubus->mon_bus;
117 if (mbus == NULL)
118 goto out_unlocked;
119
120 /*
121 * XXX Capture the error code and the 'E' event.
122 */
123
124 return;
125
126out_unlocked:
127 return;
128}
129
130/*
131 */
132static void mon_complete(struct usb_bus *ubus, struct urb *urb)
133{
134 struct mon_bus *mbus;
135 unsigned long flags;
136 struct list_head *pos;
137 struct mon_reader *r;
138
139 mbus = ubus->mon_bus;
140 if (mbus == NULL) {
141 /*
142 * This should not happen.
143 * At this point we do not even know the bus number...
144 */
145 printk(KERN_ERR TAG ": Null mon bus in URB, pipe 0x%x\n",
146 urb->pipe);
147 return;
148 }
149
150 spin_lock_irqsave(&mbus->lock, flags);
151 list_for_each (pos, &mbus->r_list) {
152 r = list_entry(pos, struct mon_reader, r_link);
153 r->rnf_complete(r->r_data, urb);
154 }
155 spin_unlock_irqrestore(&mbus->lock, flags);
156}
157
158/* int (*unlink_urb) (struct urb *urb, int status); */
159
160/*
161 * Stop monitoring.
162 * Obviously this must be well locked, so no need to play with mb's.
163 */
164static void mon_stop(struct mon_bus *mbus)
165{
166 struct usb_bus *ubus = mbus->u_bus;
167
168 /*
169 * A stop can be called for a dissolved mon_bus in case of
170 * a reader staying across an rmmod foo_hcd.
171 */
172 if (ubus != NULL) {
173 ubus->monitored = 0;
174 mb();
175 }
176}
177
178/*
179 * Add a USB bus (usually by a modprobe foo-hcd)
180 *
181 * This does not return an error code because the core cannot care less
182 * if monitoring is not established.
183 */
184static void mon_bus_add(struct usb_bus *ubus)
185{
186 mon_bus_init(mon_dir, ubus);
187}
188
189/*
190 * Remove a USB bus (either from rmmod foo-hcd or from a hot-remove event).
191 */
192static void mon_bus_remove(struct usb_bus *ubus)
193{
194 struct mon_bus *mbus = ubus->mon_bus;
195
196 down(&mon_lock);
197 list_del(&mbus->bus_link);
198 debugfs_remove(mbus->dent_t);
199 debugfs_remove(mbus->dent_s);
200
201 mon_dissolve(mbus, ubus);
202 kref_put(&mbus->ref, mon_bus_drop);
203 up(&mon_lock);
204}
205
206/*
207 * Ops
208 */
209static struct usb_mon_operations mon_ops_0 = {
210 .urb_submit = mon_submit,
211 .urb_submit_error = mon_submit_error,
212 .urb_complete = mon_complete,
213 .bus_add = mon_bus_add,
214 .bus_remove = mon_bus_remove,
215};
216
217/*
218 * Tear usb_bus and mon_bus apart.
219 */
220static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus)
221{
222
223 /*
224 * Never happens, but...
225 */
226 if (ubus->monitored) {
227 printk(KERN_ERR TAG ": bus %d is dissolved while monitored\n",
228 ubus->busnum);
229 ubus->monitored = 0;
230 mb();
231 }
232
233 ubus->mon_bus = NULL;
234 mbus->u_bus = NULL;
235 mb();
236 // usb_bus_put(ubus);
237}
238
239/*
240 */
241static void mon_bus_drop(struct kref *r)
242{
243 struct mon_bus *mbus = container_of(r, struct mon_bus, ref);
244 kfree(mbus);
245}
246
247/*
248 * Initialize a bus for us:
249 * - allocate mon_bus
250 * - refcount USB bus struct
251 * - link
252 */
253static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus)
254{
255 struct dentry *d;
256 struct mon_bus *mbus;
257 enum { NAMESZ = 10 };
258 char name[NAMESZ];
259 int rc;
260
261 if ((mbus = kmalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL)
262 goto err_alloc;
263 memset(mbus, 0, sizeof(struct mon_bus));
264 kref_init(&mbus->ref);
265 spin_lock_init(&mbus->lock);
266 INIT_LIST_HEAD(&mbus->r_list);
267
268 /*
269 * This usb_bus_get here is superfluous, because we receive
270 * a notification if usb_bus is about to be removed.
271 */
272 // usb_bus_get(ubus);
273 mbus->u_bus = ubus;
274 ubus->mon_bus = mbus;
275
276 rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
277 if (rc <= 0 || rc >= NAMESZ)
278 goto err_print_t;
279 d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_text);
280 if (d == NULL)
281 goto err_create_t;
282 mbus->dent_t = d;
283
284 rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
285 if (rc <= 0 || rc >= NAMESZ)
286 goto err_print_s;
287 d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_stat);
288 if (d == NULL)
289 goto err_create_s;
290 mbus->dent_s = d;
291
292 down(&mon_lock);
293 list_add_tail(&mbus->bus_link, &mon_buses);
294 up(&mon_lock);
295 return;
296
297err_create_s:
298err_print_s:
299 debugfs_remove(mbus->dent_t);
300err_create_t:
301err_print_t:
302 kfree(mbus);
303err_alloc:
304 return;
305}
306
307static int __init mon_init(void)
308{
309 struct usb_bus *ubus;
310 struct dentry *mondir;
311
312 mondir = debugfs_create_dir("usbmon", NULL);
313 if (IS_ERR(mondir)) {
314 printk(KERN_NOTICE TAG ": debugs is not available\n");
315 return -ENODEV;
316 }
317 if (mondir == NULL) {
318 printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
319 return -ENODEV;
320 }
321 mon_dir = mondir;
322
323 if (usb_mon_register(&mon_ops_0) != 0) {
324 printk(KERN_NOTICE TAG ": unable to register with the core\n");
325 debugfs_remove(mondir);
326 return -ENODEV;
327 }
328 // MOD_INC_USE_COUNT(which_module?);
329
330 down(&usb_bus_list_lock);
331 list_for_each_entry (ubus, &usb_bus_list, bus_list) {
332 mon_bus_init(mondir, ubus);
333 }
334 up(&usb_bus_list_lock);
335 return 0;
336}
337
338static void __exit mon_exit(void)
339{
340 struct mon_bus *mbus;
341 struct list_head *p;
342
343 usb_mon_deregister();
344
345 down(&mon_lock);
346 while (!list_empty(&mon_buses)) {
347 p = mon_buses.next;
348 mbus = list_entry(p, struct mon_bus, bus_link);
349 list_del(p);
350
351 debugfs_remove(mbus->dent_t);
352 debugfs_remove(mbus->dent_s);
353
354 /*
355 * This never happens, because the open/close paths in
356 * file level maintain module use counters and so rmmod fails
357 * before reaching here. However, better be safe...
358 */
359 if (mbus->nreaders) {
360 printk(KERN_ERR TAG
361 ": Outstanding opens (%d) on usb%d, leaking...\n",
362 mbus->nreaders, mbus->u_bus->busnum);
363 atomic_set(&mbus->ref.refcount, 2); /* Force leak */
364 }
365
366 mon_dissolve(mbus, mbus->u_bus);
367 kref_put(&mbus->ref, mon_bus_drop);
368 }
369 up(&mon_lock);
370
371 debugfs_remove(mon_dir);
372}
373
374module_init(mon_init);
375module_exit(mon_exit);
376
377MODULE_LICENSE("GPL");
diff --git a/drivers/usb/mon/mon_stat.c b/drivers/usb/mon/mon_stat.c
new file mode 100644
index 000000000000..6e4b165d070a
--- /dev/null
+++ b/drivers/usb/mon/mon_stat.c
@@ -0,0 +1,74 @@
1/*
2 * The USB Monitor, inspired by Dave Harding's USBMon.
3 *
4 * This is the 's' or 'stat' reader which debugs usbmon itself.
5 * Note that this code blows through locks, so make sure that
6 * /dbg/usbmon/0s is well protected from non-root users.
7 *
8 */
9
10#include <linux/kernel.h>
11#include <linux/usb.h>
12#include <asm/uaccess.h>
13
14#include "usb_mon.h"
15
16#define STAT_BUF_SIZE 80
17
18struct snap {
19 int slen;
20 char str[STAT_BUF_SIZE];
21};
22
23static int mon_stat_open(struct inode *inode, struct file *file)
24{
25 struct mon_bus *mbus;
26 struct snap *sp;
27
28 if ((sp = kmalloc(sizeof(struct snap), GFP_KERNEL)) == NULL)
29 return -ENOMEM;
30
31 mbus = inode->u.generic_ip;
32
33 sp->slen = snprintf(sp->str, STAT_BUF_SIZE,
34 "nreaders %d text_lost %u\n",
35 mbus->nreaders, mbus->cnt_text_lost);
36
37 file->private_data = sp;
38 return 0;
39}
40
41static ssize_t mon_stat_read(struct file *file, char __user *buf,
42 size_t nbytes, loff_t *ppos)
43{
44 struct snap *sp = file->private_data;
45 loff_t pos = *ppos;
46 int cnt;
47
48 if (pos < 0 || pos >= sp->slen)
49 return 0;
50 if (nbytes == 0)
51 return 0;
52 if ((cnt = sp->slen - pos) > nbytes)
53 cnt = nbytes;
54 if (copy_to_user(buf, sp->str + pos, cnt))
55 return -EFAULT;
56 *ppos = pos + cnt;
57 return cnt;
58}
59
60static int mon_stat_release(struct inode *inode, struct file *file)
61{
62 return 0;
63}
64
65struct file_operations mon_fops_stat = {
66 .owner = THIS_MODULE,
67 .open = mon_stat_open,
68 .llseek = no_llseek,
69 .read = mon_stat_read,
70 /* .write = mon_stat_write, */
71 /* .poll = mon_stat_poll, */
72 /* .ioctl = mon_stat_ioctl, */
73 .release = mon_stat_release,
74};
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
new file mode 100644
index 000000000000..755a4570477f
--- /dev/null
+++ b/drivers/usb/mon/mon_text.c
@@ -0,0 +1,405 @@
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
28struct 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
41struct 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
55static void mon_text_ctor(void *, kmem_cache_t *, unsigned long);
56static 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
67static 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
113static 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
124static 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
154static 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
160static 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 */
169static 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 */
189static 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);
240err_slab:
241 kfree(rp->printf_buf);
242err_alloc_pr:
243 kfree(rp);
244err_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 */
255static 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
336static 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
379struct 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 */
393static 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
402static void mon_text_dtor(void *mem, kmem_cache_t *slab, unsigned long sflags)
403{
404 ;
405}
diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h
new file mode 100644
index 000000000000..ed35c18a5c44
--- /dev/null
+++ b/drivers/usb/mon/usb_mon.h
@@ -0,0 +1,51 @@
1/*
2 * The USB Monitor, inspired by Dave Harding's USBMon.
3 */
4
5#ifndef __USB_MON_H
6#define __USB_MON_H
7
8#include <linux/list.h>
9#include <linux/slab.h>
10#include <linux/kref.h>
11/* #include <linux/usb.h> */ /* We use struct pointers only in this header */
12
13#define TAG "usbmon"
14
15struct mon_bus {
16 struct list_head bus_link;
17 spinlock_t lock;
18 struct dentry *dent_s; /* Debugging file */
19 struct dentry *dent_t; /* Text interface file */
20 struct usb_bus *u_bus;
21
22 /* Ref */
23 int nreaders; /* Under mon_lock AND mbus->lock */
24 struct list_head r_list; /* Chain of readers (usually one) */
25 struct kref ref; /* Under mon_lock */
26
27 /* Stats */
28 unsigned int cnt_text_lost;
29};
30
31/*
32 * An instance of a process which opened a file (but can fork later)
33 */
34struct mon_reader {
35 struct list_head r_link;
36 struct mon_bus *m_bus;
37 void *r_data; /* Use container_of instead? */
38
39 void (*rnf_submit)(void *data, struct urb *urb);
40 void (*rnf_complete)(void *data, struct urb *urb);
41};
42
43void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
44void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r);
45
46extern struct semaphore mon_lock;
47
48extern struct file_operations mon_fops_text;
49extern struct file_operations mon_fops_stat;
50
51#endif /* __USB_MON_H */