diff options
Diffstat (limited to 'drivers/usb/wusbcore/wa-rpipe.c')
-rw-r--r-- | drivers/usb/wusbcore/wa-rpipe.c | 562 |
1 files changed, 562 insertions, 0 deletions
diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c new file mode 100644 index 00000000000..f18e4aae66e --- /dev/null +++ b/drivers/usb/wusbcore/wa-rpipe.c | |||
@@ -0,0 +1,562 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter | ||
3 | * rpipe management | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
20 | * 02110-1301, USA. | ||
21 | * | ||
22 | * | ||
23 | * FIXME: docs | ||
24 | * | ||
25 | * RPIPE | ||
26 | * | ||
27 | * Targetted at different downstream endpoints | ||
28 | * | ||
29 | * Descriptor: use to config the remote pipe. | ||
30 | * | ||
31 | * The number of blocks could be dynamic (wBlocks in descriptor is | ||
32 | * 0)--need to schedule them then. | ||
33 | * | ||
34 | * Each bit in wa->rpipe_bm represents if an rpipe is being used or | ||
35 | * not. Rpipes are represented with a 'struct wa_rpipe' that is | ||
36 | * attached to the hcpriv member of a 'struct usb_host_endpoint'. | ||
37 | * | ||
38 | * When you need to xfer data to an endpoint, you get an rpipe for it | ||
39 | * with wa_ep_rpipe_get(), which gives you a reference to the rpipe | ||
40 | * and keeps a single one (the first one) with the endpoint. When you | ||
41 | * are done transferring, you drop that reference. At the end the | ||
42 | * rpipe is always allocated and bound to the endpoint. There it might | ||
43 | * be recycled when not used. | ||
44 | * | ||
45 | * Addresses: | ||
46 | * | ||
47 | * We use a 1:1 mapping mechanism between port address (0 based | ||
48 | * index, actually) and the address. The USB stack knows about this. | ||
49 | * | ||
50 | * USB Stack port number 4 (1 based) | ||
51 | * WUSB code port index 3 (0 based) | ||
52 | * USB Addresss 5 (2 based -- 0 is for default, 1 for root hub) | ||
53 | * | ||
54 | * Now, because we don't use the concept as default address exactly | ||
55 | * like the (wired) USB code does, we need to kind of skip it. So we | ||
56 | * never take addresses from the urb->pipe, but from the | ||
57 | * urb->dev->devnum, to make sure that we always have the right | ||
58 | * destination address. | ||
59 | */ | ||
60 | #include <linux/init.h> | ||
61 | #include <asm/atomic.h> | ||
62 | #include <linux/bitmap.h> | ||
63 | #include "wusbhc.h" | ||
64 | #include "wa-hc.h" | ||
65 | |||
66 | #define D_LOCAL 0 | ||
67 | #include <linux/uwb/debug.h> | ||
68 | |||
69 | |||
70 | static int __rpipe_get_descr(struct wahc *wa, | ||
71 | struct usb_rpipe_descriptor *descr, u16 index) | ||
72 | { | ||
73 | ssize_t result; | ||
74 | struct device *dev = &wa->usb_iface->dev; | ||
75 | |||
76 | /* Get the RPIPE descriptor -- we cannot use the usb_get_descriptor() | ||
77 | * function because the arguments are different. | ||
78 | */ | ||
79 | d_printf(1, dev, "rpipe %u: get descr\n", index); | ||
80 | result = usb_control_msg( | ||
81 | wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0), | ||
82 | USB_REQ_GET_DESCRIPTOR, | ||
83 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_RPIPE, | ||
84 | USB_DT_RPIPE<<8, index, descr, sizeof(*descr), | ||
85 | 1000 /* FIXME: arbitrary */); | ||
86 | if (result < 0) { | ||
87 | dev_err(dev, "rpipe %u: get descriptor failed: %d\n", | ||
88 | index, (int)result); | ||
89 | goto error; | ||
90 | } | ||
91 | if (result < sizeof(*descr)) { | ||
92 | dev_err(dev, "rpipe %u: got short descriptor " | ||
93 | "(%zd vs %zd bytes needed)\n", | ||
94 | index, result, sizeof(*descr)); | ||
95 | result = -EINVAL; | ||
96 | goto error; | ||
97 | } | ||
98 | result = 0; | ||
99 | |||
100 | error: | ||
101 | return result; | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * | ||
106 | * The descriptor is assumed to be properly initialized (ie: you got | ||
107 | * it through __rpipe_get_descr()). | ||
108 | */ | ||
109 | static int __rpipe_set_descr(struct wahc *wa, | ||
110 | struct usb_rpipe_descriptor *descr, u16 index) | ||
111 | { | ||
112 | ssize_t result; | ||
113 | struct device *dev = &wa->usb_iface->dev; | ||
114 | |||
115 | /* we cannot use the usb_get_descriptor() function because the | ||
116 | * arguments are different. | ||
117 | */ | ||
118 | d_printf(1, dev, "rpipe %u: set descr\n", index); | ||
119 | result = usb_control_msg( | ||
120 | wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
121 | USB_REQ_SET_DESCRIPTOR, | ||
122 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE, | ||
123 | USB_DT_RPIPE<<8, index, descr, sizeof(*descr), | ||
124 | HZ / 10); | ||
125 | if (result < 0) { | ||
126 | dev_err(dev, "rpipe %u: set descriptor failed: %d\n", | ||
127 | index, (int)result); | ||
128 | goto error; | ||
129 | } | ||
130 | if (result < sizeof(*descr)) { | ||
131 | dev_err(dev, "rpipe %u: sent short descriptor " | ||
132 | "(%zd vs %zd bytes required)\n", | ||
133 | index, result, sizeof(*descr)); | ||
134 | result = -EINVAL; | ||
135 | goto error; | ||
136 | } | ||
137 | result = 0; | ||
138 | |||
139 | error: | ||
140 | return result; | ||
141 | |||
142 | } | ||
143 | |||
144 | static void rpipe_init(struct wa_rpipe *rpipe) | ||
145 | { | ||
146 | kref_init(&rpipe->refcnt); | ||
147 | spin_lock_init(&rpipe->seg_lock); | ||
148 | INIT_LIST_HEAD(&rpipe->seg_list); | ||
149 | } | ||
150 | |||
151 | static unsigned rpipe_get_idx(struct wahc *wa, unsigned rpipe_idx) | ||
152 | { | ||
153 | unsigned long flags; | ||
154 | |||
155 | spin_lock_irqsave(&wa->rpipe_bm_lock, flags); | ||
156 | rpipe_idx = find_next_zero_bit(wa->rpipe_bm, wa->rpipes, rpipe_idx); | ||
157 | if (rpipe_idx < wa->rpipes) | ||
158 | set_bit(rpipe_idx, wa->rpipe_bm); | ||
159 | spin_unlock_irqrestore(&wa->rpipe_bm_lock, flags); | ||
160 | |||
161 | return rpipe_idx; | ||
162 | } | ||
163 | |||
164 | static void rpipe_put_idx(struct wahc *wa, unsigned rpipe_idx) | ||
165 | { | ||
166 | unsigned long flags; | ||
167 | |||
168 | spin_lock_irqsave(&wa->rpipe_bm_lock, flags); | ||
169 | clear_bit(rpipe_idx, wa->rpipe_bm); | ||
170 | spin_unlock_irqrestore(&wa->rpipe_bm_lock, flags); | ||
171 | } | ||
172 | |||
173 | void rpipe_destroy(struct kref *_rpipe) | ||
174 | { | ||
175 | struct wa_rpipe *rpipe = container_of(_rpipe, struct wa_rpipe, refcnt); | ||
176 | u8 index = le16_to_cpu(rpipe->descr.wRPipeIndex); | ||
177 | d_fnstart(1, NULL, "(rpipe %p %u)\n", rpipe, index); | ||
178 | if (rpipe->ep) | ||
179 | rpipe->ep->hcpriv = NULL; | ||
180 | rpipe_put_idx(rpipe->wa, index); | ||
181 | wa_put(rpipe->wa); | ||
182 | kfree(rpipe); | ||
183 | d_fnend(1, NULL, "(rpipe %p %u)\n", rpipe, index); | ||
184 | } | ||
185 | EXPORT_SYMBOL_GPL(rpipe_destroy); | ||
186 | |||
187 | /* | ||
188 | * Locate an idle rpipe, create an structure for it and return it | ||
189 | * | ||
190 | * @wa is referenced and unlocked | ||
191 | * @crs enum rpipe_attr, required endpoint characteristics | ||
192 | * | ||
193 | * The rpipe can be used only sequentially (not in parallel). | ||
194 | * | ||
195 | * The rpipe is moved into the "ready" state. | ||
196 | */ | ||
197 | static int rpipe_get_idle(struct wa_rpipe **prpipe, struct wahc *wa, u8 crs, | ||
198 | gfp_t gfp) | ||
199 | { | ||
200 | int result; | ||
201 | unsigned rpipe_idx; | ||
202 | struct wa_rpipe *rpipe; | ||
203 | struct device *dev = &wa->usb_iface->dev; | ||
204 | |||
205 | d_fnstart(3, dev, "(wa %p crs 0x%02x)\n", wa, crs); | ||
206 | rpipe = kzalloc(sizeof(*rpipe), gfp); | ||
207 | if (rpipe == NULL) | ||
208 | return -ENOMEM; | ||
209 | rpipe_init(rpipe); | ||
210 | |||
211 | /* Look for an idle pipe */ | ||
212 | for (rpipe_idx = 0; rpipe_idx < wa->rpipes; rpipe_idx++) { | ||
213 | rpipe_idx = rpipe_get_idx(wa, rpipe_idx); | ||
214 | if (rpipe_idx >= wa->rpipes) /* no more pipes :( */ | ||
215 | break; | ||
216 | result = __rpipe_get_descr(wa, &rpipe->descr, rpipe_idx); | ||
217 | if (result < 0) | ||
218 | dev_err(dev, "Can't get descriptor for rpipe %u: %d\n", | ||
219 | rpipe_idx, result); | ||
220 | else if ((rpipe->descr.bmCharacteristics & crs) != 0) | ||
221 | goto found; | ||
222 | rpipe_put_idx(wa, rpipe_idx); | ||
223 | } | ||
224 | *prpipe = NULL; | ||
225 | kfree(rpipe); | ||
226 | d_fnend(3, dev, "(wa %p crs 0x%02x) = -ENXIO\n", wa, crs); | ||
227 | return -ENXIO; | ||
228 | |||
229 | found: | ||
230 | set_bit(rpipe_idx, wa->rpipe_bm); | ||
231 | rpipe->wa = wa_get(wa); | ||
232 | *prpipe = rpipe; | ||
233 | d_fnstart(3, dev, "(wa %p crs 0x%02x) = 0\n", wa, crs); | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static int __rpipe_reset(struct wahc *wa, unsigned index) | ||
238 | { | ||
239 | int result; | ||
240 | struct device *dev = &wa->usb_iface->dev; | ||
241 | |||
242 | d_printf(1, dev, "rpipe %u: reset\n", index); | ||
243 | result = usb_control_msg( | ||
244 | wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
245 | USB_REQ_RPIPE_RESET, | ||
246 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE, | ||
247 | 0, index, NULL, 0, 1000 /* FIXME: arbitrary */); | ||
248 | if (result < 0) | ||
249 | dev_err(dev, "rpipe %u: reset failed: %d\n", | ||
250 | index, result); | ||
251 | return result; | ||
252 | } | ||
253 | |||
254 | /* | ||
255 | * Fake companion descriptor for ep0 | ||
256 | * | ||
257 | * See WUSB1.0[7.4.4], most of this is zero for bulk/int/ctl | ||
258 | */ | ||
259 | static struct usb_wireless_ep_comp_descriptor epc0 = { | ||
260 | .bLength = sizeof(epc0), | ||
261 | .bDescriptorType = USB_DT_WIRELESS_ENDPOINT_COMP, | ||
262 | /* .bMaxBurst = 1, */ | ||
263 | .bMaxSequence = 31, | ||
264 | }; | ||
265 | |||
266 | /* | ||
267 | * Look for EP companion descriptor | ||
268 | * | ||
269 | * Get there, look for Inara in the endpoint's extra descriptors | ||
270 | */ | ||
271 | static struct usb_wireless_ep_comp_descriptor *rpipe_epc_find( | ||
272 | struct device *dev, struct usb_host_endpoint *ep) | ||
273 | { | ||
274 | void *itr; | ||
275 | size_t itr_size; | ||
276 | struct usb_descriptor_header *hdr; | ||
277 | struct usb_wireless_ep_comp_descriptor *epcd; | ||
278 | |||
279 | d_fnstart(3, dev, "(ep %p)\n", ep); | ||
280 | if (ep->desc.bEndpointAddress == 0) { | ||
281 | epcd = &epc0; | ||
282 | goto out; | ||
283 | } | ||
284 | itr = ep->extra; | ||
285 | itr_size = ep->extralen; | ||
286 | epcd = NULL; | ||
287 | while (itr_size > 0) { | ||
288 | if (itr_size < sizeof(*hdr)) { | ||
289 | dev_err(dev, "HW Bug? ep 0x%02x: extra descriptors " | ||
290 | "at offset %zu: only %zu bytes left\n", | ||
291 | ep->desc.bEndpointAddress, | ||
292 | itr - (void *) ep->extra, itr_size); | ||
293 | break; | ||
294 | } | ||
295 | hdr = itr; | ||
296 | if (hdr->bDescriptorType == USB_DT_WIRELESS_ENDPOINT_COMP) { | ||
297 | epcd = itr; | ||
298 | break; | ||
299 | } | ||
300 | if (hdr->bLength > itr_size) { | ||
301 | dev_err(dev, "HW Bug? ep 0x%02x: extra descriptor " | ||
302 | "at offset %zu (type 0x%02x) " | ||
303 | "length %d but only %zu bytes left\n", | ||
304 | ep->desc.bEndpointAddress, | ||
305 | itr - (void *) ep->extra, hdr->bDescriptorType, | ||
306 | hdr->bLength, itr_size); | ||
307 | break; | ||
308 | } | ||
309 | itr += hdr->bLength; | ||
310 | itr_size -= hdr->bDescriptorType; | ||
311 | } | ||
312 | out: | ||
313 | d_fnend(3, dev, "(ep %p) = %p\n", ep, epcd); | ||
314 | return epcd; | ||
315 | } | ||
316 | |||
317 | /* | ||
318 | * Aim an rpipe to its device & endpoint destination | ||
319 | * | ||
320 | * Make sure we change the address to unauthenticathed if the device | ||
321 | * is WUSB and it is not authenticated. | ||
322 | */ | ||
323 | static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa, | ||
324 | struct usb_host_endpoint *ep, struct urb *urb, gfp_t gfp) | ||
325 | { | ||
326 | int result = -ENOMSG; /* better code for lack of companion? */ | ||
327 | struct device *dev = &wa->usb_iface->dev; | ||
328 | struct usb_device *usb_dev = urb->dev; | ||
329 | struct usb_wireless_ep_comp_descriptor *epcd; | ||
330 | u8 unauth; | ||
331 | |||
332 | d_fnstart(3, dev, "(rpipe %p wa %p ep %p, urb %p)\n", | ||
333 | rpipe, wa, ep, urb); | ||
334 | epcd = rpipe_epc_find(dev, ep); | ||
335 | if (epcd == NULL) { | ||
336 | dev_err(dev, "ep 0x%02x: can't find companion descriptor\n", | ||
337 | ep->desc.bEndpointAddress); | ||
338 | goto error; | ||
339 | } | ||
340 | unauth = usb_dev->wusb && !usb_dev->authenticated ? 0x80 : 0; | ||
341 | __rpipe_reset(wa, le16_to_cpu(rpipe->descr.wRPipeIndex)); | ||
342 | atomic_set(&rpipe->segs_available, le16_to_cpu(rpipe->descr.wRequests)); | ||
343 | /* FIXME: block allocation system; request with queuing and timeout */ | ||
344 | /* FIXME: compute so seg_size > ep->maxpktsize */ | ||
345 | rpipe->descr.wBlocks = cpu_to_le16(16); /* given */ | ||
346 | /* ep0 maxpktsize is 0x200 (WUSB1.0[4.8.1]) */ | ||
347 | rpipe->descr.wMaxPacketSize = cpu_to_le16(ep->desc.wMaxPacketSize); | ||
348 | rpipe->descr.bHSHubAddress = 0; /* reserved: zero */ | ||
349 | rpipe->descr.bHSHubPort = wusb_port_no_to_idx(urb->dev->portnum); | ||
350 | /* FIXME: use maximum speed as supported or recommended by device */ | ||
351 | rpipe->descr.bSpeed = usb_pipeendpoint(urb->pipe) == 0 ? | ||
352 | UWB_PHY_RATE_53 : UWB_PHY_RATE_200; | ||
353 | d_printf(2, dev, "addr %u (0x%02x) rpipe #%u ep# %u speed %d\n", | ||
354 | urb->dev->devnum, urb->dev->devnum | unauth, | ||
355 | le16_to_cpu(rpipe->descr.wRPipeIndex), | ||
356 | usb_pipeendpoint(urb->pipe), rpipe->descr.bSpeed); | ||
357 | /* see security.c:wusb_update_address() */ | ||
358 | if (unlikely(urb->dev->devnum == 0x80)) | ||
359 | rpipe->descr.bDeviceAddress = 0; | ||
360 | else | ||
361 | rpipe->descr.bDeviceAddress = urb->dev->devnum | unauth; | ||
362 | rpipe->descr.bEndpointAddress = ep->desc.bEndpointAddress; | ||
363 | /* FIXME: bDataSequence */ | ||
364 | rpipe->descr.bDataSequence = 0; | ||
365 | /* FIXME: dwCurrentWindow */ | ||
366 | rpipe->descr.dwCurrentWindow = cpu_to_le32(1); | ||
367 | /* FIXME: bMaxDataSequence */ | ||
368 | rpipe->descr.bMaxDataSequence = epcd->bMaxSequence - 1; | ||
369 | rpipe->descr.bInterval = ep->desc.bInterval; | ||
370 | /* FIXME: bOverTheAirInterval */ | ||
371 | rpipe->descr.bOverTheAirInterval = 0; /* 0 if not isoc */ | ||
372 | /* FIXME: xmit power & preamble blah blah */ | ||
373 | rpipe->descr.bmAttribute = ep->desc.bmAttributes & 0x03; | ||
374 | /* rpipe->descr.bmCharacteristics RO */ | ||
375 | /* FIXME: bmRetryOptions */ | ||
376 | rpipe->descr.bmRetryOptions = 15; | ||
377 | /* FIXME: use for assessing link quality? */ | ||
378 | rpipe->descr.wNumTransactionErrors = 0; | ||
379 | result = __rpipe_set_descr(wa, &rpipe->descr, | ||
380 | le16_to_cpu(rpipe->descr.wRPipeIndex)); | ||
381 | if (result < 0) { | ||
382 | dev_err(dev, "Cannot aim rpipe: %d\n", result); | ||
383 | goto error; | ||
384 | } | ||
385 | result = 0; | ||
386 | error: | ||
387 | d_fnend(3, dev, "(rpipe %p wa %p ep %p urb %p) = %d\n", | ||
388 | rpipe, wa, ep, urb, result); | ||
389 | return result; | ||
390 | } | ||
391 | |||
392 | /* | ||
393 | * Check an aimed rpipe to make sure it points to where we want | ||
394 | * | ||
395 | * We use bit 19 of the Linux USB pipe bitmap for unauth vs auth | ||
396 | * space; when it is like that, we or 0x80 to make an unauth address. | ||
397 | */ | ||
398 | static int rpipe_check_aim(const struct wa_rpipe *rpipe, const struct wahc *wa, | ||
399 | const struct usb_host_endpoint *ep, | ||
400 | const struct urb *urb, gfp_t gfp) | ||
401 | { | ||
402 | int result = 0; /* better code for lack of companion? */ | ||
403 | struct device *dev = &wa->usb_iface->dev; | ||
404 | struct usb_device *usb_dev = urb->dev; | ||
405 | u8 unauth = (usb_dev->wusb && !usb_dev->authenticated) ? 0x80 : 0; | ||
406 | u8 portnum = wusb_port_no_to_idx(urb->dev->portnum); | ||
407 | |||
408 | d_fnstart(3, dev, "(rpipe %p wa %p ep %p, urb %p)\n", | ||
409 | rpipe, wa, ep, urb); | ||
410 | #define AIM_CHECK(rdf, val, text) \ | ||
411 | do { \ | ||
412 | if (rpipe->descr.rdf != (val)) { \ | ||
413 | dev_err(dev, \ | ||
414 | "rpipe aim discrepancy: " #rdf " " text "\n", \ | ||
415 | rpipe->descr.rdf, (val)); \ | ||
416 | result = -EINVAL; \ | ||
417 | WARN_ON(1); \ | ||
418 | } \ | ||
419 | } while (0) | ||
420 | AIM_CHECK(wMaxPacketSize, cpu_to_le16(ep->desc.wMaxPacketSize), | ||
421 | "(%u vs %u)"); | ||
422 | AIM_CHECK(bHSHubPort, portnum, "(%u vs %u)"); | ||
423 | AIM_CHECK(bSpeed, usb_pipeendpoint(urb->pipe) == 0 ? | ||
424 | UWB_PHY_RATE_53 : UWB_PHY_RATE_200, | ||
425 | "(%u vs %u)"); | ||
426 | AIM_CHECK(bDeviceAddress, urb->dev->devnum | unauth, "(%u vs %u)"); | ||
427 | AIM_CHECK(bEndpointAddress, ep->desc.bEndpointAddress, "(%u vs %u)"); | ||
428 | AIM_CHECK(bInterval, ep->desc.bInterval, "(%u vs %u)"); | ||
429 | AIM_CHECK(bmAttribute, ep->desc.bmAttributes & 0x03, "(%u vs %u)"); | ||
430 | #undef AIM_CHECK | ||
431 | return result; | ||
432 | } | ||
433 | |||
434 | #ifndef CONFIG_BUG | ||
435 | #define CONFIG_BUG 0 | ||
436 | #endif | ||
437 | |||
438 | /* | ||
439 | * Make sure there is an rpipe allocated for an endpoint | ||
440 | * | ||
441 | * If already allocated, we just refcount it; if not, we get an | ||
442 | * idle one, aim it to the right location and take it. | ||
443 | * | ||
444 | * Attaches to ep->hcpriv and rpipe->ep to ep. | ||
445 | */ | ||
446 | int rpipe_get_by_ep(struct wahc *wa, struct usb_host_endpoint *ep, | ||
447 | struct urb *urb, gfp_t gfp) | ||
448 | { | ||
449 | int result = 0; | ||
450 | struct device *dev = &wa->usb_iface->dev; | ||
451 | struct wa_rpipe *rpipe; | ||
452 | u8 eptype; | ||
453 | |||
454 | d_fnstart(3, dev, "(wa %p ep %p urb %p gfp 0x%08x)\n", wa, ep, urb, | ||
455 | gfp); | ||
456 | mutex_lock(&wa->rpipe_mutex); | ||
457 | rpipe = ep->hcpriv; | ||
458 | if (rpipe != NULL) { | ||
459 | if (CONFIG_BUG == 1) { | ||
460 | result = rpipe_check_aim(rpipe, wa, ep, urb, gfp); | ||
461 | if (result < 0) | ||
462 | goto error; | ||
463 | } | ||
464 | __rpipe_get(rpipe); | ||
465 | d_printf(2, dev, "ep 0x%02x: reusing rpipe %u\n", | ||
466 | ep->desc.bEndpointAddress, | ||
467 | le16_to_cpu(rpipe->descr.wRPipeIndex)); | ||
468 | } else { | ||
469 | /* hmm, assign idle rpipe, aim it */ | ||
470 | result = -ENOBUFS; | ||
471 | eptype = ep->desc.bmAttributes & 0x03; | ||
472 | result = rpipe_get_idle(&rpipe, wa, 1 << eptype, gfp); | ||
473 | if (result < 0) | ||
474 | goto error; | ||
475 | result = rpipe_aim(rpipe, wa, ep, urb, gfp); | ||
476 | if (result < 0) { | ||
477 | rpipe_put(rpipe); | ||
478 | goto error; | ||
479 | } | ||
480 | ep->hcpriv = rpipe; | ||
481 | rpipe->ep = ep; | ||
482 | __rpipe_get(rpipe); /* for caching into ep->hcpriv */ | ||
483 | d_printf(2, dev, "ep 0x%02x: using rpipe %u\n", | ||
484 | ep->desc.bEndpointAddress, | ||
485 | le16_to_cpu(rpipe->descr.wRPipeIndex)); | ||
486 | } | ||
487 | d_dump(4, dev, &rpipe->descr, sizeof(rpipe->descr)); | ||
488 | error: | ||
489 | mutex_unlock(&wa->rpipe_mutex); | ||
490 | d_fnend(3, dev, "(wa %p ep %p urb %p gfp 0x%08x)\n", wa, ep, urb, gfp); | ||
491 | return result; | ||
492 | } | ||
493 | |||
494 | /* | ||
495 | * Allocate the bitmap for each rpipe. | ||
496 | */ | ||
497 | int wa_rpipes_create(struct wahc *wa) | ||
498 | { | ||
499 | wa->rpipes = wa->wa_descr->wNumRPipes; | ||
500 | wa->rpipe_bm = kzalloc(BITS_TO_LONGS(wa->rpipes)*sizeof(unsigned long), | ||
501 | GFP_KERNEL); | ||
502 | if (wa->rpipe_bm == NULL) | ||
503 | return -ENOMEM; | ||
504 | return 0; | ||
505 | } | ||
506 | |||
507 | void wa_rpipes_destroy(struct wahc *wa) | ||
508 | { | ||
509 | struct device *dev = &wa->usb_iface->dev; | ||
510 | d_fnstart(3, dev, "(wa %p)\n", wa); | ||
511 | if (!bitmap_empty(wa->rpipe_bm, wa->rpipes)) { | ||
512 | char buf[256]; | ||
513 | WARN_ON(1); | ||
514 | bitmap_scnprintf(buf, sizeof(buf), wa->rpipe_bm, wa->rpipes); | ||
515 | dev_err(dev, "BUG: pipes not released on exit: %s\n", buf); | ||
516 | } | ||
517 | kfree(wa->rpipe_bm); | ||
518 | d_fnend(3, dev, "(wa %p)\n", wa); | ||
519 | } | ||
520 | |||
521 | /* | ||
522 | * Release resources allocated for an endpoint | ||
523 | * | ||
524 | * If there is an associated rpipe to this endpoint, Abort any pending | ||
525 | * transfers and put it. If the rpipe ends up being destroyed, | ||
526 | * __rpipe_destroy() will cleanup ep->hcpriv. | ||
527 | * | ||
528 | * This is called before calling hcd->stop(), so you don't need to do | ||
529 | * anything else in there. | ||
530 | */ | ||
531 | void rpipe_ep_disable(struct wahc *wa, struct usb_host_endpoint *ep) | ||
532 | { | ||
533 | struct device *dev = &wa->usb_iface->dev; | ||
534 | struct wa_rpipe *rpipe; | ||
535 | d_fnstart(2, dev, "(wa %p ep %p)\n", wa, ep); | ||
536 | mutex_lock(&wa->rpipe_mutex); | ||
537 | rpipe = ep->hcpriv; | ||
538 | if (rpipe != NULL) { | ||
539 | unsigned rc = atomic_read(&rpipe->refcnt.refcount); | ||
540 | int result; | ||
541 | u16 index = le16_to_cpu(rpipe->descr.wRPipeIndex); | ||
542 | |||
543 | if (rc != 1) | ||
544 | d_printf(1, dev, "(wa %p ep %p) rpipe %p refcnt %u\n", | ||
545 | wa, ep, rpipe, rc); | ||
546 | |||
547 | d_printf(1, dev, "rpipe %u: abort\n", index); | ||
548 | result = usb_control_msg( | ||
549 | wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0), | ||
550 | USB_REQ_RPIPE_ABORT, | ||
551 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE, | ||
552 | 0, index, NULL, 0, 1000 /* FIXME: arbitrary */); | ||
553 | if (result < 0 && result != -ENODEV /* dev is gone */) | ||
554 | d_printf(1, dev, "(wa %p rpipe %u): abort failed: %d\n", | ||
555 | wa, index, result); | ||
556 | rpipe_put(rpipe); | ||
557 | } | ||
558 | mutex_unlock(&wa->rpipe_mutex); | ||
559 | d_fnend(2, dev, "(wa %p ep %p)\n", wa, ep); | ||
560 | return; | ||
561 | } | ||
562 | EXPORT_SYMBOL_GPL(rpipe_ep_disable); | ||