1 /* $NetBSD: usbdi.c,v 1.37 1999/09/11 08:19:27 augustss Exp $ */
5 * Copyright (c) 1998 The NetBSD Foundation, Inc.
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Lennart Augustsson (augustss@carlstedt.se) at
10 * Carlstedt Research & Technology.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the NetBSD
23 * Foundation, Inc. and its contributors.
24 * 4. Neither the name of The NetBSD Foundation nor the names of its
25 * contributors may be used to endorse or promote products derived
26 * from this software without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #if defined(__NetBSD__) || defined(__OpenBSD__)
45 #include <sys/device.h>
46 #elif defined(__FreeBSD__)
47 #include <sys/module.h>
51 #include <sys/malloc.h>
54 #include <machine/bus.h>
56 #include <dev/usb/usb.h>
57 #include <dev/usb/usbdi.h>
58 #include <dev/usb/usbdi_util.h>
59 #include <dev/usb/usbdivar.h>
60 #include <dev/usb/usb_mem.h>
62 #if defined(__FreeBSD__)
67 #define DPRINTF(x) if (usbdebug) logprintf x
68 #define DPRINTFN(n,x) if (usbdebug>(n)) logprintf x
75 static usbd_status usbd_ar_pipe __P((usbd_pipe_handle pipe));
76 void usbd_do_request_async_cb
77 __P((usbd_request_handle, usbd_private_handle, usbd_status));
78 void usbd_start_next __P((usbd_pipe_handle pipe));
80 static SIMPLEQ_HEAD(, usbd_request) usbd_free_requests
81 = SIMPLEQ_HEAD_INITIALIZER(usbd_free_requests);
83 static __inline int usbd_reqh_isread __P((usbd_request_handle reqh));
85 usbd_reqh_isread(reqh)
86 usbd_request_handle reqh;
88 if (reqh->rqflags & URQ_REQUEST)
89 return (reqh->request.bmRequestType & UT_READ);
91 return (reqh->pipe->endpoint->edesc->bEndpointAddress &
96 void usbd_dump_queue __P((usbd_pipe_handle));
100 usbd_pipe_handle pipe;
102 usbd_request_handle reqh;
104 printf("usbd_dump_queue: pipe=%p\n", pipe);
105 for (reqh = SIMPLEQ_FIRST(&pipe->queue);
107 reqh = SIMPLEQ_NEXT(reqh, next)) {
108 printf(" reqh=%p\n", reqh);
114 usbd_open_pipe(iface, address, flags, pipe)
115 usbd_interface_handle iface;
118 usbd_pipe_handle *pipe;
121 struct usbd_endpoint *ep;
125 for (i = 0; i < iface->idesc->bNumEndpoints; i++) {
126 ep = &iface->endpoints[i];
127 if (ep->edesc->bEndpointAddress == address)
130 return (USBD_BAD_ADDRESS);
132 if ((flags & USBD_EXCLUSIVE_USE) &&
134 return (USBD_IN_USE);
135 r = usbd_setup_pipe(iface->device, iface, ep, &p);
136 if (r != USBD_NORMAL_COMPLETION)
138 LIST_INSERT_HEAD(&iface->pipes, p, next);
140 return (USBD_NORMAL_COMPLETION);
144 usbd_open_pipe_intr(iface, address, flags, pipe, priv, buffer, length, cb)
145 usbd_interface_handle iface;
148 usbd_pipe_handle *pipe;
149 usbd_private_handle priv;
155 usbd_request_handle reqh;
156 usbd_pipe_handle ipipe;
158 r = usbd_open_pipe(iface, address, USBD_EXCLUSIVE_USE, &ipipe);
159 if (r != USBD_NORMAL_COMPLETION)
161 reqh = usbd_alloc_request(iface->device);
166 usbd_setup_request(reqh, ipipe, priv, buffer, length, flags,
167 USBD_NO_TIMEOUT, cb);
168 ipipe->intrreqh = reqh;
170 r = usbd_transfer(reqh);
172 if (r != USBD_IN_PROGRESS)
174 return (USBD_NORMAL_COMPLETION);
179 usbd_free_request(reqh);
181 usbd_close_pipe(ipipe);
186 usbd_close_pipe(pipe)
187 usbd_pipe_handle pipe;
191 printf("usbd_close_pipe: pipe==NULL\n");
192 return (USBD_NORMAL_COMPLETION);
196 if (--pipe->refcnt != 0)
197 return (USBD_NORMAL_COMPLETION);
198 if (SIMPLEQ_FIRST(&pipe->queue) != 0)
199 return (USBD_PENDING_REQUESTS);
200 LIST_REMOVE(pipe, next);
201 pipe->endpoint->refcnt--;
202 pipe->methods->close(pipe);
204 usbd_free_request(pipe->intrreqh);
206 return (USBD_NORMAL_COMPLETION);
211 usbd_request_handle reqh;
213 usbd_pipe_handle pipe = reqh->pipe;
218 DPRINTFN(5,("usbd_transfer: reqh=%p, flags=%d, pipe=%p, running=%d\n",
219 reqh, reqh->flags, pipe, pipe->running));
222 usbd_dump_queue(pipe);
227 /* If there is no buffer, allocate one and copy data. */
228 if (!(reqh->rqflags & URQ_DEV_DMABUF) && size != 0) {
229 usb_dma_t *dmap = &reqh->dmabuf;
230 struct usbd_bus *bus = pipe->device->bus;
233 if (reqh->rqflags & URQ_AUTO_DMABUF)
234 printf("usbd_transfer: has old buffer!\n");
236 r = bus->methods->allocm(bus, dmap, size);
237 if (r != USBD_NORMAL_COMPLETION)
239 reqh->rqflags |= URQ_AUTO_DMABUF;
241 /* finally copy data if going out */
242 if (!usbd_reqh_isread(reqh))
243 memcpy(KERNADDR(dmap), reqh->buffer, size);
246 r = pipe->methods->transfer(reqh);
248 if (r != USBD_IN_PROGRESS && r != USBD_NORMAL_COMPLETION) {
249 /* The transfer has not been queued, so free buffer. */
250 if (reqh->rqflags & URQ_AUTO_DMABUF) {
251 struct usbd_bus *bus = pipe->device->bus;
253 bus->methods->freem(bus, &reqh->dmabuf);
254 reqh->rqflags &= ~URQ_AUTO_DMABUF;
258 if (!(reqh->flags & USBD_SYNCHRONOUS))
261 /* Sync transfer, wait for completion. */
262 if (r != USBD_IN_PROGRESS)
266 if (pipe->device->bus->use_polling)
267 panic("usbd_transfer: not done\n");
268 tsleep(reqh, PRIBIO, "usbsyn", 0);
271 return (reqh->status);
274 /* Like usbd_transfer(), but waits for completion. */
276 usbd_sync_transfer(reqh)
277 usbd_request_handle reqh;
279 reqh->flags |= USBD_SYNCHRONOUS;
280 return (usbd_transfer(reqh));
284 usbd_alloc_buffer(reqh, size)
285 usbd_request_handle reqh;
288 struct usbd_bus *bus = reqh->device->bus;
291 r = bus->methods->allocm(bus, &reqh->dmabuf, size);
292 if (r != USBD_NORMAL_COMPLETION)
294 reqh->rqflags |= URQ_DEV_DMABUF;
295 return (KERNADDR(&reqh->dmabuf));
299 usbd_free_buffer(reqh)
300 usbd_request_handle reqh;
303 if (!(reqh->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF))) {
304 printf("usbd_free_buffer: no buffer\n");
308 reqh->rqflags &= ~(URQ_DEV_DMABUF | URQ_AUTO_DMABUF);
309 reqh->device->bus->methods->freem(reqh->device->bus, &reqh->dmabuf);
313 usbd_alloc_request(dev)
314 usbd_device_handle dev;
316 usbd_request_handle reqh;
318 reqh = SIMPLEQ_FIRST(&usbd_free_requests);
320 SIMPLEQ_REMOVE_HEAD(&usbd_free_requests, reqh, next);
322 reqh = malloc(sizeof(*reqh), M_USB, M_NOWAIT);
325 memset(reqh, 0, sizeof *reqh);
327 DPRINTFN(5,("usbd_alloc_request() = %p\n", reqh));
332 usbd_free_request(reqh)
333 usbd_request_handle reqh;
335 DPRINTFN(5,("usbd_free_request: %p\n", reqh));
336 if (reqh->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF))
337 usbd_free_buffer(reqh);
338 SIMPLEQ_INSERT_HEAD(&usbd_free_requests, reqh, next);
339 return (USBD_NORMAL_COMPLETION);
343 usbd_setup_request(reqh, pipe, priv, buffer, length, flags, timeout, callback)
344 usbd_request_handle reqh;
345 usbd_pipe_handle pipe;
346 usbd_private_handle priv;
351 void (*callback) __P((usbd_request_handle,
357 reqh->buffer = buffer;
358 reqh->length = length;
361 reqh->timeout = timeout;
362 reqh->status = USBD_NOT_STARTED;
363 reqh->callback = callback;
364 reqh->rqflags &= ~URQ_REQUEST;
369 usbd_setup_default_request(reqh, dev, priv, timeout, req, buffer,
370 length, flags, callback)
371 usbd_request_handle reqh;
372 usbd_device_handle dev;
373 usbd_private_handle priv;
375 usb_device_request_t *req;
379 void (*callback) __P((usbd_request_handle,
383 reqh->pipe = dev->default_pipe;
385 reqh->buffer = buffer;
386 reqh->length = length;
389 reqh->timeout = timeout;
390 reqh->status = USBD_NOT_STARTED;
391 reqh->callback = callback;
392 reqh->request = *req;
393 reqh->rqflags |= URQ_REQUEST;
398 usbd_setup_isoc_request(reqh, pipe, priv, frlengths, nframes, callback)
399 usbd_request_handle reqh;
400 usbd_pipe_handle pipe;
401 usbd_private_handle priv;
402 u_int16_t *frlengths;
404 usbd_callback callback;
412 reqh->timeout = USBD_NO_TIMEOUT;
413 reqh->status = USBD_NOT_STARTED;
414 reqh->callback = callback;
415 reqh->rqflags &= ~URQ_REQUEST;
416 reqh->frlengths = frlengths;
417 reqh->nframes = nframes;
421 usbd_get_request_status(reqh, priv, buffer, count, status)
422 usbd_request_handle reqh;
423 usbd_private_handle *priv;
431 *buffer = reqh->buffer;
433 *count = reqh->actlen;
435 *status = reqh->status;
438 usb_config_descriptor_t *
439 usbd_get_config_descriptor(dev)
440 usbd_device_handle dev;
445 usb_interface_descriptor_t *
446 usbd_get_interface_descriptor(iface)
447 usbd_interface_handle iface;
449 return (iface->idesc);
452 usb_device_descriptor_t *
453 usbd_get_device_descriptor(dev)
454 usbd_device_handle dev;
456 return (&dev->ddesc);
459 usb_endpoint_descriptor_t *
460 usbd_interface2endpoint_descriptor(iface, index)
461 usbd_interface_handle iface;
464 if (index >= iface->idesc->bNumEndpoints)
466 return (iface->endpoints[index].edesc);
470 usbd_abort_pipe(pipe)
471 usbd_pipe_handle pipe;
478 printf("usbd_close_pipe: pipe==NULL\n");
479 return (USBD_NORMAL_COMPLETION);
483 r = usbd_ar_pipe(pipe);
489 usbd_clear_endpoint_stall(pipe)
490 usbd_pipe_handle pipe;
492 usbd_device_handle dev = pipe->device;
493 usb_device_request_t req;
496 DPRINTFN(8, ("usbd_clear_endpoint_stall\n"));
499 * Clearing en endpoint stall resets the enpoint toggle, so
500 * do the same to the HC toggle.
502 pipe->methods->cleartoggle(pipe);
504 req.bmRequestType = UT_WRITE_ENDPOINT;
505 req.bRequest = UR_CLEAR_FEATURE;
506 USETW(req.wValue, UF_ENDPOINT_HALT);
507 USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);
508 USETW(req.wLength, 0);
509 r = usbd_do_request(dev, &req, 0);
511 XXX should we do this?
512 if (r == USBD_NORMAL_COMPLETION) {
513 pipe->state = USBD_PIPE_ACTIVE;
514 /* XXX activate pipe */
521 usbd_clear_endpoint_stall_async(pipe)
522 usbd_pipe_handle pipe;
524 usbd_device_handle dev = pipe->device;
525 usb_device_request_t req;
528 pipe->methods->cleartoggle(pipe);
530 req.bmRequestType = UT_WRITE_ENDPOINT;
531 req.bRequest = UR_CLEAR_FEATURE;
532 USETW(req.wValue, UF_ENDPOINT_HALT);
533 USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);
534 USETW(req.wLength, 0);
535 r = usbd_do_request_async(dev, &req, 0);
540 usbd_endpoint_count(iface, count)
541 usbd_interface_handle iface;
544 *count = iface->idesc->bNumEndpoints;
545 return (USBD_NORMAL_COMPLETION);
549 usbd_interface_count(dev, count)
550 usbd_device_handle dev;
554 return (USBD_NOT_CONFIGURED);
555 *count = dev->cdesc->bNumInterface;
556 return (USBD_NORMAL_COMPLETION);
560 usbd_interface2device_handle(iface, dev)
561 usbd_interface_handle iface;
562 usbd_device_handle *dev;
564 *dev = iface->device;
565 return (USBD_NORMAL_COMPLETION);
569 usbd_device2interface_handle(dev, ifaceno, iface)
570 usbd_device_handle dev;
572 usbd_interface_handle *iface;
575 return (USBD_NOT_CONFIGURED);
576 if (ifaceno >= dev->cdesc->bNumInterface)
578 *iface = &dev->ifaces[ifaceno];
579 return (USBD_NORMAL_COMPLETION);
583 usbd_pipe2device_handle(pipe)
584 usbd_pipe_handle pipe;
586 return (pipe->device);
591 usbd_set_interface(iface, altidx)
592 usbd_interface_handle iface;
595 usb_device_request_t req;
598 if (LIST_FIRST(&iface->pipes) != 0)
599 return (USBD_IN_USE);
601 if (iface->endpoints)
602 free(iface->endpoints, M_USB);
603 iface->endpoints = 0;
606 r = usbd_fill_iface_data(iface->device, iface->index, altidx);
607 if (r != USBD_NORMAL_COMPLETION)
610 req.bmRequestType = UT_WRITE_INTERFACE;
611 req.bRequest = UR_SET_INTERFACE;
612 USETW(req.wValue, iface->idesc->bAlternateSetting);
613 USETW(req.wIndex, iface->idesc->bInterfaceNumber);
614 USETW(req.wLength, 0);
615 return usbd_do_request(iface->device, &req, 0);
619 usbd_get_no_alts(cdesc, ifaceno)
620 usb_config_descriptor_t *cdesc;
623 char *p = (char *)cdesc;
624 char *end = p + UGETW(cdesc->wTotalLength);
625 usb_interface_descriptor_t *d;
628 for (n = 0; p < end; p += d->bLength) {
629 d = (usb_interface_descriptor_t *)p;
630 if (p + d->bLength <= end &&
631 d->bDescriptorType == UDESC_INTERFACE &&
632 d->bInterfaceNumber == ifaceno)
639 usbd_get_interface_altindex(iface)
640 usbd_interface_handle iface;
642 return (iface->altindex);
646 usbd_get_interface(iface, aiface)
647 usbd_interface_handle iface;
650 usb_device_request_t req;
652 req.bmRequestType = UT_READ_INTERFACE;
653 req.bRequest = UR_GET_INTERFACE;
654 USETW(req.wValue, 0);
655 USETW(req.wIndex, iface->idesc->bInterfaceNumber);
656 USETW(req.wLength, 1);
657 return usbd_do_request(iface->device, &req, aiface);
660 /*** Internal routines ***/
662 /* Dequeue all pipe operations, called at splusb(). */
665 usbd_pipe_handle pipe;
667 usbd_request_handle reqh;
669 DPRINTFN(2,("usbd_ar_pipe: pipe=%p\n", pipe));
672 usbd_dump_queue(pipe);
674 while ((reqh = SIMPLEQ_FIRST(&pipe->queue))) {
675 DPRINTFN(2,("usbd_ar_pipe: pipe=%p reqh=%p (methods=%p)\n",
676 pipe, reqh, pipe->methods));
677 /* Make the HC abort it (and invoke the callback). */
678 pipe->methods->abort(reqh);
679 /* XXX only for non-0 usbd_clear_endpoint_stall(pipe); */
681 return (USBD_NORMAL_COMPLETION);
685 usb_transfer_complete(reqh)
686 usbd_request_handle reqh;
688 usbd_pipe_handle pipe = reqh->pipe;
691 DPRINTFN(5, ("usb_transfer_complete: pipe=%p reqh=%p actlen=%d\n",
692 pipe, reqh, reqh->actlen));
696 printf("usbd_transfer_cb: pipe==0, reqh=%p\n", reqh);
701 polling = pipe->device->bus->use_polling;
706 /* if we allocated the buffer in usbd_transfer() we free it here. */
707 if (reqh->rqflags & URQ_AUTO_DMABUF) {
708 usb_dma_t *dmap = &reqh->dmabuf;
710 if (usbd_reqh_isread(reqh))
711 memcpy(reqh->buffer, KERNADDR(dmap), reqh->actlen);
713 struct usbd_bus *bus = pipe->device->bus;
714 bus->methods->freem(bus, dmap);
715 reqh->rqflags &= ~URQ_AUTO_DMABUF;
719 if (pipe->methods->done)
720 pipe->methods->done(reqh);
722 /* Remove request from queue. */
723 if ( reqh == SIMPLEQ_FIRST(&pipe->queue) )
724 SIMPLEQ_REMOVE_HEAD(&pipe->queue, reqh, next);
726 DPRINTF(("XXX duplicated call to usb_transfer_complete\n"));
729 /* Count completed transfers. */
730 ++pipe->device->bus->stats.requests
731 [pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE];
734 if (reqh->status == USBD_NORMAL_COMPLETION &&
735 reqh->actlen < reqh->length &&
736 !(reqh->flags & USBD_SHORT_XFER_OK)) {
737 DPRINTFN(-1, ("usbd_transfer_cb: short xfer %d<%d (bytes)\n",
738 reqh->actlen, reqh->length));
739 reqh->status = USBD_SHORT_XFER;
743 reqh->callback(reqh, reqh->priv, reqh->status);
745 if ((reqh->flags & USBD_SYNCHRONOUS) && !polling)
749 reqh->status != USBD_CANCELLED && reqh->status != USBD_TIMEOUT)
750 usbd_start_next(pipe);
754 usb_insert_transfer(reqh)
755 usbd_request_handle reqh;
757 usbd_pipe_handle pipe = reqh->pipe;
761 DPRINTFN(5,("usb_insert_transfer: pipe=%p running=%d\n", pipe,
764 SIMPLEQ_INSERT_TAIL(&pipe->queue, reqh, next);
766 r = USBD_IN_PROGRESS;
769 r = USBD_NORMAL_COMPLETION;
776 usbd_start_next(pipe)
777 usbd_pipe_handle pipe;
779 usbd_request_handle reqh;
782 DPRINTFN(10, ("usbd_start_next: pipe=%p\n", pipe));
786 printf("usbd_start_next: pipe == 0\n");
789 if (!pipe->methods || !pipe->methods->start) {
790 printf("usbd_start_next: no start method\n");
795 /* Get next request in queue. */
796 reqh = SIMPLEQ_FIRST(&pipe->queue);
797 DPRINTFN(5, ("usbd_start_next: pipe=%p start reqh=%p\n", pipe, reqh));
801 r = pipe->methods->start(reqh);
802 if (r != USBD_IN_PROGRESS) {
803 printf("usbd_start_next: error=%d\n", r);
811 usbd_do_request(dev, req, data)
812 usbd_device_handle dev;
813 usb_device_request_t *req;
816 return (usbd_do_request_flags(dev, req, data, 0, 0));
820 usbd_do_request_flags(dev, req, data, flags, actlen)
821 usbd_device_handle dev;
822 usb_device_request_t *req;
827 usbd_request_handle reqh;
832 printf("usbd_do_request: not in process context\n");
837 reqh = usbd_alloc_request(dev);
840 usbd_setup_default_request(reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req,
841 data, UGETW(req->wLength), flags, 0);
842 r = usbd_sync_transfer(reqh);
843 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
844 if (reqh->actlen > reqh->length)
845 DPRINTF(("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
846 "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
847 dev->address, reqh->request.bmRequestType,
848 reqh->request.bRequest, UGETW(reqh->request.wValue),
849 UGETW(reqh->request.wIndex),
850 UGETW(reqh->request.wLength),
851 reqh->length, reqh->actlen));
854 *actlen = reqh->actlen;
855 if (r == USBD_STALLED) {
857 * The control endpoint has stalled. Control endpoints
858 * should not halt, but some may do so anyway so clear
859 * any halt condition.
861 usb_device_request_t treq;
866 treq.bmRequestType = UT_READ_ENDPOINT;
867 treq.bRequest = UR_GET_STATUS;
868 USETW(treq.wValue, 0);
869 USETW(treq.wIndex, 0);
870 USETW(treq.wLength, sizeof(usb_status_t));
871 usbd_setup_default_request(reqh, dev, 0, USBD_DEFAULT_TIMEOUT,
872 &treq, &status,sizeof(usb_status_t),
874 nr = usbd_sync_transfer(reqh);
875 if (nr != USBD_NORMAL_COMPLETION)
877 s = UGETW(status.wStatus);
878 DPRINTF(("usbd_do_request: status = 0x%04x\n", s));
881 treq.bmRequestType = UT_WRITE_ENDPOINT;
882 treq.bRequest = UR_CLEAR_FEATURE;
883 USETW(treq.wValue, UF_ENDPOINT_HALT);
884 USETW(treq.wIndex, 0);
885 USETW(treq.wLength, 0);
886 usbd_setup_default_request(reqh, dev, 0, USBD_DEFAULT_TIMEOUT,
887 &treq, &status, 0, 0, 0);
888 nr = usbd_sync_transfer(reqh);
889 if (nr != USBD_NORMAL_COMPLETION)
894 usbd_free_request(reqh);
899 usbd_do_request_async_cb(reqh, priv, status)
900 usbd_request_handle reqh;
901 usbd_private_handle priv;
904 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
905 if (reqh->actlen > reqh->length)
906 DPRINTF(("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
907 "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
908 reqh->pipe->device->address,
909 reqh->request.bmRequestType,
910 reqh->request.bRequest, UGETW(reqh->request.wValue),
911 UGETW(reqh->request.wIndex),
912 UGETW(reqh->request.wLength),
913 reqh->length, reqh->actlen));
915 usbd_free_request(reqh);
919 * Execute a request without waiting for completion.
920 * Can be used from interrupt context.
923 usbd_do_request_async(dev, req, data)
924 usbd_device_handle dev;
925 usb_device_request_t *req;
928 usbd_request_handle reqh;
931 reqh = usbd_alloc_request(dev);
934 usbd_setup_default_request(reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req, data,
935 UGETW(req->wLength), 0,
936 usbd_do_request_async_cb);
937 r = usbd_transfer(reqh);
938 if (r != USBD_IN_PROGRESS) {
939 usbd_free_request(reqh);
942 return (USBD_NORMAL_COMPLETION);
947 usbd_device_handle dev;
949 return (dev->quirks);
952 /* XXX do periodic free() of free list */
955 * Called from keyboard driver when in polling mode.
959 usbd_interface_handle iface;
961 iface->device->bus->methods->do_poll(iface->device->bus);
965 usbd_set_polling(iface, on)
966 usbd_interface_handle iface;
969 iface->device->bus->use_polling = on;
973 usb_endpoint_descriptor_t *
974 usbd_get_endpoint_descriptor(iface, address)
975 usbd_interface_handle iface;
978 struct usbd_endpoint *ep;
981 for (i = 0; i < iface->idesc->bNumEndpoints; i++) {
982 ep = &iface->endpoints[i];
983 if (ep->edesc->bEndpointAddress == address)
984 return (iface->endpoints[i].edesc);
989 #if defined(__FreeBSD__)
991 usbd_driver_load(module_t mod, int what, void *arg)
993 /* XXX should implement something like a function that removes all generic devices */
995 return 0; /* nothing to do by us */