blob: 86db92b4915b550a08fd6acd31861b647c376c74 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * The USB Monitor, inspired by Dave Harding's USBMon.
3 *
4 * mon_main.c: Main file, module initiation and exit, registrations, etc.
Pete Zaitcevda5ca002005-08-16 15:16:46 -07005 *
6 * Copyright (C) 2005 Pete Zaitcev (zaitcev@redhat.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 */
8
9#include <linux/kernel.h>
10#include <linux/module.h>
11#include <linux/usb.h>
12#include <linux/debugfs.h>
13#include <linux/smp_lock.h>
Greg Kroah-Hartman72adaa92005-06-20 21:15:16 -070014#include <linux/notifier.h>
Arjan van de Ven4186ecf2006-01-11 15:55:29 +010015#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016
17#include "usb_mon.h"
18#include "../core/hcd.h"
19
20static void mon_submit(struct usb_bus *ubus, struct urb *urb);
21static void mon_complete(struct usb_bus *ubus, struct urb *urb);
22static void mon_stop(struct mon_bus *mbus);
23static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus);
24static void mon_bus_drop(struct kref *r);
25static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus);
26
Arjan van de Ven4186ecf2006-01-11 15:55:29 +010027DEFINE_MUTEX(mon_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
29static struct dentry *mon_dir; /* /dbg/usbmon */
30static LIST_HEAD(mon_buses); /* All buses we know: struct mon_bus */
31
32/*
33 * Link a reader into the bus.
34 *
35 * This must be called with mon_lock taken because of mbus->ref.
36 */
37void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r)
38{
39 unsigned long flags;
40 struct usb_bus *ubus;
41
42 spin_lock_irqsave(&mbus->lock, flags);
43 if (mbus->nreaders == 0) {
44 ubus = mbus->u_bus;
45 if (ubus->monitored) {
46 /*
47 * Something is really broken, refuse to go on and
48 * possibly corrupt ops pointers or worse.
49 */
50 printk(KERN_ERR TAG ": bus %d is already monitored\n",
51 ubus->busnum);
52 spin_unlock_irqrestore(&mbus->lock, flags);
53 return;
54 }
55 ubus->monitored = 1;
56 }
57 mbus->nreaders++;
58 list_add_tail(&r->r_link, &mbus->r_list);
59 spin_unlock_irqrestore(&mbus->lock, flags);
60
61 kref_get(&mbus->ref);
62}
63
64/*
65 * Unlink reader from the bus.
66 *
67 * This is called with mon_lock taken, so we can decrement mbus->ref.
68 */
69void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r)
70{
71 unsigned long flags;
72
73 spin_lock_irqsave(&mbus->lock, flags);
74 list_del(&r->r_link);
75 --mbus->nreaders;
76 if (mbus->nreaders == 0)
77 mon_stop(mbus);
78 spin_unlock_irqrestore(&mbus->lock, flags);
79
80 kref_put(&mbus->ref, mon_bus_drop);
81}
82
83/*
84 */
85static void mon_submit(struct usb_bus *ubus, struct urb *urb)
86{
87 struct mon_bus *mbus;
88 unsigned long flags;
89 struct list_head *pos;
90 struct mon_reader *r;
91
92 mbus = ubus->mon_bus;
93 if (mbus == NULL)
94 goto out_unlocked;
95
96 spin_lock_irqsave(&mbus->lock, flags);
97 if (mbus->nreaders == 0)
98 goto out_locked;
99
Pete Zaitcev5b1c6742006-06-09 20:10:10 -0700100 mbus->cnt_events++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 list_for_each (pos, &mbus->r_list) {
102 r = list_entry(pos, struct mon_reader, r_link);
103 r->rnf_submit(r->r_data, urb);
104 }
105
106 spin_unlock_irqrestore(&mbus->lock, flags);
107 return;
108
109out_locked:
110 spin_unlock_irqrestore(&mbus->lock, flags);
111out_unlocked:
112 return;
113}
114
115/*
116 */
117static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int err)
118{
119 struct mon_bus *mbus;
120
121 mbus = ubus->mon_bus;
122 if (mbus == NULL)
123 goto out_unlocked;
124
125 /*
126 * XXX Capture the error code and the 'E' event.
127 */
128
129 return;
130
131out_unlocked:
132 return;
133}
134
135/*
136 */
137static void mon_complete(struct usb_bus *ubus, struct urb *urb)
138{
139 struct mon_bus *mbus;
140 unsigned long flags;
141 struct list_head *pos;
142 struct mon_reader *r;
143
144 mbus = ubus->mon_bus;
145 if (mbus == NULL) {
146 /*
147 * This should not happen.
148 * At this point we do not even know the bus number...
149 */
150 printk(KERN_ERR TAG ": Null mon bus in URB, pipe 0x%x\n",
151 urb->pipe);
152 return;
153 }
154
155 spin_lock_irqsave(&mbus->lock, flags);
Pete Zaitcev5b1c6742006-06-09 20:10:10 -0700156 mbus->cnt_events++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 list_for_each (pos, &mbus->r_list) {
158 r = list_entry(pos, struct mon_reader, r_link);
159 r->rnf_complete(r->r_data, urb);
160 }
161 spin_unlock_irqrestore(&mbus->lock, flags);
162}
163
164/* int (*unlink_urb) (struct urb *urb, int status); */
165
166/*
167 * Stop monitoring.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 */
169static void mon_stop(struct mon_bus *mbus)
170{
171 struct usb_bus *ubus = mbus->u_bus;
172
173 /*
174 * A stop can be called for a dissolved mon_bus in case of
175 * a reader staying across an rmmod foo_hcd.
176 */
177 if (ubus != NULL) {
178 ubus->monitored = 0;
179 mb();
180 }
181}
182
183/*
184 * Add a USB bus (usually by a modprobe foo-hcd)
185 *
186 * This does not return an error code because the core cannot care less
187 * if monitoring is not established.
188 */
189static void mon_bus_add(struct usb_bus *ubus)
190{
191 mon_bus_init(mon_dir, ubus);
192}
193
194/*
195 * Remove a USB bus (either from rmmod foo-hcd or from a hot-remove event).
196 */
197static void mon_bus_remove(struct usb_bus *ubus)
198{
199 struct mon_bus *mbus = ubus->mon_bus;
200
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100201 mutex_lock(&mon_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 list_del(&mbus->bus_link);
203 debugfs_remove(mbus->dent_t);
204 debugfs_remove(mbus->dent_s);
205
206 mon_dissolve(mbus, ubus);
207 kref_put(&mbus->ref, mon_bus_drop);
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100208 mutex_unlock(&mon_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209}
210
Greg Kroah-Hartman72adaa92005-06-20 21:15:16 -0700211static int mon_notify(struct notifier_block *self, unsigned long action,
212 void *dev)
213{
214 switch (action) {
215 case USB_BUS_ADD:
216 mon_bus_add(dev);
217 break;
218 case USB_BUS_REMOVE:
219 mon_bus_remove(dev);
220 }
221 return NOTIFY_OK;
222}
223
224static struct notifier_block mon_nb = {
225 .notifier_call = mon_notify,
226};
227
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228/*
229 * Ops
230 */
231static struct usb_mon_operations mon_ops_0 = {
232 .urb_submit = mon_submit,
233 .urb_submit_error = mon_submit_error,
234 .urb_complete = mon_complete,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235};
236
237/*
238 * Tear usb_bus and mon_bus apart.
239 */
240static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus)
241{
242
243 /*
244 * Never happens, but...
245 */
246 if (ubus->monitored) {
247 printk(KERN_ERR TAG ": bus %d is dissolved while monitored\n",
248 ubus->busnum);
249 ubus->monitored = 0;
250 mb();
251 }
252
253 ubus->mon_bus = NULL;
254 mbus->u_bus = NULL;
255 mb();
256 // usb_bus_put(ubus);
257}
258
259/*
260 */
261static void mon_bus_drop(struct kref *r)
262{
263 struct mon_bus *mbus = container_of(r, struct mon_bus, ref);
264 kfree(mbus);
265}
266
267/*
268 * Initialize a bus for us:
269 * - allocate mon_bus
270 * - refcount USB bus struct
271 * - link
272 */
273static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus)
274{
275 struct dentry *d;
276 struct mon_bus *mbus;
277 enum { NAMESZ = 10 };
278 char name[NAMESZ];
279 int rc;
280
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100281 if ((mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 goto err_alloc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 kref_init(&mbus->ref);
284 spin_lock_init(&mbus->lock);
285 INIT_LIST_HEAD(&mbus->r_list);
286
287 /*
288 * This usb_bus_get here is superfluous, because we receive
289 * a notification if usb_bus is about to be removed.
290 */
291 // usb_bus_get(ubus);
292 mbus->u_bus = ubus;
293 ubus->mon_bus = mbus;
294
295 rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
296 if (rc <= 0 || rc >= NAMESZ)
297 goto err_print_t;
298 d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_text);
299 if (d == NULL)
300 goto err_create_t;
301 mbus->dent_t = d;
302
303 rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
304 if (rc <= 0 || rc >= NAMESZ)
305 goto err_print_s;
306 d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_stat);
307 if (d == NULL)
308 goto err_create_s;
309 mbus->dent_s = d;
310
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100311 mutex_lock(&mon_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 list_add_tail(&mbus->bus_link, &mon_buses);
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100313 mutex_unlock(&mon_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 return;
315
316err_create_s:
317err_print_s:
318 debugfs_remove(mbus->dent_t);
319err_create_t:
320err_print_t:
321 kfree(mbus);
322err_alloc:
323 return;
324}
325
326static int __init mon_init(void)
327{
328 struct usb_bus *ubus;
329 struct dentry *mondir;
330
331 mondir = debugfs_create_dir("usbmon", NULL);
332 if (IS_ERR(mondir)) {
Pete Zaitcevda5ca002005-08-16 15:16:46 -0700333 printk(KERN_NOTICE TAG ": debugfs is not available\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 return -ENODEV;
335 }
336 if (mondir == NULL) {
337 printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
338 return -ENODEV;
339 }
340 mon_dir = mondir;
341
342 if (usb_mon_register(&mon_ops_0) != 0) {
343 printk(KERN_NOTICE TAG ": unable to register with the core\n");
344 debugfs_remove(mondir);
345 return -ENODEV;
346 }
347 // MOD_INC_USE_COUNT(which_module?);
348
Greg Kroah-Hartman72adaa92005-06-20 21:15:16 -0700349 usb_register_notify(&mon_nb);
350
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100351 mutex_lock(&usb_bus_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 list_for_each_entry (ubus, &usb_bus_list, bus_list) {
353 mon_bus_init(mondir, ubus);
354 }
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100355 mutex_unlock(&usb_bus_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 return 0;
357}
358
359static void __exit mon_exit(void)
360{
361 struct mon_bus *mbus;
362 struct list_head *p;
363
Greg Kroah-Hartman72adaa92005-06-20 21:15:16 -0700364 usb_unregister_notify(&mon_nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 usb_mon_deregister();
366
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100367 mutex_lock(&mon_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 while (!list_empty(&mon_buses)) {
369 p = mon_buses.next;
370 mbus = list_entry(p, struct mon_bus, bus_link);
371 list_del(p);
372
373 debugfs_remove(mbus->dent_t);
374 debugfs_remove(mbus->dent_s);
375
376 /*
377 * This never happens, because the open/close paths in
378 * file level maintain module use counters and so rmmod fails
379 * before reaching here. However, better be safe...
380 */
381 if (mbus->nreaders) {
382 printk(KERN_ERR TAG
383 ": Outstanding opens (%d) on usb%d, leaking...\n",
384 mbus->nreaders, mbus->u_bus->busnum);
385 atomic_set(&mbus->ref.refcount, 2); /* Force leak */
386 }
387
388 mon_dissolve(mbus, mbus->u_bus);
389 kref_put(&mbus->ref, mon_bus_drop);
390 }
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100391 mutex_unlock(&mon_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
393 debugfs_remove(mon_dir);
394}
395
396module_init(mon_init);
397module_exit(mon_exit);
398
399MODULE_LICENSE("GPL");