diff options
author | Pete Zaitcev <zaitcev@redhat.com> | 2007-04-11 13:47:26 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-04-27 13:28:39 -0700 |
commit | ecb658d387dc09f344b3d755e8674076072032c7 (patch) | |
tree | b24067478554d5514db22ca6b107b8258e22b7e3 /drivers/usb/mon/mon_main.c | |
parent | 35d07fd58f47284adecf219d3b73e4ea197cf29f (diff) | |
download | lwn-ecb658d387dc09f344b3d755e8674076072032c7.tar.gz lwn-ecb658d387dc09f344b3d755e8674076072032c7.zip |
usbmon: bus zero
Add the "bus zero" feature to the usbmon. If a user process specifies bus
with number zero, it receives events from all buses. This is useful when
we wish to see initial enumeration when a bus is created, typically after
a modprobe. Until now, an application had to loop until a new bus could
be open, then start capturing on it. This procedure was cumbersome and
could lose initial events. Also, often it's too bothersome to find exactly
to which bus a specific device is attached.
Paolo Albeni provided the original concept implementation. I added the
handling of "bus->monitored" flag and generally fixed it up.
Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/mon/mon_main.c')
-rw-r--r-- | drivers/usb/mon/mon_main.c | 158 |
1 files changed, 93 insertions, 65 deletions
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index c9739e7b35e5..8a1df2c9c73e 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -16,8 +16,6 @@ #include "usb_mon.h" #include "../core/hcd.h" -static void mon_submit(struct usb_bus *ubus, struct urb *urb); -static void mon_complete(struct usb_bus *ubus, struct urb *urb); static void mon_stop(struct mon_bus *mbus); static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus); static void mon_bus_drop(struct kref *r); @@ -25,6 +23,7 @@ static void mon_bus_init(struct usb_bus *ubus); DEFINE_MUTEX(mon_lock); +struct mon_bus mon_bus0; /* Pseudo bus meaning "all buses" */ static LIST_HEAD(mon_buses); /* All buses we know: struct mon_bus */ /* @@ -35,22 +34,19 @@ static LIST_HEAD(mon_buses); /* All buses we know: struct mon_bus */ void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r) { unsigned long flags; - struct usb_bus *ubus; + struct list_head *p; spin_lock_irqsave(&mbus->lock, flags); if (mbus->nreaders == 0) { - ubus = mbus->u_bus; - if (ubus->monitored) { - /* - * Something is really broken, refuse to go on and - * possibly corrupt ops pointers or worse. - */ - printk(KERN_ERR TAG ": bus %d is already monitored\n", - ubus->busnum); - spin_unlock_irqrestore(&mbus->lock, flags); - return; + if (mbus == &mon_bus0) { + list_for_each (p, &mon_buses) { + struct mon_bus *m1; + m1 = list_entry(p, struct mon_bus, bus_link); + m1->u_bus->monitored = 1; + } + } else { + mbus->u_bus->monitored = 1; } - ubus->monitored = 1; } mbus->nreaders++; list_add_tail(&r->r_link, &mbus->r_list); @@ -80,77 +76,79 @@ void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r) /* */ -static void mon_submit(struct usb_bus *ubus, struct urb *urb) +static void mon_bus_submit(struct mon_bus *mbus, struct urb *urb) { - struct mon_bus *mbus; unsigned long flags; struct list_head *pos; struct mon_reader *r; - mbus = ubus->mon_bus; - if (mbus == NULL) - goto out_unlocked; - spin_lock_irqsave(&mbus->lock, flags); - if (mbus->nreaders == 0) - goto out_locked; - mbus->cnt_events++; list_for_each (pos, &mbus->r_list) { r = list_entry(pos, struct mon_reader, r_link); r->rnf_submit(r->r_data, urb); } - spin_unlock_irqrestore(&mbus->lock, flags); return; +} -out_locked: - spin_unlock_irqrestore(&mbus->lock, flags); -out_unlocked: - return; +static void mon_submit(struct usb_bus *ubus, struct urb *urb) +{ + struct mon_bus *mbus; + + if ((mbus = ubus->mon_bus) != NULL) + mon_bus_submit(mbus, urb); + mon_bus_submit(&mon_bus0, urb); } /* */ -static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error) +static void mon_bus_submit_error(struct mon_bus *mbus, struct urb *urb, int error) { - struct mon_bus *mbus; unsigned long flags; struct list_head *pos; struct mon_reader *r; - mbus = ubus->mon_bus; - if (mbus == NULL) - goto out_unlocked; - spin_lock_irqsave(&mbus->lock, flags); - if (mbus->nreaders == 0) - goto out_locked; - mbus->cnt_events++; list_for_each (pos, &mbus->r_list) { r = list_entry(pos, struct mon_reader, r_link); r->rnf_error(r->r_data, urb, error); } - spin_unlock_irqrestore(&mbus->lock, flags); return; +} -out_locked: - spin_unlock_irqrestore(&mbus->lock, flags); -out_unlocked: - return; +static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error) +{ + struct mon_bus *mbus; + + if ((mbus = ubus->mon_bus) != NULL) + mon_bus_submit_error(mbus, urb, error); + mon_bus_submit_error(&mon_bus0, urb, error); } /* */ -static void mon_complete(struct usb_bus *ubus, struct urb *urb) +static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb) { - struct mon_bus *mbus; unsigned long flags; struct list_head *pos; struct mon_reader *r; + spin_lock_irqsave(&mbus->lock, flags); + mbus->cnt_events++; + list_for_each (pos, &mbus->r_list) { + r = list_entry(pos, struct mon_reader, r_link); + r->rnf_complete(r->r_data, urb); + } + spin_unlock_irqrestore(&mbus->lock, flags); +} + +static void mon_complete(struct usb_bus *ubus, struct urb *urb) +{ + struct mon_bus *mbus; + mbus = ubus->mon_bus; if (mbus == NULL) { /* @@ -162,13 +160,8 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb) return; } - spin_lock_irqsave(&mbus->lock, flags); - mbus->cnt_events++; - list_for_each (pos, &mbus->r_list) { - r = list_entry(pos, struct mon_reader, r_link); - r->rnf_complete(r->r_data, urb); - } - spin_unlock_irqrestore(&mbus->lock, flags); + mon_bus_complete(mbus, urb); + mon_bus_complete(&mon_bus0, urb); } /* int (*unlink_urb) (struct urb *urb, int status); */ @@ -179,14 +172,26 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb) static void mon_stop(struct mon_bus *mbus) { struct usb_bus *ubus = mbus->u_bus; + struct list_head *p; - /* - * A stop can be called for a dissolved mon_bus in case of - * a reader staying across an rmmod foo_hcd. - */ - if (ubus != NULL) { - ubus->monitored = 0; - mb(); + if (mbus == &mon_bus0) { + list_for_each (p, &mon_buses) { + mbus = list_entry(p, struct mon_bus, bus_link); + /* + * We do not change nreaders here, so rely on mon_lock. + */ + if (mbus->nreaders == 0 && (ubus = mbus->u_bus) != NULL) + ubus->monitored = 0; + } + } else { + /* + * A stop can be called for a dissolved mon_bus in case of + * a reader staying across an rmmod foo_hcd, so test ->u_bus. + */ + if (mon_bus0.nreaders == 0 && (ubus = mbus->u_bus) != NULL) { + ubus->monitored = 0; + mb(); + } } } @@ -199,6 +204,10 @@ static void mon_stop(struct mon_bus *mbus) static void mon_bus_add(struct usb_bus *ubus) { mon_bus_init(ubus); + mutex_lock(&mon_lock); + if (mon_bus0.nreaders != 0) + ubus->monitored = 1; + mutex_unlock(&mon_lock); } /* @@ -250,12 +259,7 @@ static struct usb_mon_operations mon_ops_0 = { static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus) { - /* - * Never happens, but... - */ if (ubus->monitored) { - printk(KERN_ERR TAG ": bus %d is dissolved while monitored\n", - ubus->busnum); ubus->monitored = 0; mb(); } @@ -263,6 +267,8 @@ static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus) ubus->mon_bus = NULL; mbus->u_bus = NULL; mb(); + + /* We want synchronize_irq() here, but that needs an argument. */ } /* @@ -295,9 +301,8 @@ static void mon_bus_init(struct usb_bus *ubus) */ mbus->u_bus = ubus; ubus->mon_bus = mbus; - mbus->uses_dma = ubus->uses_dma; - mbus->text_inited = mon_text_add(mbus, ubus); + mbus->text_inited = mon_text_add(mbus, ubus->busnum); // mon_bin_add(...) mutex_lock(&mon_lock); @@ -309,6 +314,18 @@ err_alloc: return; } +static void mon_bus0_init(void) +{ + struct mon_bus *mbus = &mon_bus0; + + kref_init(&mbus->ref); + spin_lock_init(&mbus->lock); + INIT_LIST_HEAD(&mbus->r_list); + + mbus->text_inited = mon_text_add(mbus, 0); + // mbus->bin_inited = mon_bin_add(mbus, 0); +} + /* * Search a USB bus by number. Notice that USB bus numbers start from one, * which we may later use to identify "all" with zero. @@ -322,6 +339,9 @@ struct mon_bus *mon_bus_lookup(unsigned int num) struct list_head *p; struct mon_bus *mbus; + if (num == 0) { + return &mon_bus0; + } list_for_each (p, &mon_buses) { mbus = list_entry(p, struct mon_bus, bus_link); if (mbus->u_bus->busnum == num) { @@ -341,6 +361,8 @@ static int __init mon_init(void) if ((rc = mon_bin_init()) != 0) goto err_bin; + mon_bus0_init(); + if (usb_mon_register(&mon_ops_0) != 0) { printk(KERN_NOTICE TAG ": unable to register with the core\n"); rc = -ENODEV; @@ -374,6 +396,7 @@ static void __exit mon_exit(void) usb_mon_deregister(); mutex_lock(&mon_lock); + while (!list_empty(&mon_buses)) { p = mon_buses.next; mbus = list_entry(p, struct mon_bus, bus_link); @@ -397,6 +420,11 @@ static void __exit mon_exit(void) mon_dissolve(mbus, mbus->u_bus); kref_put(&mbus->ref, mon_bus_drop); } + + mbus = &mon_bus0; + if (mbus->text_inited) + mon_text_del(mbus); + mutex_unlock(&mon_lock); mon_text_exit(); |