]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/usb/usbdi.c
Add comments, change variable names to make them consistent (r -> err,
[FreeBSD/FreeBSD.git] / sys / dev / usb / usbdi.c
1 /*      $NetBSD: usbdi.c,v 1.20 1999/01/08 11:58:26 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 #include <sys/kernel.h>
44 #if defined(__NetBSD__)
45 #include <sys/device.h>
46 #else
47 #include <sys/module.h>
48 #include <sys/bus.h>
49 #include <sys/conf.h>
50 #endif
51 #include <sys/malloc.h>
52 #include <sys/proc.h>
53
54 #include <dev/usb/usb.h>
55
56 #include <dev/usb/usbdi.h>
57 #include <dev/usb/usbdi_util.h>
58 #include <dev/usb/usbdivar.h>
59
60 #if defined(__FreeBSD__)
61 #include "usb_if.h"
62 #endif
63
64 #ifdef USB_DEBUG
65 #define DPRINTF(x)      if (usbdebug) logprintf x
66 #define DPRINTFN(n,x)   if (usbdebug>(n)) logprintf x
67 extern int usbdebug;
68 #else
69 #define DPRINTF(x)
70 #define DPRINTFN(n,x)
71 #endif
72
73 static usbd_status usbd_ar_pipe  __P((usbd_pipe_handle pipe));
74 static usbd_status usbd_ar_iface __P((usbd_interface_handle iface));
75 static void usbd_transfer_cb __P((usbd_request_handle reqh));
76 static void usbd_sync_transfer_cb __P((usbd_request_handle reqh));
77 static usbd_status usbd_do_transfer __P((usbd_request_handle reqh));
78 void usbd_do_request_async_cb 
79         __P((usbd_request_handle, usbd_private_handle, usbd_status));
80
81 static SIMPLEQ_HEAD(, usbd_request) usbd_free_requests;
82
83 #ifdef USB_DEBUG
84 char *usbd_error_strs[USBD_ERROR_MAX] = {
85         "NORMAL_COMPLETION",
86         "IN_PROGRESS",
87         "PENDING_REQUESTS",
88         "NOT_STARTED",
89         "INVAL",
90         "IS_IDLE",
91         "NOMEM",
92         "CANCELLED",
93         "BAD_ADDRESS",
94         "IN_USE",
95         "INTERFACE_NOT_ACTIVE",
96         "NO_ADDR",
97         "SET_ADDR_FAILED",
98         "NO_POWER",
99         "TOO_DEEP",
100         "IOERROR",
101         "NOT_CONFIGURED",
102         "TIMEOUT",
103         "SHORT_XFER",
104         "STALLED",
105         "XXX",
106 };
107 #endif
108
109
110 usbd_status 
111 usbd_open_pipe(iface, address, flags, pipe)
112         usbd_interface_handle iface;
113         u_int8_t address;
114         u_int8_t flags;
115         usbd_pipe_handle *pipe;
116
117         usbd_pipe_handle p;
118         struct usbd_endpoint *ep;
119         usbd_status r;
120         int i;
121
122         if (iface->state != USBD_INTERFACE_ACTIVE)
123                 return (USBD_INTERFACE_NOT_ACTIVE);
124         for (i = 0; i < iface->idesc->bNumEndpoints; i++) {
125                 ep = &iface->endpoints[i];
126                 if (ep->edesc->bEndpointAddress == address)
127                         goto found;
128         }
129         return (USBD_BAD_ADDRESS);
130  found:
131         if ((flags & USBD_EXCLUSIVE_USE) &&
132             ep->refcnt != 0)
133                 return (USBD_IN_USE);
134         r = usbd_setup_pipe(iface->device, iface, ep, &p);
135         if (r != USBD_NORMAL_COMPLETION)
136                 return (r);
137         LIST_INSERT_HEAD(&iface->pipes, p, next);
138         *pipe = p;
139         return (USBD_NORMAL_COMPLETION);
140 }
141
142 usbd_status 
143 usbd_open_pipe_intr(iface, address, flags, pipe, priv, buffer, length, cb)
144         usbd_interface_handle iface;
145         u_int8_t address;
146         u_int8_t flags;
147         usbd_pipe_handle *pipe;
148         usbd_private_handle priv;
149         void *buffer;
150         u_int32_t length;
151         usbd_callback cb;
152 {
153         usbd_status r;
154         usbd_request_handle reqh;
155         usbd_pipe_handle ipipe;
156
157         reqh = usbd_alloc_request();
158         if (reqh == 0)
159                 return (USBD_NOMEM);
160         r = usbd_open_pipe(iface, address, USBD_EXCLUSIVE_USE, &ipipe);
161         if (r != USBD_NORMAL_COMPLETION)
162                 goto bad1;
163         r = usbd_setup_request(reqh, ipipe, priv, buffer, length, 
164                                USBD_XFER_IN | flags, USBD_NO_TIMEOUT, cb);
165         if (r != USBD_NORMAL_COMPLETION)
166                 goto bad2;
167         ipipe->intrreqh = reqh;
168         r = usbd_transfer(reqh);
169         *pipe = ipipe;
170         if (r != USBD_IN_PROGRESS)
171                 goto bad3;
172         return (USBD_NORMAL_COMPLETION);
173
174  bad3:
175         ipipe->intrreqh = 0;
176  bad2:
177         usbd_close_pipe(ipipe);
178  bad1:
179         usbd_free_request(reqh);
180         return r;
181 }
182
183 usbd_status 
184 usbd_open_pipe_iso(iface, address, flags, pipe, priv, bufsize, nbuf, cb)
185         usbd_interface_handle iface;
186         u_int8_t address;
187         u_int8_t flags;
188         usbd_pipe_handle *pipe;
189         usbd_private_handle priv;
190         u_int32_t bufsize;
191         u_int32_t nbuf;
192         usbd_callback cb;
193 {
194         usbd_status r;
195         usbd_pipe_handle p;
196
197         r = usbd_open_pipe(iface, address, USBD_EXCLUSIVE_USE, &p);
198         if (r != USBD_NORMAL_COMPLETION)
199                 return (r);
200         if (!p->methods->isobuf) {
201                 usbd_close_pipe(p);
202                 return (USBD_INVAL);
203         }
204         r = p->methods->isobuf(p, bufsize, nbuf);
205         if (r != USBD_NORMAL_COMPLETION) {
206                 usbd_close_pipe(p);
207                 return (r);
208         }       
209         *pipe = p;
210         return r;
211 }
212
213 usbd_status
214 usbd_close_pipe(pipe)
215         usbd_pipe_handle pipe;
216 {
217         if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
218                 return (USBD_INTERFACE_NOT_ACTIVE);
219         if (--pipe->refcnt != 0)
220                 return (USBD_NORMAL_COMPLETION);
221         if (SIMPLEQ_FIRST(&pipe->queue) != 0)
222                 return (USBD_PENDING_REQUESTS);
223         LIST_REMOVE(pipe, next);
224         pipe->endpoint->refcnt--;
225         pipe->methods->close(pipe);
226         if (pipe->intrreqh)
227                 usbd_free_request(pipe->intrreqh);
228         free(pipe, M_USB);
229         return (USBD_NORMAL_COMPLETION);
230 }
231
232 usbd_status 
233 usbd_transfer(reqh)
234         usbd_request_handle reqh;
235 {
236         reqh->xfercb = usbd_transfer_cb;
237         return (usbd_do_transfer(reqh));
238 }
239
240 static usbd_status
241 usbd_do_transfer(reqh)
242         usbd_request_handle reqh;
243 {
244         usbd_pipe_handle pipe = reqh->pipe;
245
246         DPRINTFN(10,("usbd_do_transfer: reqh=%p\n", reqh));
247         reqh->done = 0;
248         return (pipe->methods->transfer(reqh));
249 }
250
251 usbd_request_handle 
252 usbd_alloc_request()
253 {
254         usbd_request_handle reqh;
255
256         reqh = SIMPLEQ_FIRST(&usbd_free_requests);
257         if (reqh)
258 #if defined(__NetBSD__)
259                 SIMPLEQ_REMOVE_HEAD(&usbd_free_requests, reqh, next);
260 #elif defined(__FreeBSD__)
261                 SIMPLEQ_REMOVE_HEAD(&usbd_free_requests, next);
262 #endif
263         else
264                 reqh = malloc(sizeof(*reqh), M_USB, M_NOWAIT);
265         if (!reqh)
266                 return (0);
267         memset(reqh, 0, sizeof *reqh);
268         return (reqh);
269 }
270
271 usbd_status 
272 usbd_free_request(reqh)
273         usbd_request_handle reqh;
274 {
275         SIMPLEQ_INSERT_HEAD(&usbd_free_requests, reqh, next);
276         return (USBD_NORMAL_COMPLETION);
277 }
278
279 usbd_status 
280 usbd_setup_request(reqh, pipe, priv, buffer, length, flags, timeout, callback)
281         usbd_request_handle reqh;
282         usbd_pipe_handle pipe;
283         usbd_private_handle priv;
284         void *buffer;
285         u_int32_t length;
286         u_int16_t flags;
287         u_int32_t timeout;
288         void (*callback) __P((usbd_request_handle,
289                               usbd_private_handle,
290                               usbd_status));
291 {
292         reqh->pipe = pipe;
293         reqh->priv = priv;
294         reqh->buffer = buffer;
295         reqh->length = length;
296         reqh->actlen = 0;
297         reqh->flags = flags;
298         reqh->timeout = timeout;
299         reqh->status = USBD_NOT_STARTED;
300         reqh->callback = callback;
301         reqh->retries = 1;
302         reqh->isreq = 0;
303         return (USBD_NORMAL_COMPLETION);
304 }
305
306 usbd_status 
307 usbd_setup_device_request(reqh, req)
308         usbd_request_handle reqh;
309         usb_device_request_t *req;
310 {
311         reqh->isreq = 1;
312         reqh->request = *req;
313         return (USBD_NORMAL_COMPLETION);
314 }
315
316 usbd_status 
317 usbd_setup_default_request(reqh, dev, priv, timeout, req, buffer, 
318                            length, flags, callback)
319         usbd_request_handle reqh;
320         usbd_device_handle dev;
321         usbd_private_handle priv;
322         u_int32_t timeout;
323         usb_device_request_t *req;
324         void *buffer;
325         u_int32_t length;
326         u_int16_t flags;
327         void (*callback) __P((usbd_request_handle,
328                               usbd_private_handle,
329                               usbd_status));
330 {
331         reqh->pipe = dev->default_pipe;
332         reqh->priv = priv;
333         reqh->buffer = buffer;
334         reqh->length = length;
335         reqh->actlen = 0;
336         reqh->flags = flags;
337         reqh->timeout = timeout;
338         reqh->status = USBD_NOT_STARTED;
339         reqh->callback = callback;
340         reqh->request = *req;
341         reqh->retries = 1;
342         reqh->isreq = 1;
343         return (USBD_NORMAL_COMPLETION);
344 }
345
346 usbd_status 
347 usbd_set_request_timeout(reqh, timeout)
348         usbd_request_handle reqh;
349         u_int32_t timeout;
350 {
351         reqh->timeout = timeout;
352         return (USBD_NORMAL_COMPLETION);
353 }
354
355 usbd_status 
356 usbd_get_request_status(reqh, priv, buffer, count, status)
357         usbd_request_handle reqh;
358         usbd_private_handle *priv;
359         void **buffer;
360         u_int32_t *count;
361         usbd_status *status;
362 {
363         if (priv)
364                 *priv = reqh->priv;
365         if (buffer)
366                 *buffer = reqh->buffer;
367         if (count)
368                 *count = reqh->actlen;
369         if (status)
370                 *status = reqh->status;
371
372         return (USBD_NORMAL_COMPLETION);
373 }
374
375 usbd_status 
376 usbd_request_device_data(reqh, req)
377         usbd_request_handle reqh;
378         usb_device_request_t *req;
379 {
380         if (!reqh->isreq) 
381                 return (USBD_INVAL);
382         *req = reqh->request;
383         return (USBD_NORMAL_COMPLETION);
384 }
385
386 #if 0
387 usb_descriptor_t *
388 usbd_get_descriptor(iface, desc_type)
389         usbd_interface_handle *iface;
390         u_int8_t desc_type;
391 XX
392 #endif
393
394 usb_config_descriptor_t *
395 usbd_get_config_descriptor(dev)
396         usbd_device_handle dev;
397 {
398         return (dev->cdesc);
399 }
400
401 usb_interface_descriptor_t *
402 usbd_get_interface_descriptor(iface)
403         usbd_interface_handle iface;
404 {
405         return (iface->idesc);
406 }
407
408 usb_device_descriptor_t *
409 usbd_get_device_descriptor(dev)
410         usbd_device_handle dev;
411 {
412         return (&dev->ddesc);
413 }
414
415 usb_endpoint_descriptor_t *
416 usbd_interface2endpoint_descriptor(iface, index)
417         usbd_interface_handle iface;
418         u_int8_t index;
419 {
420         if (index >= iface->idesc->bNumEndpoints)
421                 return (0);
422         return (iface->endpoints[index].edesc);
423 }
424
425 usbd_status 
426 usbd_set_configuration(dev, conf)
427         usbd_device_handle dev;
428         u_int8_t conf;
429 {
430         return usbd_set_config_no(dev, conf, 0);
431 }
432
433 usbd_status 
434 usbd_retry_request(reqh, retry_count)
435         usbd_request_handle reqh;
436         u_int32_t retry_count;
437 {
438         usbd_status r;
439
440         r = usbd_set_pipe_state(reqh->pipe, USBD_PIPE_ACTIVE);
441         if (r != USBD_NORMAL_COMPLETION)
442                 return (r);
443         reqh->retries = retry_count;
444         return (usbd_transfer(reqh));
445 }
446
447 usbd_status 
448 usbd_abort_pipe(pipe)
449         usbd_pipe_handle pipe;
450 {
451         usbd_status r;
452         int s, state;
453
454         if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
455                 return (USBD_INTERFACE_NOT_ACTIVE);
456         s = splusb();
457         state = pipe->state;
458         r = usbd_ar_pipe(pipe);
459         pipe->state = state;
460         splx(s);
461         return (r);
462 }
463         
464 usbd_status 
465 usbd_abort_interface(iface)
466         usbd_interface_handle iface;
467 {
468         usbd_status r;
469         int s, st;
470
471         s = splusb();
472         st = iface->state;
473         r = usbd_ar_iface(iface);
474         iface->state = st;
475         splx(s);
476         return (r);
477 }
478
479 usbd_status 
480 usbd_reset_pipe(pipe)
481         usbd_pipe_handle pipe;
482 {
483         usbd_status r;
484         int s;
485
486         if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
487                 return (USBD_INTERFACE_NOT_ACTIVE);
488         s = splusb();
489         r = usbd_ar_pipe(pipe);
490         /* XXX anything else */
491         pipe->state = USBD_PIPE_ACTIVE;
492         splx(s);
493         return (r);
494 }
495
496 usbd_status 
497 usbd_reset_interface(iface)
498         usbd_interface_handle iface;
499 {
500         usbd_status r;
501         int s;
502
503         s = splusb();
504         r = usbd_ar_iface(iface);
505         /* XXX anything else */
506         iface->state = USBD_INTERFACE_ACTIVE;
507         splx(s);
508         return (r);
509 }
510
511 usbd_status 
512 usbd_clear_endpoint_stall(pipe)
513         usbd_pipe_handle pipe;
514 {
515         usbd_device_handle dev = pipe->device;
516         usb_device_request_t req;
517         usbd_status r;
518
519         req.bmRequestType = UT_WRITE_ENDPOINT;
520         req.bRequest = UR_CLEAR_FEATURE;
521         USETW(req.wValue, UF_ENDPOINT_HALT);
522         USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);
523         USETW(req.wLength, 0);
524         r = usbd_do_request(dev, &req, 0);
525 #if 0
526 XXX should we do this?
527         if (r == USBD_NORMAL_COMPLETION) {
528                 pipe->state = USBD_PIPE_ACTIVE;
529                 /* XXX activate pipe */
530         }
531 #endif
532         return (r);
533 }
534
535 usbd_status 
536 usbd_clear_endpoint_stall_async(pipe)
537         usbd_pipe_handle pipe;
538 {
539         usbd_device_handle dev = pipe->device;
540         usb_device_request_t req;
541         usbd_status r;
542
543         req.bmRequestType = UT_WRITE_ENDPOINT;
544         req.bRequest = UR_CLEAR_FEATURE;
545         USETW(req.wValue, UF_ENDPOINT_HALT);
546         USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);
547         USETW(req.wLength, 0);
548         r = usbd_do_request_async(dev, &req, 0);
549         return (r);
550 }
551
552 usbd_status 
553 usbd_set_pipe_state(pipe, state)
554         usbd_pipe_handle pipe;
555         usbd_pipe_state state;
556 {
557         int s;
558         usbd_status r;
559         usbd_request_handle reqh;
560
561         if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
562                 return (USBD_INTERFACE_NOT_ACTIVE);
563         if (state != USBD_PIPE_ACTIVE &&
564             state != USBD_PIPE_STALLED &&
565             state != USBD_PIPE_IDLE)
566                 return (USBD_INVAL);
567         pipe->state = state;
568         r = USBD_NORMAL_COMPLETION;
569         if (state == USBD_PIPE_ACTIVE) {
570                 s = splusb();
571                 if (!pipe->running) {
572                         reqh = SIMPLEQ_FIRST(&pipe->queue);
573                         if (reqh != 0) {
574                                 pipe->running = 1;
575                                 splx(s);
576                                 r = pipe->methods->start(reqh);
577                         } else
578                                 splx(s);
579                 } else
580                         splx(s);
581         }
582         return (r);
583 }
584
585 usbd_status 
586 usbd_get_pipe_state(pipe, state, endpoint_state, request_count)
587         usbd_pipe_handle pipe;
588         usbd_pipe_state *state;
589         u_int32_t *endpoint_state;
590         u_int32_t *request_count;
591 {
592         int n;
593         usbd_request_handle r;
594
595         *state = pipe->state;
596         *endpoint_state = pipe->endpoint->state;
597         for (r = SIMPLEQ_FIRST(&pipe->queue), n = 0; 
598              r != 0; 
599              r = SIMPLEQ_NEXT(r, next), n++)
600                 ;
601         *request_count = n;
602         return (USBD_NORMAL_COMPLETION);
603 }
604
605 usbd_status 
606 usbd_set_interface_state(iface, state)
607         usbd_interface_handle iface;
608         usbd_interface_state state;
609 {
610         int ps;
611         usbd_pipe_handle p;
612
613         if (state == USBD_INTERFACE_ACTIVE)
614                 ps = USBD_PIPE_ACTIVE;
615         else if (state == USBD_INTERFACE_STALLED)
616                 ps = USBD_PIPE_STALLED;
617         else if (state == USBD_INTERFACE_IDLE)
618                 ps = USBD_PIPE_IDLE;
619         else
620                 return (USBD_INVAL);
621         iface->state = USBD_INTERFACE_ACTIVE; /* to allow setting the pipe */
622         for (p = LIST_FIRST(&iface->pipes); p != 0; p = LIST_NEXT(p, next))
623                 usbd_set_pipe_state(p, ps);
624         iface->state = state;
625         return (USBD_NORMAL_COMPLETION);
626 }
627
628 usbd_status 
629 usbd_get_interface_state(iface, state)
630         usbd_interface_handle iface;
631         usbd_interface_state *state;
632 {
633         *state = iface->state;
634         return (USBD_NORMAL_COMPLETION);
635 }
636
637 usbd_status 
638 usbd_get_device_state(dev, state)
639         usbd_device_handle dev;
640         usbd_device_state *state;
641 {
642         *state = dev->state;
643         return (USBD_NORMAL_COMPLETION);
644 }
645
646 #if 0
647 usbd_status 
648 usbd_set_device_state(dev, state)
649         usbd_device_handle dev;
650         usbd_device_state state;
651 X
652 #endif
653
654 usbd_status 
655 usbd_device_address(dev, address)
656         usbd_device_handle dev;
657         u_int8_t *address;
658 {
659         *address = dev->address;
660         return (USBD_NORMAL_COMPLETION);
661 }
662
663 usbd_status 
664 usbd_endpoint_address(pipe, address)
665         usbd_pipe_handle pipe;
666         u_int8_t *address;
667 {
668         *address = pipe->endpoint->edesc->bEndpointAddress;
669         return (USBD_NORMAL_COMPLETION);
670 }
671
672 usbd_status 
673 usbd_endpoint_count(iface, count)
674         usbd_interface_handle iface;
675         u_int8_t *count;
676 {
677         *count = iface->idesc->bNumEndpoints;
678         return (USBD_NORMAL_COMPLETION);
679 }
680
681 usbd_status 
682 usbd_interface_count(dev, count)
683         usbd_device_handle dev;
684         u_int8_t *count;
685 {
686         if (!dev->cdesc)
687                 return (USBD_NOT_CONFIGURED);
688         *count = dev->cdesc->bNumInterface;
689         return (USBD_NORMAL_COMPLETION);
690 }
691
692 #if 0
693 u_int8_t 
694 usbd_bus_count()
695 {
696         return (usb_bus_count());
697 }
698
699 usbd_status 
700 usbd_get_bus_handle(index, bus)
701         u_int8_t index;
702         usbd_bus_handle *bus;
703 {
704         return (usb_get_bus_handle(index, bus));
705 }
706
707 usbd_status 
708 usbd_get_root_hub(bus, dev)
709         usbd_bus_handle bus; 
710         usbd_device_handle *dev;
711 {
712         *dev = bus->root_hub;
713         return (USBD_NORMAL_COMPLETION);
714 }
715
716 usbd_status 
717 usbd_port_count(dev, nports)
718         usbd_device_handle dev;
719         u_int8_t *nports;
720 {
721         if (dev->hub == 0)
722                 return (USBD_INVAL);
723         *nports = dev->hub->hubdesc.bNbrPorts;
724         return (USBD_NORMAL_COMPLETION);
725 }
726
727 usbd_status 
728 usbd_hub2device_handle(dev, port, devp)
729         usbd_device_handle dev;
730         u_int8_t port;
731         usbd_device_handle *devp;
732 {
733         if (dev->hub == 0 || port >= dev->hub->hubdesc.bNbrPorts || 
734             dev->hub->ports[port].device == 0)
735                 return (USBD_INVAL);
736         *devp = dev->hub->ports[port].device;
737         return (USBD_NORMAL_COMPLETION);
738 }
739 #endif
740
741 usbd_status 
742 usbd_request2pipe_handle(reqh, pipe)
743         usbd_request_handle reqh;
744         usbd_pipe_handle *pipe;
745 {
746         *pipe = reqh->pipe;
747         return (USBD_NORMAL_COMPLETION);
748 }
749
750 usbd_status 
751 usbd_pipe2interface_handle(pipe, iface)
752         usbd_pipe_handle pipe;
753         usbd_interface_handle *iface;
754 {
755         *iface = pipe->iface;
756         return (USBD_NORMAL_COMPLETION);
757 }
758
759 usbd_status 
760 usbd_interface2device_handle(iface, dev)
761         usbd_interface_handle iface;
762         usbd_device_handle *dev;
763 {
764         *dev = iface->device;
765         return (USBD_NORMAL_COMPLETION);
766 }
767
768 usbd_status 
769 usbd_device2bus_handle(dev, bus)
770         usbd_device_handle dev;
771         usbd_bus_handle *bus;
772 {
773         *bus = dev->bus;
774         return (USBD_NORMAL_COMPLETION);
775 }
776
777 usbd_status 
778 usbd_device2interface_handle(dev, ifaceno, iface)
779         usbd_device_handle dev;
780         u_int8_t ifaceno;
781         usbd_interface_handle *iface;
782 {
783         if (!dev->cdesc)
784                 return (USBD_NOT_CONFIGURED);
785         if (ifaceno >= dev->cdesc->bNumInterface)
786                 return (USBD_INVAL);
787         *iface = &dev->ifaces[ifaceno];
788         return (USBD_NORMAL_COMPLETION);
789 }
790
791 usbd_status 
792 usbd_set_interface_private_handle(iface, priv)
793         usbd_interface_handle iface;
794         usbd_private_handle priv;
795 {
796         iface->priv = priv;
797         return (USBD_NORMAL_COMPLETION);
798 }
799
800 usbd_status 
801 usbd_get_interface_private_handle(iface, priv)
802         usbd_interface_handle iface;
803         usbd_private_handle *priv;
804 {
805         *priv = iface->priv;
806         return (USBD_NORMAL_COMPLETION);
807 }
808
809 usbd_status 
810 usbd_reference_pipe(pipe)
811         usbd_pipe_handle pipe;
812 {
813         pipe->refcnt++;
814         return (USBD_NORMAL_COMPLETION);
815 }
816
817 usbd_status 
818 usbd_dereference_pipe(pipe)
819         usbd_pipe_handle pipe;
820 {
821         pipe->refcnt--;
822         return (USBD_NORMAL_COMPLETION);
823 }
824
825 usbd_lock_token
826 usbd_lock()
827 {
828         return (splusb());
829 }
830
831 void
832 usbd_unlock(tok)
833         usbd_lock_token tok;
834 {
835         splx(tok);
836 }
837
838 /* XXXX use altno */
839 usbd_status
840 usbd_set_interface(iface, altidx)
841         usbd_interface_handle iface;
842         int altidx;
843 {
844         usb_device_request_t req;
845         usbd_status r;
846
847         if (LIST_FIRST(&iface->pipes) != 0)
848                 return (USBD_IN_USE);
849
850         if (iface->endpoints)
851                 free(iface->endpoints, M_USB);
852         iface->endpoints = 0;
853         iface->idesc = 0;
854         iface->state = USBD_INTERFACE_IDLE;
855
856         r = usbd_fill_iface_data(iface->device, iface->index, altidx);
857         if (r != USBD_NORMAL_COMPLETION)
858                 return (r);
859
860         req.bmRequestType = UT_WRITE_INTERFACE;
861         req.bRequest = UR_SET_INTERFACE;
862         USETW(req.wValue, iface->idesc->bAlternateSetting);
863         USETW(req.wIndex, iface->idesc->bInterfaceNumber);
864         USETW(req.wLength, 0);
865         return usbd_do_request(iface->device, &req, 0);
866 }
867
868 int
869 usbd_get_no_alts(cdesc, ifaceno)
870         usb_config_descriptor_t *cdesc;
871         int ifaceno;
872 {
873         char *p = (char *)cdesc;
874         char *end = p + UGETW(cdesc->wTotalLength);
875         usb_interface_descriptor_t *d;
876         int n;
877
878         for (n = 0; p < end; p += d->bLength) {
879                 d = (usb_interface_descriptor_t *)p;
880                 if (p + d->bLength <= end && 
881                     d->bDescriptorType == UDESC_INTERFACE &&
882                     d->bInterfaceNumber == ifaceno)
883                         n++;
884         }
885         return (n);
886 }
887
888 int
889 usbd_get_interface_altindex(iface)
890         usbd_interface_handle iface;
891 {
892         return (iface->altindex);
893 }
894
895 usbd_status
896 usbd_get_interface(iface, aiface)
897         usbd_interface_handle iface;
898         u_int8_t *aiface;
899 {
900         usb_device_request_t req;
901
902         req.bmRequestType = UT_READ_INTERFACE;
903         req.bRequest = UR_GET_INTERFACE;
904         USETW(req.wValue, 0);
905         USETW(req.wIndex, iface->idesc->bInterfaceNumber);
906         USETW(req.wLength, 1);
907         return usbd_do_request(iface->device, &req, aiface);
908 }
909
910 /*** Internal routines ***/
911
912 /* Dequeue all pipe operations, called at splusb(). */
913 static usbd_status
914 usbd_ar_pipe(pipe)
915         usbd_pipe_handle pipe;
916 {
917         usbd_request_handle reqh;
918
919 #if 0
920         for (;;) {
921                 reqh = SIMPLEQ_FIRST(&pipe->queue);
922                 if (reqh == 0)
923                         break;
924 #if defined(__NetBSD__)
925                 SIMPLEQ_REMOVE_HEAD(&pipe->queue, reqh, next);
926 #elif defined(__FreeBSD__)
927                 SIMPLEQ_REMOVE_HEAD(&pipe->queue, next);
928 #endif
929                 reqh->status = USBD_CANCELLED;
930                 if (reqh->callback)
931                         reqh->callback(reqh, reqh->priv, reqh->status);
932         }
933 #else
934         while ((reqh = SIMPLEQ_FIRST(&pipe->queue))) {
935                 pipe->methods->abort(reqh);
936 #if defined(__NetBSD__)
937                 SIMPLEQ_REMOVE_HEAD(&pipe->queue, reqh, next);
938 #elif defined(__FreeBSD__)
939                 SIMPLEQ_REMOVE_HEAD(&pipe->queue, next);
940 #endif
941         }
942 #endif
943         return (USBD_NORMAL_COMPLETION);
944 }
945
946 /* Dequeue all interface operations, called at splusb(). */
947 static usbd_status
948 usbd_ar_iface(iface)
949         usbd_interface_handle iface;
950 {
951         usbd_pipe_handle p;
952         usbd_status r, ret = USBD_NORMAL_COMPLETION;
953
954         for (p = LIST_FIRST(&iface->pipes); p != 0; p = LIST_NEXT(p, next)) {
955                 r = usbd_ar_pipe(p);
956                 if (r != USBD_NORMAL_COMPLETION)
957                         ret = r;
958         }
959         return (ret);
960 }
961
962 static int usbd_global_init_done = 0;
963
964 void
965 usbd_init()
966 {
967         
968         if (!usbd_global_init_done) {
969                 usbd_global_init_done = 1;
970                 SIMPLEQ_INIT(&usbd_free_requests);
971
972 #if defined(__FreeBSD__)
973                 cdevsw_add(&usb_cdevsw);
974 #endif
975         }
976 }
977
978 static void
979 usbd_transfer_cb(reqh)
980         usbd_request_handle reqh;
981 {
982         usbd_pipe_handle pipe = reqh->pipe;
983
984         /* Count completed transfers. */
985         ++pipe->device->bus->stats.requests[pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE];
986
987         /* XXX check retry count */
988         reqh->done = 1;
989         if (reqh->status == USBD_NORMAL_COMPLETION &&
990             reqh->actlen < reqh->length &&
991             !(reqh->flags & USBD_SHORT_XFER_OK)) {
992                 DPRINTFN(-1, ("usbd_transfer_cb: short xfer %d<%d (bytes)\n",
993                               reqh->actlen, reqh->length));
994                 reqh->status = USBD_SHORT_XFER;
995         }
996         
997         if (reqh->callback)
998                 reqh->callback(reqh, reqh->priv, reqh->status);
999 }
1000
1001 static void
1002 usbd_sync_transfer_cb(reqh)
1003         usbd_request_handle reqh;
1004 {
1005         usbd_transfer_cb(reqh);
1006         if (!reqh->pipe->device->bus->use_polling)
1007                 wakeup(reqh);
1008 }
1009
1010 /* Like usbd_transfer(), but waits for completion. */
1011 usbd_status
1012 usbd_sync_transfer(reqh)
1013         usbd_request_handle reqh;
1014 {
1015         usbd_status r;
1016         int s;
1017
1018         reqh->xfercb = usbd_sync_transfer_cb;
1019         r = usbd_do_transfer(reqh);
1020         if (r != USBD_IN_PROGRESS)
1021                 return (r);
1022         s = splusb();
1023         if (!reqh->done) {
1024                 if (reqh->pipe->device->bus->use_polling)
1025                         panic("usbd_sync_transfer: not done\n");
1026                 tsleep(reqh, PRIBIO, "usbsyn", 0);
1027         }
1028         splx(s);
1029         return (reqh->status);
1030 }
1031
1032 usbd_status
1033 usbd_do_request(dev, req, data)
1034         usbd_device_handle dev;
1035         usb_device_request_t *req;
1036         void *data;
1037 {
1038         return (usbd_do_request_flags(dev, req, data, 0, 0));
1039 }
1040
1041 usbd_status
1042 usbd_do_request_flags(dev, req, data, flags, actlen)
1043         usbd_device_handle dev;
1044         usb_device_request_t *req;
1045         void *data;
1046         u_int16_t flags;
1047         int *actlen;
1048 {
1049         usbd_request_handle reqh;
1050         usbd_status r;
1051
1052 #ifdef DIAGNOSTIC
1053         if (!curproc) {
1054                 printf("usbd_do_request: not in process context\n");
1055                 return (USBD_XXX);
1056         }
1057 #endif
1058
1059         reqh = usbd_alloc_request();
1060         if (reqh == 0)
1061                 return (USBD_NOMEM);
1062         r = usbd_setup_default_request(
1063                 reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req, data, 
1064                 UGETW(req->wLength), flags, 0);
1065         if (r != USBD_NORMAL_COMPLETION)
1066                 goto bad;
1067         r = usbd_sync_transfer(reqh);
1068
1069 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
1070         if (reqh->actlen > reqh->length)
1071                 printf("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
1072                        "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
1073                        dev->address, reqh->request.bmRequestType,
1074                        reqh->request.bRequest, UGETW(reqh->request.wValue),
1075                        UGETW(reqh->request.wIndex), 
1076                        UGETW(reqh->request.wLength), 
1077                        reqh->length, reqh->actlen);
1078 #endif
1079
1080         if (actlen)
1081                 *actlen = reqh->actlen;
1082                 
1083         if (r == USBD_STALLED) {
1084                 /* 
1085                  * The control endpoint has stalled.  Control endpoints
1086                  * should not halt, but some may do so anyway so clear
1087                  * any halt condition.
1088                  */
1089                 usb_device_request_t treq;
1090                 usb_status_t status;
1091                 u_int16_t s;
1092                 usbd_status nr;
1093
1094                 treq.bmRequestType = UT_READ_ENDPOINT;
1095                 treq.bRequest = UR_GET_STATUS;
1096                 USETW(treq.wValue, 0);
1097                 USETW(treq.wIndex, 0);
1098                 USETW(treq.wLength, sizeof(usb_status_t));
1099                 nr = usbd_setup_default_request(
1100                         reqh, dev, 0, USBD_DEFAULT_TIMEOUT, &treq, &status, 
1101                         sizeof(usb_status_t), 0, 0);
1102                 if (nr != USBD_NORMAL_COMPLETION)
1103                         goto bad;
1104                 nr = usbd_sync_transfer(reqh);
1105                 if (nr != USBD_NORMAL_COMPLETION)
1106                         goto bad;
1107                 s = UGETW(status.wStatus);
1108                 DPRINTF(("usbd_do_request: status = 0x%04x\n", s));
1109                 if (!(s & UES_HALT))
1110                         goto bad;
1111                 treq.bmRequestType = UT_WRITE_ENDPOINT;
1112                 treq.bRequest = UR_CLEAR_FEATURE;
1113                 USETW(treq.wValue, UF_ENDPOINT_HALT);
1114                 USETW(treq.wIndex, 0);
1115                 USETW(treq.wLength, 0);
1116                 nr = usbd_setup_default_request(
1117                         reqh, dev, 0, USBD_DEFAULT_TIMEOUT, &treq, &status, 
1118                         0, 0, 0);
1119                 if (nr != USBD_NORMAL_COMPLETION)
1120                         goto bad;
1121                 nr = usbd_sync_transfer(reqh);
1122                 if (nr != USBD_NORMAL_COMPLETION)
1123                         goto bad;
1124         }
1125
1126  bad:
1127         usbd_free_request(reqh);
1128         return (r);
1129 }
1130
1131 void
1132 usbd_do_request_async_cb(reqh, priv, status)
1133         usbd_request_handle reqh;
1134         usbd_private_handle priv;
1135         usbd_status status;
1136 {
1137 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
1138         if (reqh->actlen > reqh->length)
1139                 printf("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
1140                        "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
1141                        reqh->pipe->device->address, 
1142                        reqh->request.bmRequestType,
1143                        reqh->request.bRequest, UGETW(reqh->request.wValue),
1144                        UGETW(reqh->request.wIndex), 
1145                        UGETW(reqh->request.wLength), 
1146                        reqh->length, reqh->actlen);
1147 #endif
1148         usbd_free_request(reqh);
1149 }
1150
1151 /*
1152  * Execute a request without waiting for completion.
1153  * Can be used from interrupt context.
1154  */
1155 usbd_status
1156 usbd_do_request_async(dev, req, data)
1157         usbd_device_handle dev;
1158         usb_device_request_t *req;
1159         void *data;
1160 {
1161         usbd_request_handle reqh;
1162         usbd_status r;
1163
1164         reqh = usbd_alloc_request();
1165         if (reqh == 0)
1166                 return (USBD_NOMEM);
1167         r = usbd_setup_default_request(
1168                 reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req, data, 
1169                 UGETW(req->wLength), 0, usbd_do_request_async_cb);
1170         if (r != USBD_NORMAL_COMPLETION) {
1171                 usbd_free_request(reqh);
1172                 return (r);
1173         }
1174         r = usbd_transfer(reqh);
1175         if (r != USBD_IN_PROGRESS)
1176                 return (r);
1177         return (USBD_NORMAL_COMPLETION);
1178 }
1179
1180 struct usbd_quirks *
1181 usbd_get_quirks(dev)
1182         usbd_device_handle dev;
1183 {
1184         return (dev->quirks);
1185 }
1186
1187 void
1188 usbd_set_disco(p, hdl, data)
1189         usbd_pipe_handle p;
1190         void (*hdl) __P((void *));
1191         void *data;
1192 {
1193         p->disco = hdl;
1194         p->discoarg = data;
1195 }
1196
1197 /* XXX do periodic free() of free list */
1198
1199 /*
1200  * Called from keyboard driver when in polling mode.
1201  */
1202 void
1203 usbd_dopoll(iface)
1204         usbd_interface_handle iface;
1205 {
1206         iface->device->bus->do_poll(iface->device->bus);
1207 }
1208
1209 void
1210 usbd_set_polling(iface, on)
1211         usbd_interface_handle iface;
1212         int on;
1213 {
1214         iface->device->bus->use_polling = on;
1215 }
1216
1217
1218 usb_endpoint_descriptor_t *
1219 usbd_get_endpoint_descriptor(iface, address)
1220         usbd_interface_handle iface;
1221         u_int8_t address;
1222 {
1223         struct usbd_endpoint *ep;
1224         int i;
1225
1226         for (i = 0; i < iface->idesc->bNumEndpoints; i++) {
1227                 ep = &iface->endpoints[i];
1228                 if (ep->edesc->bEndpointAddress == address)
1229                         return (iface->endpoints[i].edesc);
1230         }
1231         return (0);
1232 }
1233
1234 #if defined(__FreeBSD__)
1235 void
1236 usbd_print_child(device_t parent, device_t child)
1237 {
1238         /*
1239         struct usb_softc *sc = device_get_softc(child);
1240         */
1241
1242         printf(" at %s%d", device_get_name(parent), device_get_unit(parent));
1243
1244         /* XXX How do we get to the usbd_device_handle???
1245         usbd_device_handle dev = invalidadosch;
1246
1247         printf(" addr %d", dev->addr);
1248
1249         if (bootverbose) {
1250                 if (dev->lowspeed)
1251                         printf(", lowspeed");
1252                 if (dev->self_powered)
1253                         printf(", self powered");
1254                 else
1255                         printf(", %dmA", dev->power);
1256                 printf(", config %d", dev->config);
1257         }
1258          */
1259 }
1260
1261 /* Reconfigure all the USB busses in the system. */
1262 int
1263 usbd_driver_load(module_t mod, int what, void *arg)
1264 {
1265 #if 1
1266         return 0;
1267 #else
1268         devclass_t usb_devclass = devclass_find("usb");
1269         devclass_t ugen_devclass = devclass_find("ugen");
1270         device_t *devlist;
1271         int devcount;
1272         int error;
1273
1274         if ( what == MOD_LOAD || what == MOD_UNLOAD ) {
1275                 if (!usb_devclass)
1276                         return 0;       /* just ignore call */
1277
1278                 /* Detach all the generic devices and do a reconfigure
1279                  * of the bus. This should attach the new driver to anything
1280                  * that is already connected and it can handle.
1281                  * XXX For the moment disabled. The detach does not remove
1282                  * the device from the list of devices attached to the hub.
1283                  * Legacy of converting from NetBSD to FreeBSD.
1284                  */
1285                 if (ugen_devclass) {
1286                         /* detach devices from generic driver if possible */
1287                         error = devclass_get_devices(ugen_devclass, &devlist,
1288                                                      &devcount);
1289                         if (!error)
1290                                 for (devcount--; devcount >= 0; devcount--)
1291                                         (void)DEVICE_DETACH(devlist[devcount]);
1292                         free(devlist, M_TEMP);
1293                 }
1294
1295                 /* Reconfigure the busses, possibly attaching something to the
1296                  * new driver */
1297                 error = devclass_get_devices(usb_devclass, &devlist, &devcount);
1298                 if (error)
1299                         return 0;       /* XXX maybe transient, or error? */
1300
1301                 for (devcount--; devcount >= 0; devcount--)
1302                         USB_RECONFIGURE(devlist[devcount]);
1303
1304                 free(devlist, M_TEMP);
1305         }
1306
1307         return 0;                       /* nothing to do */
1308 #endif
1309 }
1310 #endif
1311
1312 char *
1313 usbd_errstr(usbd_status err)
1314 {
1315         static char buffer[5];          /* XXX static buffer */
1316
1317 #ifdef  USB_DEBUG
1318         if ( err < USBD_ERROR_MAX ) {
1319                 return usbd_error_strs[err];
1320         } else {
1321                 snprintf(buffer, 4, "%d", err);
1322                 return buffer;
1323         }
1324 #else
1325         snprintf(buffer, 4, "%d", err);
1326         return buffer;
1327 #endif
1328 }