]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/usb/usbdi.c
This commit was generated by cvs2svn to compensate for changes in r53574,
[FreeBSD/FreeBSD.git] / sys / dev / usb / usbdi.c
1 /*      $NetBSD: usbdi.c,v 1.47 1999/10/13 23:46:10 augustss Exp $      */
2 /*      $FreeBSD$       */
3
4 /*
5  * Copyright (c) 1998 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Lennart Augustsson (augustss@carlstedt.se) at
10  * Carlstedt Research & Technology.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
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.
27  *
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.
39  */
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #if defined(__NetBSD__) || defined(__OpenBSD__)
44 #include <sys/kernel.h>
45 #include <sys/device.h>
46 #elif defined(__FreeBSD__)
47 #include <sys/module.h>
48 #include <sys/bus.h>
49 #include <sys/conf.h>
50 #include "usb_if.h"
51 #if defined(DIAGNOSTIC) && defined(__i386__)
52 #include <machine/cpu.h>
53 #endif
54 #endif
55 #include <sys/malloc.h>
56 #include <sys/proc.h>
57
58 #include <machine/bus.h>
59
60 #include <dev/usb/usb.h>
61 #include <dev/usb/usbdi.h>
62 #include <dev/usb/usbdi_util.h>
63 #include <dev/usb/usbdivar.h>
64 #include <dev/usb/usb_mem.h>
65
66 #if defined(__FreeBSD__)
67 #include "usb_if.h"
68 #endif
69
70 #ifdef USB_DEBUG
71 #define DPRINTF(x)      if (usbdebug) logprintf x
72 #define DPRINTFN(n,x)   if (usbdebug>(n)) logprintf x
73 extern int usbdebug;
74 #else
75 #define DPRINTF(x)
76 #define DPRINTFN(n,x)
77 #endif
78
79 static usbd_status usbd_ar_pipe  __P((usbd_pipe_handle pipe));
80 static void usbd_do_request_async_cb 
81         __P((usbd_xfer_handle, usbd_private_handle, usbd_status));
82 static void usbd_start_next __P((usbd_pipe_handle pipe));
83
84 static SIMPLEQ_HEAD(, usbd_xfer) usbd_free_requests =
85         SIMPLEQ_HEAD_INITIALIZER(usbd_free_requests);
86
87 static int usbd_nbuses = 0;
88
89 void
90 usbd_init()
91 {
92         usbd_nbuses++;
93 }
94
95 void
96 usbd_finish()
97 {
98         usbd_xfer_handle xfer;
99
100         if (--usbd_nbuses == 0) {
101                 /* Last controller is gone, free all requests. */
102                 for (;;) {
103                         xfer = SIMPLEQ_FIRST(&usbd_free_requests);
104                         if (xfer == NULL)
105                                 break;
106                         SIMPLEQ_REMOVE_HEAD(&usbd_free_requests, xfer, next);
107                         free(xfer, M_USB);
108                 }                       
109         }
110 }
111
112 static __inline int usbd_xfer_isread __P((usbd_xfer_handle xfer));
113 static __inline int
114 usbd_xfer_isread(xfer)
115         usbd_xfer_handle xfer;
116 {
117         if (xfer->rqflags & URQ_REQUEST)
118                 return (xfer->request.bmRequestType & UT_READ);
119         else
120                 return (xfer->pipe->endpoint->edesc->bEndpointAddress &
121                         UE_DIR_IN);
122 }
123
124 #ifdef USB_DEBUG
125 void usbd_dump_queue __P((usbd_pipe_handle));
126
127 void
128 usbd_dump_queue(pipe)
129         usbd_pipe_handle pipe;
130 {
131         usbd_xfer_handle xfer;
132
133         printf("usbd_dump_queue: pipe=%p\n", pipe);
134         for (xfer = SIMPLEQ_FIRST(&pipe->queue);
135              xfer;
136              xfer = SIMPLEQ_NEXT(xfer, next)) {
137                 printf("  xfer=%p\n", xfer);
138         }
139 }
140 #endif
141
142 usbd_status 
143 usbd_open_pipe(iface, address, flags, pipe)
144         usbd_interface_handle iface;
145         u_int8_t address;
146         u_int8_t flags;
147         usbd_pipe_handle *pipe;
148
149         usbd_pipe_handle p;
150         struct usbd_endpoint *ep;
151         usbd_status err;
152         int i;
153
154         for (i = 0; i < iface->idesc->bNumEndpoints; i++) {
155                 ep = &iface->endpoints[i];
156                 if (ep->edesc->bEndpointAddress == address)
157                         goto found;
158         }
159         return (USBD_BAD_ADDRESS);
160  found:
161         if ((flags & USBD_EXCLUSIVE_USE) &&
162             ep->refcnt != 0)
163                 return (USBD_IN_USE);
164         err = usbd_setup_pipe(iface->device, iface, ep, &p);
165         if (err)
166                 return (err);
167         LIST_INSERT_HEAD(&iface->pipes, p, next);
168         *pipe = p;
169         return (USBD_NORMAL_COMPLETION);
170 }
171
172 usbd_status 
173 usbd_open_pipe_intr(iface, address, flags, pipe, priv, buffer, length, cb)
174         usbd_interface_handle iface;
175         u_int8_t address;
176         u_int8_t flags;
177         usbd_pipe_handle *pipe;
178         usbd_private_handle priv;
179         void *buffer;
180         u_int32_t length;
181         usbd_callback cb;
182 {
183         usbd_status err;
184         usbd_xfer_handle xfer;
185         usbd_pipe_handle ipipe;
186
187         err = usbd_open_pipe(iface, address, USBD_EXCLUSIVE_USE, &ipipe);
188         if (err)
189                 return (err);
190         xfer = usbd_alloc_request(iface->device);
191         if (xfer == NULL) {
192                 err = USBD_NOMEM;
193                 goto bad1;
194         }
195         usbd_setup_request(xfer, ipipe, priv, buffer, length, flags,
196                            USBD_NO_TIMEOUT, cb);
197         ipipe->intrxfer = xfer;
198         ipipe->repeat = 1;
199         err = usbd_transfer(xfer);
200         *pipe = ipipe;
201         if (err != USBD_IN_PROGRESS)
202                 goto bad2;
203         return (USBD_NORMAL_COMPLETION);
204
205  bad2:
206         ipipe->intrxfer = NULL;
207         ipipe->repeat = 0;
208         usbd_free_request(xfer);
209  bad1:
210         usbd_close_pipe(ipipe);
211         return (err);
212 }
213
214 usbd_status
215 usbd_close_pipe(pipe)
216         usbd_pipe_handle pipe;
217 {
218 #ifdef DIAGNOSTIC
219         if (pipe == NULL) {
220                 printf("usbd_close_pipe: pipe==NULL\n");
221                 return (USBD_NORMAL_COMPLETION);
222         }
223 #endif
224
225         if (--pipe->refcnt != 0)
226                 return (USBD_NORMAL_COMPLETION);
227         if (SIMPLEQ_FIRST(&pipe->queue) != 0)
228                 return (USBD_PENDING_REQUESTS);
229         LIST_REMOVE(pipe, next);
230         pipe->endpoint->refcnt--;
231         pipe->methods->close(pipe);
232         if (pipe->intrxfer != NULL)
233                 usbd_free_request(pipe->intrxfer);
234         free(pipe, M_USB);
235         return (USBD_NORMAL_COMPLETION);
236 }
237
238 usbd_status
239 usbd_transfer(xfer)
240         usbd_xfer_handle xfer;
241 {
242         usbd_pipe_handle pipe = xfer->pipe;
243         usb_dma_t *dmap = &xfer->dmabuf;
244         usbd_status err;
245         u_int size;
246         int s;
247
248         DPRINTFN(5,("usbd_transfer: xfer=%p, flags=%d, pipe=%p, running=%d\n",
249                     xfer, xfer->flags, pipe, pipe->running));
250 #ifdef USB_DEBUG
251         if (usbdebug > 5)
252                 usbd_dump_queue(pipe);
253 #endif
254         xfer->done = 0;
255
256         size = xfer->length;
257         /* If there is no buffer, allocate one. */
258         if (!(xfer->rqflags & URQ_DEV_DMABUF) && size != 0) {
259                 struct usbd_bus *bus = pipe->device->bus;
260
261 #ifdef DIAGNOSTIC
262                 if (xfer->rqflags & URQ_AUTO_DMABUF)
263                         printf("usbd_transfer: has old buffer!\n");
264 #endif
265                 err = bus->methods->allocm(bus, dmap, size);
266                 if (err)
267                         return (err);
268                 xfer->rqflags |= URQ_AUTO_DMABUF;
269         }
270
271         /* Copy data if going out. */
272         if (!(xfer->flags & USBD_NO_COPY) && size != 0 && 
273             !usbd_xfer_isread(xfer))
274                 memcpy(KERNADDR(dmap), xfer->buffer, size);
275
276         err = pipe->methods->transfer(xfer);
277
278         if (err != USBD_IN_PROGRESS && err) {
279                 /* The transfer has not been queued, so free buffer. */
280                 if (xfer->rqflags & URQ_AUTO_DMABUF) {
281                         struct usbd_bus *bus = pipe->device->bus;
282
283                         bus->methods->freem(bus, &xfer->dmabuf);
284                         xfer->rqflags &= ~URQ_AUTO_DMABUF;
285                 }
286         }
287
288         if (!(xfer->flags & USBD_SYNCHRONOUS))
289                 return (err);
290
291         /* Sync transfer, wait for completion. */
292         if (err != USBD_IN_PROGRESS)
293                 return (err);
294         s = splusb();
295         if (!xfer->done) {
296                 if (pipe->device->bus->use_polling)
297                         panic("usbd_transfer: not done\n");
298                 tsleep(xfer, PRIBIO, "usbsyn", 0);
299         }
300         splx(s);
301         return (xfer->status);
302 }
303
304 /* Like usbd_transfer(), but waits for completion. */
305 usbd_status
306 usbd_sync_transfer(xfer)
307         usbd_xfer_handle xfer;
308 {
309         xfer->flags |= USBD_SYNCHRONOUS;
310         return (usbd_transfer(xfer));
311 }
312
313 void *
314 usbd_alloc_buffer(xfer, size)
315         usbd_xfer_handle xfer;
316         u_int32_t size;
317 {
318         struct usbd_bus *bus = xfer->device->bus;
319         usbd_status err;
320
321         err = bus->methods->allocm(bus, &xfer->dmabuf, size);
322         if (err)
323                 return (0);
324         xfer->rqflags |= URQ_DEV_DMABUF;
325         return (KERNADDR(&xfer->dmabuf));
326 }
327
328 void
329 usbd_free_buffer(xfer)
330         usbd_xfer_handle xfer;
331 {
332 #ifdef DIAGNOSTIC
333         if (!(xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF))) {
334                 printf("usbd_free_buffer: no buffer\n");
335                 return;
336         }
337 #endif
338         xfer->rqflags &= ~(URQ_DEV_DMABUF | URQ_AUTO_DMABUF);
339         xfer->device->bus->methods->freem(xfer->device->bus, &xfer->dmabuf);
340 }
341
342 void *
343 usbd_get_buffer(xfer)
344         usbd_xfer_handle xfer;
345 {
346         if (!(xfer->rqflags & URQ_DEV_DMABUF))
347                 return (0);
348         return (KERNADDR(&xfer->dmabuf));
349 }
350
351 usbd_xfer_handle 
352 usbd_alloc_request(dev)
353         usbd_device_handle dev;
354 {
355         usbd_xfer_handle xfer;
356
357         xfer = SIMPLEQ_FIRST(&usbd_free_requests);
358         if (xfer != NULL)
359                 SIMPLEQ_REMOVE_HEAD(&usbd_free_requests, xfer, next);
360         else
361                 xfer = malloc(sizeof(*xfer), M_USB, M_NOWAIT);
362         if (xfer == NULL)
363                 return (0);
364         memset(xfer, 0, sizeof *xfer);
365         xfer->device = dev;
366         DPRINTFN(5,("usbd_alloc_request() = %p\n", xfer));
367         return (xfer);
368 }
369
370 usbd_status 
371 usbd_free_request(xfer)
372         usbd_xfer_handle xfer;
373 {
374         DPRINTFN(5,("usbd_free_request: %p\n", xfer));
375         if (xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF))
376                 usbd_free_buffer(xfer);
377         SIMPLEQ_INSERT_HEAD(&usbd_free_requests, xfer, next);
378         return (USBD_NORMAL_COMPLETION);
379 }
380
381 void
382 usbd_setup_request(xfer, pipe, priv, buffer, length, flags, timeout, callback)
383         usbd_xfer_handle xfer;
384         usbd_pipe_handle pipe;
385         usbd_private_handle priv;
386         void *buffer;
387         u_int32_t length;
388         u_int16_t flags;
389         u_int32_t timeout;
390         void (*callback) __P((usbd_xfer_handle,
391                               usbd_private_handle,
392                               usbd_status));
393 {
394         xfer->pipe = pipe;
395         xfer->priv = priv;
396         xfer->buffer = buffer;
397         xfer->length = length;
398         xfer->actlen = 0;
399         xfer->flags = flags;
400         xfer->timeout = timeout;
401         xfer->status = USBD_NOT_STARTED;
402         xfer->callback = callback;
403         xfer->rqflags &= ~URQ_REQUEST;
404         xfer->nframes = 0;
405 }
406
407 void
408 usbd_setup_default_request(xfer, dev, priv, timeout, req, buffer, 
409                            length, flags, callback)
410         usbd_xfer_handle xfer;
411         usbd_device_handle dev;
412         usbd_private_handle priv;
413         u_int32_t timeout;
414         usb_device_request_t *req;
415         void *buffer;
416         u_int32_t length;
417         u_int16_t flags;
418         void (*callback) __P((usbd_xfer_handle,
419                               usbd_private_handle,
420                               usbd_status));
421 {
422         xfer->pipe = dev->default_pipe;
423         xfer->priv = priv;
424         xfer->buffer = buffer;
425         xfer->length = length;
426         xfer->actlen = 0;
427         xfer->flags = flags;
428         xfer->timeout = timeout;
429         xfer->status = USBD_NOT_STARTED;
430         xfer->callback = callback;
431         xfer->request = *req;
432         xfer->rqflags |= URQ_REQUEST;
433         xfer->nframes = 0;
434 }
435
436 void
437 usbd_setup_isoc_request(xfer, pipe, priv, frlengths, nframes, flags, callback)
438         usbd_xfer_handle xfer;
439         usbd_pipe_handle pipe;
440         usbd_private_handle priv;
441         u_int16_t *frlengths;
442         u_int32_t nframes;
443         u_int16_t flags;
444         usbd_callback callback;
445 {
446         xfer->pipe = pipe;
447         xfer->priv = priv;
448         xfer->buffer = 0;
449         xfer->length = 0;
450         xfer->actlen = 0;
451         xfer->flags = flags;
452         xfer->timeout = USBD_NO_TIMEOUT;
453         xfer->status = USBD_NOT_STARTED;
454         xfer->callback = callback;
455         xfer->rqflags &= ~URQ_REQUEST;
456         xfer->frlengths = frlengths;
457         xfer->nframes = nframes;
458 }
459
460 void
461 usbd_get_request_status(xfer, priv, buffer, count, status)
462         usbd_xfer_handle xfer;
463         usbd_private_handle *priv;
464         void **buffer;
465         u_int32_t *count;
466         usbd_status *status;
467 {
468         if (priv != NULL)
469                 *priv = xfer->priv;
470         if (buffer != NULL)
471                 *buffer = xfer->buffer;
472         if (count != NULL)
473                 *count = xfer->actlen;
474         if (status != NULL)
475                 *status = xfer->status;
476 }
477
478 usb_config_descriptor_t *
479 usbd_get_config_descriptor(dev)
480         usbd_device_handle dev;
481 {
482         return (dev->cdesc);
483 }
484
485 usb_interface_descriptor_t *
486 usbd_get_interface_descriptor(iface)
487         usbd_interface_handle iface;
488 {
489         return (iface->idesc);
490 }
491
492 usb_device_descriptor_t *
493 usbd_get_device_descriptor(dev)
494         usbd_device_handle dev;
495 {
496         return (&dev->ddesc);
497 }
498
499 usb_endpoint_descriptor_t *
500 usbd_interface2endpoint_descriptor(iface, index)
501         usbd_interface_handle iface;
502         u_int8_t index;
503 {
504         if (index >= iface->idesc->bNumEndpoints)
505                 return (0);
506         return (iface->endpoints[index].edesc);
507 }
508
509 usbd_status 
510 usbd_abort_pipe(pipe)
511         usbd_pipe_handle pipe;
512 {
513         usbd_status err;
514         int s;
515
516 #ifdef DIAGNOSTIC
517         if (pipe == NULL) {
518                 printf("usbd_close_pipe: pipe==NULL\n");
519                 return (USBD_NORMAL_COMPLETION);
520         }
521 #endif
522         s = splusb();
523         err = usbd_ar_pipe(pipe);
524         splx(s);
525         return (err);
526 }
527         
528 usbd_status 
529 usbd_clear_endpoint_stall(pipe)
530         usbd_pipe_handle pipe;
531 {
532         usbd_device_handle dev = pipe->device;
533         usb_device_request_t req;
534         usbd_status err;
535
536         DPRINTFN(8, ("usbd_clear_endpoint_stall\n"));
537
538         /* 
539          * Clearing en endpoint stall resets the enpoint toggle, so
540          * do the same to the HC toggle.
541          */
542         pipe->methods->cleartoggle(pipe);
543
544         req.bmRequestType = UT_WRITE_ENDPOINT;
545         req.bRequest = UR_CLEAR_FEATURE;
546         USETW(req.wValue, UF_ENDPOINT_HALT);
547         USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);
548         USETW(req.wLength, 0);
549         err = usbd_do_request(dev, &req, 0);
550 #if 0
551 XXX should we do this?
552         if (!err) {
553                 pipe->state = USBD_PIPE_ACTIVE;
554                 /* XXX activate pipe */
555         }
556 #endif
557         return (err);
558 }
559
560 usbd_status 
561 usbd_clear_endpoint_stall_async(pipe)
562         usbd_pipe_handle pipe;
563 {
564         usbd_device_handle dev = pipe->device;
565         usb_device_request_t req;
566         usbd_status err;
567
568         pipe->methods->cleartoggle(pipe);
569
570         req.bmRequestType = UT_WRITE_ENDPOINT;
571         req.bRequest = UR_CLEAR_FEATURE;
572         USETW(req.wValue, UF_ENDPOINT_HALT);
573         USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);
574         USETW(req.wLength, 0);
575         err = usbd_do_request_async(dev, &req, 0);
576         return (err);
577 }
578
579 usbd_status 
580 usbd_endpoint_count(iface, count)
581         usbd_interface_handle iface;
582         u_int8_t *count;
583 {
584         *count = iface->idesc->bNumEndpoints;
585         return (USBD_NORMAL_COMPLETION);
586 }
587
588 usbd_status 
589 usbd_interface_count(dev, count)
590         usbd_device_handle dev;
591         u_int8_t *count;
592 {
593         if (dev->cdesc == NULL)
594                 return (USBD_NOT_CONFIGURED);
595         *count = dev->cdesc->bNumInterface;
596         return (USBD_NORMAL_COMPLETION);
597 }
598
599 usbd_status 
600 usbd_interface2device_handle(iface, dev)
601         usbd_interface_handle iface;
602         usbd_device_handle *dev;
603 {
604         *dev = iface->device;
605         return (USBD_NORMAL_COMPLETION);
606 }
607
608 usbd_status 
609 usbd_device2interface_handle(dev, ifaceno, iface)
610         usbd_device_handle dev;
611         u_int8_t ifaceno;
612         usbd_interface_handle *iface;
613 {
614         if (dev->cdesc == NULL)
615                 return (USBD_NOT_CONFIGURED);
616         if (ifaceno >= dev->cdesc->bNumInterface)
617                 return (USBD_INVAL);
618         *iface = &dev->ifaces[ifaceno];
619         return (USBD_NORMAL_COMPLETION);
620 }
621
622 usbd_device_handle
623 usbd_pipe2device_handle(pipe)
624         usbd_pipe_handle pipe;
625 {
626         return (pipe->device);
627 }
628
629 /* XXXX use altno */
630 usbd_status
631 usbd_set_interface(iface, altidx)
632         usbd_interface_handle iface;
633         int altidx;
634 {
635         usb_device_request_t req;
636         usbd_status err;
637
638         if (LIST_FIRST(&iface->pipes) != 0)
639                 return (USBD_IN_USE);
640
641         if (iface->endpoints)
642                 free(iface->endpoints, M_USB);
643         iface->endpoints = 0;
644         iface->idesc = 0;
645
646         err = usbd_fill_iface_data(iface->device, iface->index, altidx);
647         if (err)
648                 return (err);
649
650         req.bmRequestType = UT_WRITE_INTERFACE;
651         req.bRequest = UR_SET_INTERFACE;
652         USETW(req.wValue, iface->idesc->bAlternateSetting);
653         USETW(req.wIndex, iface->idesc->bInterfaceNumber);
654         USETW(req.wLength, 0);
655         return (usbd_do_request(iface->device, &req, 0));
656 }
657
658 int
659 usbd_get_no_alts(cdesc, ifaceno)
660         usb_config_descriptor_t *cdesc;
661         int ifaceno;
662 {
663         char *p = (char *)cdesc;
664         char *end = p + UGETW(cdesc->wTotalLength);
665         usb_interface_descriptor_t *d;
666         int n;
667
668         for (n = 0; p < end; p += d->bLength) {
669                 d = (usb_interface_descriptor_t *)p;
670                 if (p + d->bLength <= end && 
671                     d->bDescriptorType == UDESC_INTERFACE &&
672                     d->bInterfaceNumber == ifaceno)
673                         n++;
674         }
675         return (n);
676 }
677
678 int
679 usbd_get_interface_altindex(iface)
680         usbd_interface_handle iface;
681 {
682         return (iface->altindex);
683 }
684
685 usbd_status
686 usbd_get_interface(iface, aiface)
687         usbd_interface_handle iface;
688         u_int8_t *aiface;
689 {
690         usb_device_request_t req;
691
692         req.bmRequestType = UT_READ_INTERFACE;
693         req.bRequest = UR_GET_INTERFACE;
694         USETW(req.wValue, 0);
695         USETW(req.wIndex, iface->idesc->bInterfaceNumber);
696         USETW(req.wLength, 1);
697         return (usbd_do_request(iface->device, &req, aiface));
698 }
699
700 /*** Internal routines ***/
701
702 /* Dequeue all pipe operations, called at splusb(). */
703 static usbd_status
704 usbd_ar_pipe(pipe)
705         usbd_pipe_handle pipe;
706 {
707         usbd_xfer_handle xfer;
708
709         SPLUSBCHECK;
710
711         DPRINTFN(2,("usbd_ar_pipe: pipe=%p\n", pipe));
712 #ifdef USB_DEBUG
713         if (usbdebug > 5)
714                 usbd_dump_queue(pipe);
715 #endif
716         pipe->repeat = 0;
717         while ((xfer = SIMPLEQ_FIRST(&pipe->queue)) != NULL) {
718                 DPRINTFN(2,("usbd_ar_pipe: pipe=%p xfer=%p (methods=%p)\n", 
719                             pipe, xfer, pipe->methods));
720                 /* Make the HC abort it (and invoke the callback). */
721                 pipe->methods->abort(xfer);
722                 /* XXX only for non-0 usbd_clear_endpoint_stall(pipe); */
723         }
724         return (USBD_NORMAL_COMPLETION);
725 }
726
727 /* Called at splusb() */
728 void
729 usb_transfer_complete(xfer)
730         usbd_xfer_handle xfer;
731 {
732         usbd_pipe_handle pipe = xfer->pipe;
733         usb_dma_t *dmap = &xfer->dmabuf;
734         int repeat = pipe->repeat;
735         int polling;
736
737         SPLUSBCHECK;
738
739         DPRINTFN(5, ("usb_transfer_complete: pipe=%p xfer=%p status=%d "
740                      "actlen=%d\n", pipe, xfer, xfer->status, xfer->actlen));
741
742 #ifdef DIAGNOSTIC
743         if (pipe == NULL) {
744                 printf("usbd_transfer_cb: pipe==0, xfer=%p\n", xfer);
745                 return;
746         }
747 #endif
748         polling = pipe->device->bus->use_polling;
749         /* XXXX */
750         if (polling)
751                 pipe->running = 0;
752
753         if (!(xfer->flags & USBD_NO_COPY) && xfer->actlen != 0 &&
754             usbd_xfer_isread(xfer)) {
755 #ifdef DIAGNOSTIC
756                 if (xfer->actlen > xfer->length) {
757                         printf("usb_transfer_complete: actlen > len %d > %d\n",
758                                xfer->actlen, xfer->length);
759                         xfer->actlen = xfer->length;
760                 }
761 #endif
762                 memcpy(xfer->buffer, KERNADDR(dmap), xfer->actlen);
763         }
764
765         /* if we allocated the buffer in usbd_transfer() we free it here. */
766         if (xfer->rqflags & URQ_AUTO_DMABUF) {
767                 if (!repeat) {
768                         struct usbd_bus *bus = pipe->device->bus;
769                         bus->methods->freem(bus, dmap);
770                         xfer->rqflags &= ~URQ_AUTO_DMABUF;
771                 }
772         }
773
774         if (pipe->methods->done != NULL)
775                 pipe->methods->done(xfer);
776
777         if (!repeat) {
778                 /* Remove request from queue. */
779 #ifdef DIAGNOSTIC
780                 if (xfer != SIMPLEQ_FIRST(&pipe->queue))
781                         printf("usb_transfer_complete: bad dequeue %p != %p\n",
782                                xfer, SIMPLEQ_FIRST(&pipe->queue));
783 #endif
784                 SIMPLEQ_REMOVE_HEAD(&pipe->queue, xfer, next);
785         }
786
787         /* Count completed transfers. */
788         ++pipe->device->bus->stats.requests
789                 [pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE];
790
791         xfer->done = 1;
792         if (xfer->status == USBD_NORMAL_COMPLETION &&
793             xfer->actlen < xfer->length &&
794             !(xfer->flags & USBD_SHORT_XFER_OK)) {
795                 DPRINTFN(-1, ("usbd_transfer_cb: short transfer %d<%d\n",
796                               xfer->actlen, xfer->length));
797                 xfer->status = USBD_SHORT_XFER;
798         }
799
800         if (xfer->callback)
801                 xfer->callback(xfer, xfer->priv, xfer->status);
802
803         if ((xfer->flags & USBD_SYNCHRONOUS) && !polling)
804                 wakeup(xfer);
805
806         if (!repeat) {
807                 /* XXX should we stop the queue on all errors? */
808                 if (xfer->status == USBD_CANCELLED ||
809                     xfer->status == USBD_TIMEOUT)
810                         pipe->running = 0;
811                 else
812                         usbd_start_next(pipe);
813         }
814 }
815
816 usbd_status
817 usb_insert_transfer(xfer)
818         usbd_xfer_handle xfer;
819 {
820         usbd_pipe_handle pipe = xfer->pipe;
821         usbd_status err;
822         int s;
823
824         DPRINTFN(5,("usb_insert_transfer: pipe=%p running=%d timeout=%d\n", 
825                     pipe, pipe->running, xfer->timeout));
826         s = splusb();
827         SIMPLEQ_INSERT_TAIL(&pipe->queue, xfer, next);
828         if (pipe->running)
829                 err = USBD_IN_PROGRESS;
830         else {
831                 pipe->running = 1;
832                 err = USBD_NORMAL_COMPLETION;
833         }
834         splx(s);
835         return (err);
836 }
837
838 /* Called at splusb() */
839 void
840 usbd_start_next(pipe)
841         usbd_pipe_handle pipe;
842 {
843         usbd_xfer_handle xfer;
844         usbd_status err;
845
846         SPLUSBCHECK;
847
848 #ifdef DIAGNOSTIC
849         if (pipe == NULL) {
850                 printf("usbd_start_next: pipe == NULL\n");
851                 return;
852         }
853         if (pipe->methods == NULL || pipe->methods->start == NULL) {
854                 printf("usbd_start_next: pipe=%p no start method\n", pipe);
855                 return;
856         }
857 #endif
858
859         /* Get next request in queue. */
860         xfer = SIMPLEQ_FIRST(&pipe->queue);
861         DPRINTFN(5, ("usbd_start_next: pipe=%p, xfer=%p\n", pipe, xfer));
862         if (xfer == NULL) {
863                 pipe->running = 0;
864         } else {
865                 err = pipe->methods->start(xfer);
866                 if (err != USBD_IN_PROGRESS) {
867                         printf("usbd_start_next: error=%d\n", err);
868                         pipe->running = 0;
869                         /* XXX do what? */
870                 }
871         }
872 }
873
874 usbd_status
875 usbd_do_request(dev, req, data)
876         usbd_device_handle dev;
877         usb_device_request_t *req;
878         void *data;
879 {
880         return (usbd_do_request_flags(dev, req, data, 0, 0));
881 }
882
883 usbd_status
884 usbd_do_request_flags(dev, req, data, flags, actlen)
885         usbd_device_handle dev;
886         usb_device_request_t *req;
887         void *data;
888         u_int16_t flags;
889         int *actlen;
890 {
891         usbd_xfer_handle xfer;
892         usbd_status err;
893
894 #ifdef DIAGNOSTIC
895 #if defined(__i386__)
896         KASSERT(intr_nesting_level == 0,
897                 ("ohci_abort_req in interrupt context"));
898 #endif
899         if (dev->bus->intr_context) {
900                 printf("usbd_do_request: not in process context\n");
901                 return (USBD_INVAL);
902         }
903 #endif
904
905         xfer = usbd_alloc_request(dev);
906         if (xfer == NULL)
907                 return (USBD_NOMEM);
908         usbd_setup_default_request(xfer, dev, 0, USBD_DEFAULT_TIMEOUT, req,
909                                    data, UGETW(req->wLength), flags, 0);
910         err = usbd_sync_transfer(xfer);
911 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
912         if (xfer->actlen > xfer->length)
913                 DPRINTF(("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
914                          "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
915                          dev->address, xfer->request.bmRequestType,
916                          xfer->request.bRequest, UGETW(xfer->request.wValue),
917                          UGETW(xfer->request.wIndex), 
918                          UGETW(xfer->request.wLength), 
919                          xfer->length, xfer->actlen));
920 #endif
921         if (actlen != NULL)
922                 *actlen = xfer->actlen;
923         if (err == USBD_STALLED) {
924                 /* 
925                  * The control endpoint has stalled.  Control endpoints
926                  * should not halt, but some may do so anyway so clear
927                  * any halt condition.
928                  */
929                 usb_device_request_t treq;
930                 usb_status_t status;
931                 u_int16_t s;
932                 usbd_status nerr;
933
934                 treq.bmRequestType = UT_READ_ENDPOINT;
935                 treq.bRequest = UR_GET_STATUS;
936                 USETW(treq.wValue, 0);
937                 USETW(treq.wIndex, 0);
938                 USETW(treq.wLength, sizeof(usb_status_t));
939                 usbd_setup_default_request(xfer, dev, 0, USBD_DEFAULT_TIMEOUT,
940                                            &treq, &status,sizeof(usb_status_t),
941                                            0, 0);
942                 nerr = usbd_sync_transfer(xfer);
943                 if (nerr)
944                         goto bad;
945                 s = UGETW(status.wStatus);
946                 DPRINTF(("usbd_do_request: status = 0x%04x\n", s));
947                 if (!(s & UES_HALT))
948                         goto bad;
949                 treq.bmRequestType = UT_WRITE_ENDPOINT;
950                 treq.bRequest = UR_CLEAR_FEATURE;
951                 USETW(treq.wValue, UF_ENDPOINT_HALT);
952                 USETW(treq.wIndex, 0);
953                 USETW(treq.wLength, 0);
954                 usbd_setup_default_request(xfer, dev, 0, USBD_DEFAULT_TIMEOUT,
955                                            &treq, &status, 0, 0, 0);
956                 nerr = usbd_sync_transfer(xfer);
957                 if (nerr)
958                         goto bad;
959         }
960
961  bad:
962         usbd_free_request(xfer);
963         return (err);
964 }
965
966 void
967 usbd_do_request_async_cb(xfer, priv, status)
968         usbd_xfer_handle xfer;
969         usbd_private_handle priv;
970         usbd_status status;
971 {
972 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
973         if (xfer->actlen > xfer->length)
974                 DPRINTF(("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
975                          "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
976                          xfer->pipe->device->address, 
977                          xfer->request.bmRequestType,
978                          xfer->request.bRequest, UGETW(xfer->request.wValue),
979                          UGETW(xfer->request.wIndex), 
980                          UGETW(xfer->request.wLength), 
981                          xfer->length, xfer->actlen));
982 #endif
983         usbd_free_request(xfer);
984 }
985
986 /*
987  * Execute a request without waiting for completion.
988  * Can be used from interrupt context.
989  */
990 usbd_status
991 usbd_do_request_async(dev, req, data)
992         usbd_device_handle dev;
993         usb_device_request_t *req;
994         void *data;
995 {
996         usbd_xfer_handle xfer;
997         usbd_status err;
998
999         xfer = usbd_alloc_request(dev);
1000         if (xfer == NULL)
1001                 return (USBD_NOMEM);
1002         usbd_setup_default_request(xfer, dev, 0, USBD_DEFAULT_TIMEOUT, req,
1003             data, UGETW(req->wLength), 0, usbd_do_request_async_cb);
1004         err = usbd_transfer(xfer);
1005         if (err != USBD_IN_PROGRESS) {
1006                 usbd_free_request(xfer);
1007                 return (err);
1008         }
1009         return (USBD_NORMAL_COMPLETION);
1010 }
1011
1012 struct usbd_quirks *
1013 usbd_get_quirks(dev)
1014         usbd_device_handle dev;
1015 {
1016         return (dev->quirks);
1017 }
1018
1019 /* XXX do periodic free() of free list */
1020
1021 /*
1022  * Called from keyboard driver when in polling mode.
1023  */
1024 void
1025 usbd_dopoll(iface)
1026         usbd_interface_handle iface;
1027 {
1028         iface->device->bus->methods->do_poll(iface->device->bus);
1029 }
1030
1031 void
1032 usbd_set_polling(iface, on)
1033         usbd_interface_handle iface;
1034         int on;
1035 {
1036         if (on)
1037                 iface->device->bus->use_polling++;
1038         else
1039                 iface->device->bus->use_polling--;
1040 }
1041
1042
1043 usb_endpoint_descriptor_t *
1044 usbd_get_endpoint_descriptor(iface, address)
1045         usbd_interface_handle iface;
1046         u_int8_t address;
1047 {
1048         struct usbd_endpoint *ep;
1049         int i;
1050
1051         for (i = 0; i < iface->idesc->bNumEndpoints; i++) {
1052                 ep = &iface->endpoints[i];
1053                 if (ep->edesc->bEndpointAddress == address)
1054                         return (iface->endpoints[i].edesc);
1055         }
1056         return (0);
1057 }
1058
1059 #if defined(__FreeBSD__)
1060 int
1061 usbd_driver_load(module_t mod, int what, void *arg)
1062 {
1063         /* XXX should implement something like a function that removes all generic devices */
1064  
1065         return (0);
1066 }
1067
1068 #endif