blob: c9739e7b35e53eb112ffbc16e0c6263512a69aa5 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/smp_lock.h>
Greg Kroah-Hartman72adaa92005-06-20 21:15:16 -070013#include <linux/notifier.h>
Arjan van de Ven4186ecf2006-01-11 15:55:29 +010014#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015
16#include "usb_mon.h"
17#include "../core/hcd.h"
18
19static void mon_submit(struct usb_bus *ubus, struct urb *urb);
20static void mon_complete(struct usb_bus *ubus, struct urb *urb);
21static void mon_stop(struct mon_bus *mbus);
22static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus);
23static void mon_bus_drop(struct kref *r);
Pete Zaitcev6f23ee12006-12-30 22:43:10 -080024static void mon_bus_init(struct usb_bus *ubus);
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
Arjan van de Ven4186ecf2006-01-11 15:55:29 +010026DEFINE_MUTEX(mon_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070027
Linus Torvalds1da177e2005-04-16 15:20:36 -070028static LIST_HEAD(mon_buses); /* All buses we know: struct mon_bus */
29
30/*
31 * Link a reader into the bus.
32 *
33 * This must be called with mon_lock taken because of mbus->ref.
34 */
35void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r)
36{
37 unsigned long flags;
38 struct usb_bus *ubus;
39
40 spin_lock_irqsave(&mbus->lock, flags);
41 if (mbus->nreaders == 0) {
42 ubus = mbus->u_bus;
43 if (ubus->monitored) {
44 /*
45 * Something is really broken, refuse to go on and
46 * possibly corrupt ops pointers or worse.
47 */
48 printk(KERN_ERR TAG ": bus %d is already monitored\n",
49 ubus->busnum);
50 spin_unlock_irqrestore(&mbus->lock, flags);
51 return;
52 }
53 ubus->monitored = 1;
54 }
55 mbus->nreaders++;
56 list_add_tail(&r->r_link, &mbus->r_list);
57 spin_unlock_irqrestore(&mbus->lock, flags);
58
59 kref_get(&mbus->ref);
60}
61
62/*
63 * Unlink reader from the bus.
64 *
65 * This is called with mon_lock taken, so we can decrement mbus->ref.
66 */
67void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r)
68{
69 unsigned long flags;
70
71 spin_lock_irqsave(&mbus->lock, flags);
72 list_del(&r->r_link);
73 --mbus->nreaders;
74 if (mbus->nreaders == 0)
75 mon_stop(mbus);
76 spin_unlock_irqrestore(&mbus->lock, flags);
77
78 kref_put(&mbus->ref, mon_bus_drop);
79}
80
81/*
82 */
83static void mon_submit(struct usb_bus *ubus, struct urb *urb)
84{
85 struct mon_bus *mbus;
86 unsigned long flags;
87 struct list_head *pos;
88 struct mon_reader *r;
89
90 mbus = ubus->mon_bus;
91 if (mbus == NULL)
92 goto out_unlocked;
93
94 spin_lock_irqsave(&mbus->lock, flags);
95 if (mbus->nreaders == 0)
96 goto out_locked;
97
Pete Zaitcev5b1c6742006-06-09 20:10:10 -070098 mbus->cnt_events++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 list_for_each (pos, &mbus->r_list) {
100 r = list_entry(pos, struct mon_reader, r_link);
101 r->rnf_submit(r->r_data, urb);
102 }
103
104 spin_unlock_irqrestore(&mbus->lock, flags);
105 return;
106
107out_locked:
108 spin_unlock_irqrestore(&mbus->lock, flags);
109out_unlocked:
110 return;
111}
112
113/*
114 */
Pete Zaitcev12e72fe2006-06-09 22:03:32 -0700115static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116{
117 struct mon_bus *mbus;
Pete Zaitcev12e72fe2006-06-09 22:03:32 -0700118 unsigned long flags;
119 struct list_head *pos;
120 struct mon_reader *r;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
122 mbus = ubus->mon_bus;
123 if (mbus == NULL)
124 goto out_unlocked;
125
Pete Zaitcev12e72fe2006-06-09 22:03:32 -0700126 spin_lock_irqsave(&mbus->lock, flags);
127 if (mbus->nreaders == 0)
128 goto out_locked;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
Pete Zaitcev12e72fe2006-06-09 22:03:32 -0700130 mbus->cnt_events++;
131 list_for_each (pos, &mbus->r_list) {
132 r = list_entry(pos, struct mon_reader, r_link);
133 r->rnf_error(r->r_data, urb, error);
134 }
135
136 spin_unlock_irqrestore(&mbus->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 return;
138
Pete Zaitcev12e72fe2006-06-09 22:03:32 -0700139out_locked:
140 spin_unlock_irqrestore(&mbus->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141out_unlocked:
142 return;
143}
144
145/*
146 */
147static void mon_complete(struct usb_bus *ubus, struct urb *urb)
148{
149 struct mon_bus *mbus;
150 unsigned long flags;
151 struct list_head *pos;
152 struct mon_reader *r;
153
154 mbus = ubus->mon_bus;
155 if (mbus == NULL) {
156 /*
157 * This should not happen.
158 * At this point we do not even know the bus number...
159 */
160 printk(KERN_ERR TAG ": Null mon bus in URB, pipe 0x%x\n",
161 urb->pipe);
162 return;
163 }
164
165 spin_lock_irqsave(&mbus->lock, flags);
Pete Zaitcev5b1c6742006-06-09 20:10:10 -0700166 mbus->cnt_events++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 list_for_each (pos, &mbus->r_list) {
168 r = list_entry(pos, struct mon_reader, r_link);
169 r->rnf_complete(r->r_data, urb);
170 }
171 spin_unlock_irqrestore(&mbus->lock, flags);
172}
173
174/* int (*unlink_urb) (struct urb *urb, int status); */
175
176/*
177 * Stop monitoring.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 */
179static void mon_stop(struct mon_bus *mbus)
180{
181 struct usb_bus *ubus = mbus->u_bus;
182
183 /*
184 * A stop can be called for a dissolved mon_bus in case of
185 * a reader staying across an rmmod foo_hcd.
186 */
187 if (ubus != NULL) {
188 ubus->monitored = 0;
189 mb();
190 }
191}
192
193/*
194 * Add a USB bus (usually by a modprobe foo-hcd)
195 *
196 * This does not return an error code because the core cannot care less
197 * if monitoring is not established.
198 */
199static void mon_bus_add(struct usb_bus *ubus)
200{
Pete Zaitcev6f23ee12006-12-30 22:43:10 -0800201 mon_bus_init(ubus);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202}
203
204/*
205 * Remove a USB bus (either from rmmod foo-hcd or from a hot-remove event).
206 */
207static void mon_bus_remove(struct usb_bus *ubus)
208{
209 struct mon_bus *mbus = ubus->mon_bus;
210
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100211 mutex_lock(&mon_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 list_del(&mbus->bus_link);
Pete Zaitcev6f23ee12006-12-30 22:43:10 -0800213 if (mbus->text_inited)
214 mon_text_del(mbus);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
216 mon_dissolve(mbus, ubus);
217 kref_put(&mbus->ref, mon_bus_drop);
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100218 mutex_unlock(&mon_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219}
220
Greg Kroah-Hartman72adaa92005-06-20 21:15:16 -0700221static int mon_notify(struct notifier_block *self, unsigned long action,
222 void *dev)
223{
224 switch (action) {
225 case USB_BUS_ADD:
226 mon_bus_add(dev);
227 break;
228 case USB_BUS_REMOVE:
229 mon_bus_remove(dev);
230 }
231 return NOTIFY_OK;
232}
233
234static struct notifier_block mon_nb = {
235 .notifier_call = mon_notify,
236};
237
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238/*
239 * Ops
240 */
241static struct usb_mon_operations mon_ops_0 = {
242 .urb_submit = mon_submit,
243 .urb_submit_error = mon_submit_error,
244 .urb_complete = mon_complete,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245};
246
247/*
248 * Tear usb_bus and mon_bus apart.
249 */
250static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus)
251{
252
253 /*
254 * Never happens, but...
255 */
256 if (ubus->monitored) {
257 printk(KERN_ERR TAG ": bus %d is dissolved while monitored\n",
258 ubus->busnum);
259 ubus->monitored = 0;
260 mb();
261 }
262
263 ubus->mon_bus = NULL;
264 mbus->u_bus = NULL;
265 mb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266}
267
268/*
269 */
270static void mon_bus_drop(struct kref *r)
271{
272 struct mon_bus *mbus = container_of(r, struct mon_bus, ref);
273 kfree(mbus);
274}
275
276/*
277 * Initialize a bus for us:
278 * - allocate mon_bus
279 * - refcount USB bus struct
280 * - link
281 */
Pete Zaitcev6f23ee12006-12-30 22:43:10 -0800282static void mon_bus_init(struct usb_bus *ubus)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 struct mon_bus *mbus;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100286 if ((mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 goto err_alloc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 kref_init(&mbus->ref);
289 spin_lock_init(&mbus->lock);
290 INIT_LIST_HEAD(&mbus->r_list);
291
292 /*
Alan Stern17200582006-08-30 11:32:52 -0400293 * We don't need to take a reference to ubus, because we receive
294 * a notification if the bus is about to be removed.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 mbus->u_bus = ubus;
297 ubus->mon_bus = mbus;
Alan Stern4d6cd482006-08-30 11:35:21 -0400298 mbus->uses_dma = ubus->uses_dma;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
Pete Zaitcev6f23ee12006-12-30 22:43:10 -0800300 mbus->text_inited = mon_text_add(mbus, ubus);
301 // mon_bin_add(...)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100303 mutex_lock(&mon_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 list_add_tail(&mbus->bus_link, &mon_buses);
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100305 mutex_unlock(&mon_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 return;
307
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308err_alloc:
309 return;
310}
311
Pete Zaitcev6f23ee12006-12-30 22:43:10 -0800312/*
313 * Search a USB bus by number. Notice that USB bus numbers start from one,
314 * which we may later use to identify "all" with zero.
315 *
316 * This function must be called with mon_lock held.
317 *
318 * This is obviously inefficient and may be revised in the future.
319 */
320struct mon_bus *mon_bus_lookup(unsigned int num)
321{
322 struct list_head *p;
323 struct mon_bus *mbus;
324
325 list_for_each (p, &mon_buses) {
326 mbus = list_entry(p, struct mon_bus, bus_link);
327 if (mbus->u_bus->busnum == num) {
328 return mbus;
329 }
330 }
331 return NULL;
332}
333
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334static int __init mon_init(void)
335{
336 struct usb_bus *ubus;
Pete Zaitcev6f23ee12006-12-30 22:43:10 -0800337 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338
Pete Zaitcev6f23ee12006-12-30 22:43:10 -0800339 if ((rc = mon_text_init()) != 0)
340 goto err_text;
341 if ((rc = mon_bin_init()) != 0)
342 goto err_bin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
344 if (usb_mon_register(&mon_ops_0) != 0) {
345 printk(KERN_NOTICE TAG ": unable to register with the core\n");
Pete Zaitcev6f23ee12006-12-30 22:43:10 -0800346 rc = -ENODEV;
347 goto err_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 }
349 // MOD_INC_USE_COUNT(which_module?);
350
Greg Kroah-Hartman72adaa92005-06-20 21:15:16 -0700351 usb_register_notify(&mon_nb);
352
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100353 mutex_lock(&usb_bus_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 list_for_each_entry (ubus, &usb_bus_list, bus_list) {
Pete Zaitcev6f23ee12006-12-30 22:43:10 -0800355 mon_bus_init(ubus);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 }
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100357 mutex_unlock(&usb_bus_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 return 0;
Pete Zaitcev6f23ee12006-12-30 22:43:10 -0800359
360err_reg:
361 mon_bin_exit();
362err_bin:
363 mon_text_exit();
364err_text:
365 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366}
367
368static void __exit mon_exit(void)
369{
370 struct mon_bus *mbus;
371 struct list_head *p;
372
Greg Kroah-Hartman72adaa92005-06-20 21:15:16 -0700373 usb_unregister_notify(&mon_nb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 usb_mon_deregister();
375
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100376 mutex_lock(&mon_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 while (!list_empty(&mon_buses)) {
378 p = mon_buses.next;
379 mbus = list_entry(p, struct mon_bus, bus_link);
380 list_del(p);
381
Pete Zaitcev6f23ee12006-12-30 22:43:10 -0800382 if (mbus->text_inited)
383 mon_text_del(mbus);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
385 /*
386 * This never happens, because the open/close paths in
387 * file level maintain module use counters and so rmmod fails
388 * before reaching here. However, better be safe...
389 */
390 if (mbus->nreaders) {
391 printk(KERN_ERR TAG
392 ": Outstanding opens (%d) on usb%d, leaking...\n",
393 mbus->nreaders, mbus->u_bus->busnum);
394 atomic_set(&mbus->ref.refcount, 2); /* Force leak */
395 }
396
397 mon_dissolve(mbus, mbus->u_bus);
398 kref_put(&mbus->ref, mon_bus_drop);
399 }
Arjan van de Ven4186ecf2006-01-11 15:55:29 +0100400 mutex_unlock(&mon_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
Pete Zaitcev6f23ee12006-12-30 22:43:10 -0800402 mon_text_exit();
403 mon_bin_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404}
405
406module_init(mon_init);
407module_exit(mon_exit);
408
409MODULE_LICENSE("GPL");