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