diff options
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 @@ | |||
16 | #include "usb_mon.h" | 16 | #include "usb_mon.h" |
17 | #include "../core/hcd.h" | 17 | #include "../core/hcd.h" |
18 | 18 | ||
19 | static void mon_submit(struct usb_bus *ubus, struct urb *urb); | ||
20 | static void mon_complete(struct usb_bus *ubus, struct urb *urb); | ||
21 | static void mon_stop(struct mon_bus *mbus); | 19 | static void mon_stop(struct mon_bus *mbus); |
22 | static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus); | 20 | static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus); |
23 | static void mon_bus_drop(struct kref *r); | 21 | static void mon_bus_drop(struct kref *r); |
@@ -25,6 +23,7 @@ static void mon_bus_init(struct usb_bus *ubus); | |||
25 | 23 | ||
26 | DEFINE_MUTEX(mon_lock); | 24 | DEFINE_MUTEX(mon_lock); |
27 | 25 | ||
26 | struct mon_bus mon_bus0; /* Pseudo bus meaning "all buses" */ | ||
28 | static LIST_HEAD(mon_buses); /* All buses we know: struct mon_bus */ | 27 | static LIST_HEAD(mon_buses); /* All buses we know: struct mon_bus */ |
29 | 28 | ||
30 | /* | 29 | /* |
@@ -35,22 +34,19 @@ static LIST_HEAD(mon_buses); /* All buses we know: struct mon_bus */ | |||
35 | void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r) | 34 | void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r) |
36 | { | 35 | { |
37 | unsigned long flags; | 36 | unsigned long flags; |
38 | struct usb_bus *ubus; | 37 | struct list_head *p; |
39 | 38 | ||
40 | spin_lock_irqsave(&mbus->lock, flags); | 39 | spin_lock_irqsave(&mbus->lock, flags); |
41 | if (mbus->nreaders == 0) { | 40 | if (mbus->nreaders == 0) { |
42 | ubus = mbus->u_bus; | 41 | if (mbus == &mon_bus0) { |
43 | if (ubus->monitored) { | 42 | list_for_each (p, &mon_buses) { |
44 | /* | 43 | struct mon_bus *m1; |
45 | * Something is really broken, refuse to go on and | 44 | m1 = list_entry(p, struct mon_bus, bus_link); |
46 | * possibly corrupt ops pointers or worse. | 45 | m1->u_bus->monitored = 1; |
47 | */ | 46 | } |
48 | printk(KERN_ERR TAG ": bus %d is already monitored\n", | 47 | } else { |
49 | ubus->busnum); | 48 | mbus->u_bus->monitored = 1; |
50 | spin_unlock_irqrestore(&mbus->lock, flags); | ||
51 | return; | ||
52 | } | 49 | } |
53 | ubus->monitored = 1; | ||
54 | } | 50 | } |
55 | mbus->nreaders++; | 51 | mbus->nreaders++; |
56 | list_add_tail(&r->r_link, &mbus->r_list); | 52 | 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) | |||
80 | 76 | ||
81 | /* | 77 | /* |
82 | */ | 78 | */ |
83 | static void mon_submit(struct usb_bus *ubus, struct urb *urb) | 79 | static void mon_bus_submit(struct mon_bus *mbus, struct urb *urb) |
84 | { | 80 | { |
85 | struct mon_bus *mbus; | ||
86 | unsigned long flags; | 81 | unsigned long flags; |
87 | struct list_head *pos; | 82 | struct list_head *pos; |
88 | struct mon_reader *r; | 83 | struct mon_reader *r; |
89 | 84 | ||
90 | mbus = ubus->mon_bus; | ||
91 | if (mbus == NULL) | ||
92 | goto out_unlocked; | ||
93 | |||
94 | spin_lock_irqsave(&mbus->lock, flags); | 85 | spin_lock_irqsave(&mbus->lock, flags); |
95 | if (mbus->nreaders == 0) | ||
96 | goto out_locked; | ||
97 | |||
98 | mbus->cnt_events++; | 86 | mbus->cnt_events++; |
99 | list_for_each (pos, &mbus->r_list) { | 87 | list_for_each (pos, &mbus->r_list) { |
100 | r = list_entry(pos, struct mon_reader, r_link); | 88 | r = list_entry(pos, struct mon_reader, r_link); |
101 | r->rnf_submit(r->r_data, urb); | 89 | r->rnf_submit(r->r_data, urb); |
102 | } | 90 | } |
103 | |||
104 | spin_unlock_irqrestore(&mbus->lock, flags); | 91 | spin_unlock_irqrestore(&mbus->lock, flags); |
105 | return; | 92 | return; |
93 | } | ||
106 | 94 | ||
107 | out_locked: | 95 | static void mon_submit(struct usb_bus *ubus, struct urb *urb) |
108 | spin_unlock_irqrestore(&mbus->lock, flags); | 96 | { |
109 | out_unlocked: | 97 | struct mon_bus *mbus; |
110 | return; | 98 | |
99 | if ((mbus = ubus->mon_bus) != NULL) | ||
100 | mon_bus_submit(mbus, urb); | ||
101 | mon_bus_submit(&mon_bus0, urb); | ||
111 | } | 102 | } |
112 | 103 | ||
113 | /* | 104 | /* |
114 | */ | 105 | */ |
115 | static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error) | 106 | static void mon_bus_submit_error(struct mon_bus *mbus, struct urb *urb, int error) |
116 | { | 107 | { |
117 | struct mon_bus *mbus; | ||
118 | unsigned long flags; | 108 | unsigned long flags; |
119 | struct list_head *pos; | 109 | struct list_head *pos; |
120 | struct mon_reader *r; | 110 | struct mon_reader *r; |
121 | 111 | ||
122 | mbus = ubus->mon_bus; | ||
123 | if (mbus == NULL) | ||
124 | goto out_unlocked; | ||
125 | |||
126 | spin_lock_irqsave(&mbus->lock, flags); | 112 | spin_lock_irqsave(&mbus->lock, flags); |
127 | if (mbus->nreaders == 0) | ||
128 | goto out_locked; | ||
129 | |||
130 | mbus->cnt_events++; | 113 | mbus->cnt_events++; |
131 | list_for_each (pos, &mbus->r_list) { | 114 | list_for_each (pos, &mbus->r_list) { |
132 | r = list_entry(pos, struct mon_reader, r_link); | 115 | r = list_entry(pos, struct mon_reader, r_link); |
133 | r->rnf_error(r->r_data, urb, error); | 116 | r->rnf_error(r->r_data, urb, error); |
134 | } | 117 | } |
135 | |||
136 | spin_unlock_irqrestore(&mbus->lock, flags); | 118 | spin_unlock_irqrestore(&mbus->lock, flags); |
137 | return; | 119 | return; |
120 | } | ||
138 | 121 | ||
139 | out_locked: | 122 | static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error) |
140 | spin_unlock_irqrestore(&mbus->lock, flags); | 123 | { |
141 | out_unlocked: | 124 | struct mon_bus *mbus; |
142 | return; | 125 | |
126 | if ((mbus = ubus->mon_bus) != NULL) | ||
127 | mon_bus_submit_error(mbus, urb, error); | ||
128 | mon_bus_submit_error(&mon_bus0, urb, error); | ||
143 | } | 129 | } |
144 | 130 | ||
145 | /* | 131 | /* |
146 | */ | 132 | */ |
147 | static void mon_complete(struct usb_bus *ubus, struct urb *urb) | 133 | static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb) |
148 | { | 134 | { |
149 | struct mon_bus *mbus; | ||
150 | unsigned long flags; | 135 | unsigned long flags; |
151 | struct list_head *pos; | 136 | struct list_head *pos; |
152 | struct mon_reader *r; | 137 | struct mon_reader *r; |
153 | 138 | ||
139 | spin_lock_irqsave(&mbus->lock, flags); | ||
140 | mbus->cnt_events++; | ||
141 | list_for_each (pos, &mbus->r_list) { | ||
142 | r = list_entry(pos, struct mon_reader, r_link); | ||
143 | r->rnf_complete(r->r_data, urb); | ||
144 | } | ||
145 | spin_unlock_irqrestore(&mbus->lock, flags); | ||
146 | } | ||
147 | |||
148 | static void mon_complete(struct usb_bus *ubus, struct urb *urb) | ||
149 | { | ||
150 | struct mon_bus *mbus; | ||
151 | |||
154 | mbus = ubus->mon_bus; | 152 | mbus = ubus->mon_bus; |
155 | if (mbus == NULL) { | 153 | if (mbus == NULL) { |
156 | /* | 154 | /* |
@@ -162,13 +160,8 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb) | |||
162 | return; | 160 | return; |
163 | } | 161 | } |
164 | 162 | ||
165 | spin_lock_irqsave(&mbus->lock, flags); | 163 | mon_bus_complete(mbus, urb); |
166 | mbus->cnt_events++; | 164 | mon_bus_complete(&mon_bus0, urb); |
167 | 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 | } | 165 | } |
173 | 166 | ||
174 | /* int (*unlink_urb) (struct urb *urb, int status); */ | 167 | /* int (*unlink_urb) (struct urb *urb, int status); */ |
@@ -179,14 +172,26 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb) | |||
179 | static void mon_stop(struct mon_bus *mbus) | 172 | static void mon_stop(struct mon_bus *mbus) |
180 | { | 173 | { |
181 | struct usb_bus *ubus = mbus->u_bus; | 174 | struct usb_bus *ubus = mbus->u_bus; |
175 | struct list_head *p; | ||
182 | 176 | ||
183 | /* | 177 | if (mbus == &mon_bus0) { |
184 | * A stop can be called for a dissolved mon_bus in case of | 178 | list_for_each (p, &mon_buses) { |
185 | * a reader staying across an rmmod foo_hcd. | 179 | mbus = list_entry(p, struct mon_bus, bus_link); |
186 | */ | 180 | /* |
187 | if (ubus != NULL) { | 181 | * We do not change nreaders here, so rely on mon_lock. |
188 | ubus->monitored = 0; | 182 | */ |
189 | mb(); | 183 | if (mbus->nreaders == 0 && (ubus = mbus->u_bus) != NULL) |
184 | ubus->monitored = 0; | ||
185 | } | ||
186 | } else { | ||
187 | /* | ||
188 | * A stop can be called for a dissolved mon_bus in case of | ||
189 | * a reader staying across an rmmod foo_hcd, so test ->u_bus. | ||
190 | */ | ||
191 | if (mon_bus0.nreaders == 0 && (ubus = mbus->u_bus) != NULL) { | ||
192 | ubus->monitored = 0; | ||
193 | mb(); | ||
194 | } | ||
190 | } | 195 | } |
191 | } | 196 | } |
192 | 197 | ||
@@ -199,6 +204,10 @@ static void mon_stop(struct mon_bus *mbus) | |||
199 | static void mon_bus_add(struct usb_bus *ubus) | 204 | static void mon_bus_add(struct usb_bus *ubus) |
200 | { | 205 | { |
201 | mon_bus_init(ubus); | 206 | mon_bus_init(ubus); |
207 | mutex_lock(&mon_lock); | ||
208 | if (mon_bus0.nreaders != 0) | ||
209 | ubus->monitored = 1; | ||
210 | mutex_unlock(&mon_lock); | ||
202 | } | 211 | } |
203 | 212 | ||
204 | /* | 213 | /* |
@@ -250,12 +259,7 @@ static struct usb_mon_operations mon_ops_0 = { | |||
250 | static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus) | 259 | static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus) |
251 | { | 260 | { |
252 | 261 | ||
253 | /* | ||
254 | * Never happens, but... | ||
255 | */ | ||
256 | if (ubus->monitored) { | 262 | if (ubus->monitored) { |
257 | printk(KERN_ERR TAG ": bus %d is dissolved while monitored\n", | ||
258 | ubus->busnum); | ||
259 | ubus->monitored = 0; | 263 | ubus->monitored = 0; |
260 | mb(); | 264 | mb(); |
261 | } | 265 | } |
@@ -263,6 +267,8 @@ static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus) | |||
263 | ubus->mon_bus = NULL; | 267 | ubus->mon_bus = NULL; |
264 | mbus->u_bus = NULL; | 268 | mbus->u_bus = NULL; |
265 | mb(); | 269 | mb(); |
270 | |||
271 | /* We want synchronize_irq() here, but that needs an argument. */ | ||
266 | } | 272 | } |
267 | 273 | ||
268 | /* | 274 | /* |
@@ -295,9 +301,8 @@ static void mon_bus_init(struct usb_bus *ubus) | |||
295 | */ | 301 | */ |
296 | mbus->u_bus = ubus; | 302 | mbus->u_bus = ubus; |
297 | ubus->mon_bus = mbus; | 303 | ubus->mon_bus = mbus; |
298 | mbus->uses_dma = ubus->uses_dma; | ||
299 | 304 | ||
300 | mbus->text_inited = mon_text_add(mbus, ubus); | 305 | mbus->text_inited = mon_text_add(mbus, ubus->busnum); |
301 | // mon_bin_add(...) | 306 | // mon_bin_add(...) |
302 | 307 | ||
303 | mutex_lock(&mon_lock); | 308 | mutex_lock(&mon_lock); |
@@ -309,6 +314,18 @@ err_alloc: | |||
309 | return; | 314 | return; |
310 | } | 315 | } |
311 | 316 | ||
317 | static void mon_bus0_init(void) | ||
318 | { | ||
319 | struct mon_bus *mbus = &mon_bus0; | ||
320 | |||
321 | kref_init(&mbus->ref); | ||
322 | spin_lock_init(&mbus->lock); | ||
323 | INIT_LIST_HEAD(&mbus->r_list); | ||
324 | |||
325 | mbus->text_inited = mon_text_add(mbus, 0); | ||
326 | // mbus->bin_inited = mon_bin_add(mbus, 0); | ||
327 | } | ||
328 | |||
312 | /* | 329 | /* |
313 | * Search a USB bus by number. Notice that USB bus numbers start from one, | 330 | * 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. | 331 | * which we may later use to identify "all" with zero. |
@@ -322,6 +339,9 @@ struct mon_bus *mon_bus_lookup(unsigned int num) | |||
322 | struct list_head *p; | 339 | struct list_head *p; |
323 | struct mon_bus *mbus; | 340 | struct mon_bus *mbus; |
324 | 341 | ||
342 | if (num == 0) { | ||
343 | return &mon_bus0; | ||
344 | } | ||
325 | list_for_each (p, &mon_buses) { | 345 | list_for_each (p, &mon_buses) { |
326 | mbus = list_entry(p, struct mon_bus, bus_link); | 346 | mbus = list_entry(p, struct mon_bus, bus_link); |
327 | if (mbus->u_bus->busnum == num) { | 347 | if (mbus->u_bus->busnum == num) { |
@@ -341,6 +361,8 @@ static int __init mon_init(void) | |||
341 | if ((rc = mon_bin_init()) != 0) | 361 | if ((rc = mon_bin_init()) != 0) |
342 | goto err_bin; | 362 | goto err_bin; |
343 | 363 | ||
364 | mon_bus0_init(); | ||
365 | |||
344 | if (usb_mon_register(&mon_ops_0) != 0) { | 366 | if (usb_mon_register(&mon_ops_0) != 0) { |
345 | printk(KERN_NOTICE TAG ": unable to register with the core\n"); | 367 | printk(KERN_NOTICE TAG ": unable to register with the core\n"); |
346 | rc = -ENODEV; | 368 | rc = -ENODEV; |
@@ -374,6 +396,7 @@ static void __exit mon_exit(void) | |||
374 | usb_mon_deregister(); | 396 | usb_mon_deregister(); |
375 | 397 | ||
376 | mutex_lock(&mon_lock); | 398 | mutex_lock(&mon_lock); |
399 | |||
377 | while (!list_empty(&mon_buses)) { | 400 | while (!list_empty(&mon_buses)) { |
378 | p = mon_buses.next; | 401 | p = mon_buses.next; |
379 | mbus = list_entry(p, struct mon_bus, bus_link); | 402 | mbus = list_entry(p, struct mon_bus, bus_link); |
@@ -397,6 +420,11 @@ static void __exit mon_exit(void) | |||
397 | mon_dissolve(mbus, mbus->u_bus); | 420 | mon_dissolve(mbus, mbus->u_bus); |
398 | kref_put(&mbus->ref, mon_bus_drop); | 421 | kref_put(&mbus->ref, mon_bus_drop); |
399 | } | 422 | } |
423 | |||
424 | mbus = &mon_bus0; | ||
425 | if (mbus->text_inited) | ||
426 | mon_text_del(mbus); | ||
427 | |||
400 | mutex_unlock(&mon_lock); | 428 | mutex_unlock(&mon_lock); |
401 | 429 | ||
402 | mon_text_exit(); | 430 | mon_text_exit(); |