usbdi.c revision 1.26 1 /* $NetBSD: usbdi.c,v 1.26 1999/07/06 07:12:03 augustss Exp $ */
2
3 /*
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (augustss (at) carlstedt.se) at
9 * Carlstedt Research & Technology.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #if defined(__NetBSD__)
44 #include <sys/device.h>
45 #else
46 #include <sys/module.h>
47 #include <sys/bus.h>
48 #include <sys/conf.h>
49 #endif
50 #include <sys/malloc.h>
51 #include <sys/proc.h>
52
53 #include <dev/usb/usb.h>
54
55 #include <dev/usb/usbdi.h>
56 #include <dev/usb/usbdi_util.h>
57 #include <dev/usb/usbdivar.h>
58
59 #if defined(__FreeBSD__)
60 #include "usb_if.h"
61 #endif
62
63 #ifdef USB_DEBUG
64 #define DPRINTF(x) if (usbdebug) printf x
65 #define DPRINTFN(n,x) if (usbdebug>(n)) printf x
66 extern int usbdebug;
67 #else
68 #define DPRINTF(x)
69 #define DPRINTFN(n,x)
70 #endif
71
72 static usbd_status usbd_ar_pipe __P((usbd_pipe_handle pipe));
73 static void usbd_transfer_cb __P((usbd_request_handle reqh));
74 static void usbd_sync_transfer_cb __P((usbd_request_handle reqh));
75 static usbd_status usbd_do_transfer __P((usbd_request_handle reqh));
76 void usbd_do_request_async_cb
77 __P((usbd_request_handle, usbd_private_handle, usbd_status));
78
79 static SIMPLEQ_HEAD(, usbd_request) usbd_free_requests;
80
81 #if defined(__FreeBSD__)
82 #define USB_CDEV_MAJOR 108
83
84 extern struct cdevsw usb_cdevsw;
85 #endif
86
87 usbd_status
88 usbd_open_pipe(iface, address, flags, pipe)
89 usbd_interface_handle iface;
90 u_int8_t address;
91 u_int8_t flags;
92 usbd_pipe_handle *pipe;
93 {
94 usbd_pipe_handle p;
95 struct usbd_endpoint *ep;
96 usbd_status r;
97 int i;
98
99 for (i = 0; i < iface->idesc->bNumEndpoints; i++) {
100 ep = &iface->endpoints[i];
101 if (ep->edesc->bEndpointAddress == address)
102 goto found;
103 }
104 return (USBD_BAD_ADDRESS);
105 found:
106 if ((flags & USBD_EXCLUSIVE_USE) &&
107 ep->refcnt != 0)
108 return (USBD_IN_USE);
109 r = usbd_setup_pipe(iface->device, iface, ep, &p);
110 if (r != USBD_NORMAL_COMPLETION)
111 return (r);
112 LIST_INSERT_HEAD(&iface->pipes, p, next);
113 *pipe = p;
114 return (USBD_NORMAL_COMPLETION);
115 }
116
117 usbd_status
118 usbd_open_pipe_intr(iface, address, flags, pipe, priv, buffer, length, cb)
119 usbd_interface_handle iface;
120 u_int8_t address;
121 u_int8_t flags;
122 usbd_pipe_handle *pipe;
123 usbd_private_handle priv;
124 void *buffer;
125 u_int32_t length;
126 usbd_callback cb;
127 {
128 usbd_status r;
129 usbd_request_handle reqh;
130 usbd_pipe_handle ipipe;
131
132 reqh = usbd_alloc_request();
133 if (reqh == 0)
134 return (USBD_NOMEM);
135 r = usbd_open_pipe(iface, address, USBD_EXCLUSIVE_USE, &ipipe);
136 if (r != USBD_NORMAL_COMPLETION)
137 goto bad1;
138 r = usbd_setup_request(reqh, ipipe, priv, buffer, length,
139 USBD_XFER_IN | flags, USBD_NO_TIMEOUT, cb);
140 if (r != USBD_NORMAL_COMPLETION)
141 goto bad2;
142 ipipe->intrreqh = reqh;
143 ipipe->repeat = 1;
144 r = usbd_transfer(reqh);
145 *pipe = ipipe;
146 if (r != USBD_IN_PROGRESS)
147 goto bad3;
148 return (USBD_NORMAL_COMPLETION);
149
150 bad3:
151 ipipe->intrreqh = 0;
152 ipipe->repeat = 0;
153 bad2:
154 usbd_close_pipe(ipipe);
155 bad1:
156 usbd_free_request(reqh);
157 return r;
158 }
159
160 usbd_status
161 usbd_open_pipe_iso(iface, address, flags, pipe, priv, bufsize, nbuf, cb)
162 usbd_interface_handle iface;
163 u_int8_t address;
164 u_int8_t flags;
165 usbd_pipe_handle *pipe;
166 usbd_private_handle priv;
167 u_int32_t bufsize;
168 u_int32_t nbuf;
169 usbd_callback cb;
170 {
171 usbd_status r;
172 usbd_pipe_handle p;
173
174 r = usbd_open_pipe(iface, address, USBD_EXCLUSIVE_USE, &p);
175 if (r != USBD_NORMAL_COMPLETION)
176 return (r);
177 if (!p->methods->isobuf) {
178 usbd_close_pipe(p);
179 return (USBD_INVAL);
180 }
181 r = p->methods->isobuf(p, bufsize, nbuf);
182 if (r != USBD_NORMAL_COMPLETION) {
183 usbd_close_pipe(p);
184 return (r);
185 }
186 *pipe = p;
187 return r;
188 }
189
190 usbd_status
191 usbd_close_pipe(pipe)
192 usbd_pipe_handle pipe;
193 {
194 #ifdef DIAGNOSTIC
195 if (pipe == 0) {
196 printf("usbd_close_pipe: pipe==NULL\n");
197 return (USBD_NORMAL_COMPLETION);
198 }
199 #endif
200
201 if (--pipe->refcnt != 0)
202 return (USBD_NORMAL_COMPLETION);
203 if (SIMPLEQ_FIRST(&pipe->queue) != 0)
204 return (USBD_PENDING_REQUESTS);
205 LIST_REMOVE(pipe, next);
206 pipe->endpoint->refcnt--;
207 pipe->methods->close(pipe);
208 if (pipe->intrreqh)
209 usbd_free_request(pipe->intrreqh);
210 free(pipe, M_USB);
211 return (USBD_NORMAL_COMPLETION);
212 }
213
214 usbd_status
215 usbd_transfer(reqh)
216 usbd_request_handle reqh;
217 {
218 reqh->xfercb = usbd_transfer_cb;
219 return (usbd_do_transfer(reqh));
220 }
221
222 static usbd_status
223 usbd_do_transfer(reqh)
224 usbd_request_handle reqh;
225 {
226 usbd_pipe_handle pipe = reqh->pipe;
227
228 DPRINTFN(10,("usbd_do_transfer: reqh=%p\n", reqh));
229 reqh->done = 0;
230 return (pipe->methods->transfer(reqh));
231 }
232
233 usbd_request_handle
234 usbd_alloc_request()
235 {
236 usbd_request_handle reqh;
237
238 reqh = SIMPLEQ_FIRST(&usbd_free_requests);
239 if (reqh)
240 SIMPLEQ_REMOVE_HEAD(&usbd_free_requests, reqh, next);
241 else
242 reqh = malloc(sizeof(*reqh), M_USB, M_NOWAIT);
243 if (!reqh)
244 return (0);
245 memset(reqh, 0, sizeof *reqh);
246 DPRINTFN(1,("usbd_alloc_request() = %p\n", reqh));
247 return (reqh);
248 }
249
250 usbd_status
251 usbd_free_request(reqh)
252 usbd_request_handle reqh;
253 {
254 DPRINTFN(1,("usbd_free_request: %p\n", reqh));
255 SIMPLEQ_INSERT_HEAD(&usbd_free_requests, reqh, next);
256 return (USBD_NORMAL_COMPLETION);
257 }
258
259 usbd_status
260 usbd_setup_request(reqh, pipe, priv, buffer, length, flags, timeout, callback)
261 usbd_request_handle reqh;
262 usbd_pipe_handle pipe;
263 usbd_private_handle priv;
264 void *buffer;
265 u_int32_t length;
266 u_int16_t flags;
267 u_int32_t timeout;
268 void (*callback) __P((usbd_request_handle,
269 usbd_private_handle,
270 usbd_status));
271 {
272 reqh->pipe = pipe;
273 reqh->priv = priv;
274 reqh->buffer = buffer;
275 reqh->length = length;
276 reqh->actlen = 0;
277 reqh->flags = flags;
278 reqh->timeout = timeout;
279 reqh->status = USBD_NOT_STARTED;
280 reqh->callback = callback;
281 reqh->retries = 1;
282 reqh->isreq = 0;
283 return (USBD_NORMAL_COMPLETION);
284 }
285
286 usbd_status
287 usbd_setup_default_request(reqh, dev, priv, timeout, req, buffer,
288 length, flags, callback)
289 usbd_request_handle reqh;
290 usbd_device_handle dev;
291 usbd_private_handle priv;
292 u_int32_t timeout;
293 usb_device_request_t *req;
294 void *buffer;
295 u_int32_t length;
296 u_int16_t flags;
297 void (*callback) __P((usbd_request_handle,
298 usbd_private_handle,
299 usbd_status));
300 {
301 reqh->pipe = dev->default_pipe;
302 reqh->priv = priv;
303 reqh->buffer = buffer;
304 reqh->length = length;
305 reqh->actlen = 0;
306 reqh->flags = flags;
307 reqh->timeout = timeout;
308 reqh->status = USBD_NOT_STARTED;
309 reqh->callback = callback;
310 reqh->request = *req;
311 reqh->retries = 1;
312 reqh->isreq = 1;
313 return (USBD_NORMAL_COMPLETION);
314 }
315
316 usbd_status
317 usbd_get_request_status(reqh, priv, buffer, count, status)
318 usbd_request_handle reqh;
319 usbd_private_handle *priv;
320 void **buffer;
321 u_int32_t *count;
322 usbd_status *status;
323 {
324 *priv = reqh->priv;
325 *buffer = reqh->buffer;
326 *count = reqh->actlen;
327 *status = reqh->status;
328 return (USBD_NORMAL_COMPLETION);
329 }
330
331 usb_config_descriptor_t *
332 usbd_get_config_descriptor(dev)
333 usbd_device_handle dev;
334 {
335 return (dev->cdesc);
336 }
337
338 usb_interface_descriptor_t *
339 usbd_get_interface_descriptor(iface)
340 usbd_interface_handle iface;
341 {
342 return (iface->idesc);
343 }
344
345 usb_device_descriptor_t *
346 usbd_get_device_descriptor(dev)
347 usbd_device_handle dev;
348 {
349 return (&dev->ddesc);
350 }
351
352 usb_endpoint_descriptor_t *
353 usbd_interface2endpoint_descriptor(iface, index)
354 usbd_interface_handle iface;
355 u_int8_t index;
356 {
357 if (index >= iface->idesc->bNumEndpoints)
358 return (0);
359 return (iface->endpoints[index].edesc);
360 }
361
362 usbd_status
363 usbd_abort_pipe(pipe)
364 usbd_pipe_handle pipe;
365 {
366 usbd_status r;
367 int s;
368
369 #ifdef DIAGNOSTIC
370 if (pipe == 0) {
371 printf("usbd_close_pipe: pipe==NULL\n");
372 return (USBD_NORMAL_COMPLETION);
373 }
374 #endif
375 s = splusb();
376 r = usbd_ar_pipe(pipe);
377 splx(s);
378 return (r);
379 }
380
381 usbd_status
382 usbd_clear_endpoint_stall(pipe)
383 usbd_pipe_handle pipe;
384 {
385 usbd_device_handle dev = pipe->device;
386 usb_device_request_t req;
387 usbd_status r;
388
389 DPRINTFN(8, ("usbd_clear_endpoint_stall\n"));
390 req.bmRequestType = UT_WRITE_ENDPOINT;
391 req.bRequest = UR_CLEAR_FEATURE;
392 USETW(req.wValue, UF_ENDPOINT_HALT);
393 USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);
394 USETW(req.wLength, 0);
395 r = usbd_do_request(dev, &req, 0);
396 #if 0
397 XXX should we do this?
398 if (r == USBD_NORMAL_COMPLETION) {
399 pipe->state = USBD_PIPE_ACTIVE;
400 /* XXX activate pipe */
401 }
402 #endif
403 return (r);
404 }
405
406 usbd_status
407 usbd_clear_endpoint_stall_async(pipe)
408 usbd_pipe_handle pipe;
409 {
410 usbd_device_handle dev = pipe->device;
411 usb_device_request_t req;
412 usbd_status r;
413
414 req.bmRequestType = UT_WRITE_ENDPOINT;
415 req.bRequest = UR_CLEAR_FEATURE;
416 USETW(req.wValue, UF_ENDPOINT_HALT);
417 USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);
418 USETW(req.wLength, 0);
419 r = usbd_do_request_async(dev, &req, 0);
420 return (r);
421 }
422
423 usbd_status
424 usbd_endpoint_count(iface, count)
425 usbd_interface_handle iface;
426 u_int8_t *count;
427 {
428 *count = iface->idesc->bNumEndpoints;
429 return (USBD_NORMAL_COMPLETION);
430 }
431
432 usbd_status
433 usbd_interface_count(dev, count)
434 usbd_device_handle dev;
435 u_int8_t *count;
436 {
437 if (!dev->cdesc)
438 return (USBD_NOT_CONFIGURED);
439 *count = dev->cdesc->bNumInterface;
440 return (USBD_NORMAL_COMPLETION);
441 }
442
443 usbd_status
444 usbd_interface2device_handle(iface, dev)
445 usbd_interface_handle iface;
446 usbd_device_handle *dev;
447 {
448 *dev = iface->device;
449 return (USBD_NORMAL_COMPLETION);
450 }
451
452 usbd_status
453 usbd_device2interface_handle(dev, ifaceno, iface)
454 usbd_device_handle dev;
455 u_int8_t ifaceno;
456 usbd_interface_handle *iface;
457 {
458 if (!dev->cdesc)
459 return (USBD_NOT_CONFIGURED);
460 if (ifaceno >= dev->cdesc->bNumInterface)
461 return (USBD_INVAL);
462 *iface = &dev->ifaces[ifaceno];
463 return (USBD_NORMAL_COMPLETION);
464 }
465
466 /* XXXX use altno */
467 usbd_status
468 usbd_set_interface(iface, altidx)
469 usbd_interface_handle iface;
470 int altidx;
471 {
472 usb_device_request_t req;
473 usbd_status r;
474
475 if (LIST_FIRST(&iface->pipes) != 0)
476 return (USBD_IN_USE);
477
478 if (iface->endpoints)
479 free(iface->endpoints, M_USB);
480 iface->endpoints = 0;
481 iface->idesc = 0;
482
483 r = usbd_fill_iface_data(iface->device, iface->index, altidx);
484 if (r != USBD_NORMAL_COMPLETION)
485 return (r);
486
487 req.bmRequestType = UT_WRITE_INTERFACE;
488 req.bRequest = UR_SET_INTERFACE;
489 USETW(req.wValue, iface->idesc->bAlternateSetting);
490 USETW(req.wIndex, iface->idesc->bInterfaceNumber);
491 USETW(req.wLength, 0);
492 return usbd_do_request(iface->device, &req, 0);
493 }
494
495 int
496 usbd_get_no_alts(cdesc, ifaceno)
497 usb_config_descriptor_t *cdesc;
498 int ifaceno;
499 {
500 char *p = (char *)cdesc;
501 char *end = p + UGETW(cdesc->wTotalLength);
502 usb_interface_descriptor_t *d;
503 int n;
504
505 for (n = 0; p < end; p += d->bLength) {
506 d = (usb_interface_descriptor_t *)p;
507 if (p + d->bLength <= end &&
508 d->bDescriptorType == UDESC_INTERFACE &&
509 d->bInterfaceNumber == ifaceno)
510 n++;
511 }
512 return (n);
513 }
514
515 int
516 usbd_get_interface_altindex(iface)
517 usbd_interface_handle iface;
518 {
519 return (iface->altindex);
520 }
521
522 usbd_status
523 usbd_get_interface(iface, aiface)
524 usbd_interface_handle iface;
525 u_int8_t *aiface;
526 {
527 usb_device_request_t req;
528
529 req.bmRequestType = UT_READ_INTERFACE;
530 req.bRequest = UR_GET_INTERFACE;
531 USETW(req.wValue, 0);
532 USETW(req.wIndex, iface->idesc->bInterfaceNumber);
533 USETW(req.wLength, 1);
534 return usbd_do_request(iface->device, &req, aiface);
535 }
536
537 /*** Internal routines ***/
538
539 /* Dequeue all pipe operations, called at splusb(). */
540 static usbd_status
541 usbd_ar_pipe(pipe)
542 usbd_pipe_handle pipe;
543 {
544 usbd_request_handle reqh;
545
546 #if 0
547 for (;;) {
548 reqh = SIMPLEQ_FIRST(&pipe->queue);
549 if (reqh == 0)
550 break;
551 SIMPLEQ_REMOVE_HEAD(&pipe->queue, reqh, next);
552 reqh->status = USBD_CANCELLED;
553 if (reqh->callback)
554 reqh->callback(reqh, reqh->priv, reqh->status);
555 }
556 #else
557 DPRINTFN(2,("usbd_ar_pipe: pipe=%p\n", pipe));
558 while ((reqh = SIMPLEQ_FIRST(&pipe->queue))) {
559 DPRINTFN(2,("usbd_ar_pipe: reqh=%p (methods=%p)\n",
560 pipe, pipe->methods));
561 pipe->methods->abort(reqh);
562 SIMPLEQ_REMOVE_HEAD(&pipe->queue, reqh, next);
563 }
564 #endif
565 return (USBD_NORMAL_COMPLETION);
566 }
567
568 static int usbd_global_init_done = 0;
569
570 void
571 usbd_init()
572 {
573 #if defined(__FreeBSD__)
574 dev_t dev;
575 #endif
576
577 if (!usbd_global_init_done) {
578 usbd_global_init_done = 1;
579 SIMPLEQ_INIT(&usbd_free_requests);
580
581 #if defined(__FreeBSD__)
582 dev = makedev(USB_CDEV_MAJOR, 0);
583 cdevsw_add(&dev, &usb_cdevsw, NULL);
584 #endif
585 }
586 }
587
588 static void
589 usbd_transfer_cb(reqh)
590 usbd_request_handle reqh;
591 {
592 usbd_pipe_handle pipe = reqh->pipe;
593
594 DPRINTFN(10, ("usbd_transfer_cb: reqh=%p\n", reqh));
595 /* Count completed transfers. */
596 #ifdef DIAGNOSTIC
597 if (!pipe)
598 printf("usbd_transfer_cb: pipe==0, reqh=%p\n", reqh);
599 else
600 #endif
601 ++pipe->device->bus->stats.requests
602 [pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE];
603
604 /* XXX check retry count */
605 reqh->done = 1;
606 if (reqh->status == USBD_NORMAL_COMPLETION &&
607 reqh->actlen < reqh->length &&
608 !(reqh->flags & USBD_SHORT_XFER_OK)) {
609 DPRINTFN(-1, ("usbd_transfer_cb: short xfer %d<%d (bytes)\n",
610 reqh->actlen, reqh->length));
611 reqh->status = USBD_SHORT_XFER;
612 }
613 if (reqh->callback)
614 reqh->callback(reqh, reqh->priv, reqh->status);
615 }
616
617 static void
618 usbd_sync_transfer_cb(reqh)
619 usbd_request_handle reqh;
620 {
621 DPRINTFN(10, ("usbd_sync_transfer_cb: reqh=%p\n", reqh));
622 usbd_transfer_cb(reqh);
623 if (!reqh->pipe->device->bus->use_polling)
624 wakeup(reqh);
625 }
626
627 /* Like usbd_transfer(), but waits for completion. */
628 usbd_status
629 usbd_sync_transfer(reqh)
630 usbd_request_handle reqh;
631 {
632 usbd_status r;
633 int s;
634
635 reqh->xfercb = usbd_sync_transfer_cb;
636 r = usbd_do_transfer(reqh);
637 if (r != USBD_IN_PROGRESS)
638 return (r);
639 s = splusb();
640 if (!reqh->done) {
641 if (reqh->pipe->device->bus->use_polling)
642 panic("usbd_sync_transfer: not done\n");
643 tsleep(reqh, PRIBIO, "usbsyn", 0);
644 }
645 splx(s);
646 return (reqh->status);
647 }
648
649 usbd_status
650 usbd_do_request(dev, req, data)
651 usbd_device_handle dev;
652 usb_device_request_t *req;
653 void *data;
654 {
655 return (usbd_do_request_flags(dev, req, data, 0, 0));
656 }
657
658 usbd_status
659 usbd_do_request_flags(dev, req, data, flags, actlen)
660 usbd_device_handle dev;
661 usb_device_request_t *req;
662 void *data;
663 u_int16_t flags;
664 int *actlen;
665 {
666 usbd_request_handle reqh;
667 usbd_status r;
668
669 #ifdef DIAGNOSTIC
670 if (!curproc) {
671 printf("usbd_do_request: not in process context\n");
672 return (USBD_XXX);
673 }
674 #endif
675
676 reqh = usbd_alloc_request();
677 if (reqh == 0)
678 return (USBD_NOMEM);
679 r = usbd_setup_default_request(
680 reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req, data,
681 UGETW(req->wLength), flags, 0);
682 if (r != USBD_NORMAL_COMPLETION)
683 goto bad;
684 r = usbd_sync_transfer(reqh);
685 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
686 if (reqh->actlen > reqh->length)
687 printf("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
688 "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
689 dev->address, reqh->request.bmRequestType,
690 reqh->request.bRequest, UGETW(reqh->request.wValue),
691 UGETW(reqh->request.wIndex),
692 UGETW(reqh->request.wLength),
693 reqh->length, reqh->actlen);
694 #endif
695 if (actlen)
696 *actlen = reqh->actlen;
697 if (r == USBD_STALLED) {
698 /*
699 * The control endpoint has stalled. Control endpoints
700 * should not halt, but some may do so anyway so clear
701 * any halt condition.
702 */
703 usb_device_request_t treq;
704 usb_status_t status;
705 u_int16_t s;
706 usbd_status nr;
707
708 treq.bmRequestType = UT_READ_ENDPOINT;
709 treq.bRequest = UR_GET_STATUS;
710 USETW(treq.wValue, 0);
711 USETW(treq.wIndex, 0);
712 USETW(treq.wLength, sizeof(usb_status_t));
713 nr = usbd_setup_default_request(
714 reqh, dev, 0, USBD_DEFAULT_TIMEOUT, &treq, &status,
715 sizeof(usb_status_t), 0, 0);
716 if (nr != USBD_NORMAL_COMPLETION)
717 goto bad;
718 nr = usbd_sync_transfer(reqh);
719 if (nr != USBD_NORMAL_COMPLETION)
720 goto bad;
721 s = UGETW(status.wStatus);
722 DPRINTF(("usbd_do_request: status = 0x%04x\n", s));
723 if (!(s & UES_HALT))
724 goto bad;
725 treq.bmRequestType = UT_WRITE_ENDPOINT;
726 treq.bRequest = UR_CLEAR_FEATURE;
727 USETW(treq.wValue, UF_ENDPOINT_HALT);
728 USETW(treq.wIndex, 0);
729 USETW(treq.wLength, 0);
730 nr = usbd_setup_default_request(
731 reqh, dev, 0, USBD_DEFAULT_TIMEOUT, &treq, &status,
732 0, 0, 0);
733 if (nr != USBD_NORMAL_COMPLETION)
734 goto bad;
735 nr = usbd_sync_transfer(reqh);
736 if (nr != USBD_NORMAL_COMPLETION)
737 goto bad;
738 }
739
740 bad:
741 usbd_free_request(reqh);
742 return (r);
743 }
744
745 void
746 usbd_do_request_async_cb(reqh, priv, status)
747 usbd_request_handle reqh;
748 usbd_private_handle priv;
749 usbd_status status;
750 {
751 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
752 if (reqh->actlen > reqh->length)
753 printf("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
754 "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
755 reqh->pipe->device->address,
756 reqh->request.bmRequestType,
757 reqh->request.bRequest, UGETW(reqh->request.wValue),
758 UGETW(reqh->request.wIndex),
759 UGETW(reqh->request.wLength),
760 reqh->length, reqh->actlen);
761 #endif
762 usbd_free_request(reqh);
763 }
764
765 /*
766 * Execute a request without waiting for completion.
767 * Can be used from interrupt context.
768 */
769 usbd_status
770 usbd_do_request_async(dev, req, data)
771 usbd_device_handle dev;
772 usb_device_request_t *req;
773 void *data;
774 {
775 usbd_request_handle reqh;
776 usbd_status r;
777
778 reqh = usbd_alloc_request();
779 if (reqh == 0)
780 return (USBD_NOMEM);
781 r = usbd_setup_default_request(
782 reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req, data,
783 UGETW(req->wLength), 0, usbd_do_request_async_cb);
784 if (r != USBD_NORMAL_COMPLETION) {
785 usbd_free_request(reqh);
786 return (r);
787 }
788 r = usbd_transfer(reqh);
789 if (r != USBD_IN_PROGRESS)
790 return (r);
791 return (USBD_NORMAL_COMPLETION);
792 }
793
794 struct usbd_quirks *
795 usbd_get_quirks(dev)
796 usbd_device_handle dev;
797 {
798 return (dev->quirks);
799 }
800
801 /* XXX do periodic free() of free list */
802
803 /*
804 * Called from keyboard driver when in polling mode.
805 */
806 void
807 usbd_dopoll(iface)
808 usbd_interface_handle iface;
809 {
810 iface->device->bus->do_poll(iface->device->bus);
811 }
812
813 void
814 usbd_set_polling(iface, on)
815 usbd_interface_handle iface;
816 int on;
817 {
818 iface->device->bus->use_polling = on;
819 }
820
821
822 usb_endpoint_descriptor_t *
823 usbd_get_endpoint_descriptor(iface, address)
824 usbd_interface_handle iface;
825 u_int8_t address;
826 {
827 struct usbd_endpoint *ep;
828 int i;
829
830 for (i = 0; i < iface->idesc->bNumEndpoints; i++) {
831 ep = &iface->endpoints[i];
832 if (ep->edesc->bEndpointAddress == address)
833 return (iface->endpoints[i].edesc);
834 }
835 return (0);
836 }
837
838 #if defined(__FreeBSD__)
839 void
840 usbd_print_child(device_t parent, device_t child)
841 {
842 /*
843 struct usb_softc *sc = device_get_softc(child);
844 */
845
846 printf(" at %s%d", device_get_name(parent), device_get_unit(parent));
847
848 /* XXX How do we get to the usbd_device_handle???
849 usbd_device_handle dev = invalidadosch;
850
851 printf(" addr %d", dev->addr);
852
853 if (bootverbose) {
854 if (dev->lowspeed)
855 printf(", lowspeed");
856 if (dev->self_powered)
857 printf(", self powered");
858 else
859 printf(", %dmA", dev->power);
860 printf(", config %d", dev->config);
861 }
862 */
863 }
864
865 /* Reconfigure all the USB busses in the system. */
866 int
867 usbd_driver_load(module_t mod, int what, void *arg)
868 {
869 devclass_t usb_devclass = devclass_find("usb");
870 devclass_t ugen_devclass = devclass_find("ugen");
871 device_t *devlist;
872 int devcount;
873 int error;
874
875 switch (what) {
876 case MOD_LOAD:
877 case MOD_UNLOAD:
878 if (!usb_devclass)
879 return 0; /* just ignore call */
880
881 if (ugen_devclass) {
882 /* detach devices from generic driver if possible */
883 error = devclass_get_devices(ugen_devclass, &devlist,
884 &devcount);
885 if (!error)
886 for (devcount--; devcount >= 0; devcount--)
887 (void)DEVICE_DETACH(devlist[devcount]);
888 }
889
890 error = devclass_get_devices(usb_devclass, &devlist, &devcount);
891 if (error)
892 return 0; /* XXX maybe transient, or error? */
893
894 for (devcount--; devcount >= 0; devcount--)
895 USB_RECONFIGURE(devlist[devcount]);
896
897 free(devlist, M_TEMP);
898 return 0;
899 }
900
901 return 0; /* nothing to do by us */
902 }
903
904 /* Set the description of the device including a malloc and copy. */
905 void
906 usbd_device_set_desc(device_t device, char *devinfo)
907 {
908 size_t l;
909 char *desc;
910
911 if ( devinfo ) {
912 l = strlen(devinfo);
913 desc = malloc(l+1, M_USB, M_NOWAIT);
914 if (desc)
915 memcpy(desc, devinfo, l+1);
916 } else
917 desc = NULL;
918
919 device_set_desc(device, desc);
920 }
921
922 char *
923 usbd_devname(bdevice *bdev)
924 {
925 static char buf[20];
926 /*
927 * A static buffer is a loss if this routine is used from an interrupt,
928 * but it's not fatal.
929 */
930
931 sprintf(buf, "%s%d", device_get_name(*bdev), device_get_unit(*bdev));
932 return (buf);
933 }
934
935 #endif
936