]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/usb/usbdi.c
This commit was generated by cvs2svn to compensate for changes in r49182,
[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         while ((reqh = SIMPLEQ_FIRST(&pipe->queue))) {
920                 pipe->methods->abort(reqh);
921 #if defined(__NetBSD__)
922                 SIMPLEQ_REMOVE_HEAD(&pipe->queue, reqh, next);
923 #elif defined(__FreeBSD__)
924                 SIMPLEQ_REMOVE_HEAD(&pipe->queue, next);
925 #endif
926                 /* XXX should the callback not be called something
927                  * else than splusb? Create a new list of reqh and
928                  * execute them after the while for example?
929                  */
930                 reqh->status = USBD_CANCELLED;
931                 if (reqh->callback)
932                         reqh->callback(reqh, reqh->priv, reqh->status);
933         }
934
935         return (USBD_NORMAL_COMPLETION);
936 }
937
938 /* Dequeue all interface operations, called at splusb(). */
939 static usbd_status
940 usbd_ar_iface(iface)
941         usbd_interface_handle iface;
942 {
943         usbd_pipe_handle p;
944         usbd_status r, ret = USBD_NORMAL_COMPLETION;
945
946         for (p = LIST_FIRST(&iface->pipes); p != 0; p = LIST_NEXT(p, next)) {
947                 r = usbd_ar_pipe(p);
948                 if (r != USBD_NORMAL_COMPLETION)
949                         ret = r;
950         }
951         return (ret);
952 }
953
954 static int usbd_global_init_done = 0;
955
956 void
957 usbd_init()
958 {
959         
960         if (!usbd_global_init_done) {
961                 usbd_global_init_done = 1;
962                 SIMPLEQ_INIT(&usbd_free_requests);
963
964 #if defined(__FreeBSD__)
965                 cdevsw_add(&usb_cdevsw);
966 #endif
967         }
968 }
969
970 static void
971 usbd_transfer_cb(reqh)
972         usbd_request_handle reqh;
973 {
974         usbd_pipe_handle pipe = reqh->pipe;
975
976         /* Count completed transfers. */
977         ++pipe->device->bus->stats.requests[pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE];
978
979         /* XXX check retry count */
980         reqh->done = 1;
981         if (reqh->status == USBD_NORMAL_COMPLETION &&
982             reqh->actlen < reqh->length &&
983             !(reqh->flags & USBD_SHORT_XFER_OK)) {
984                 DPRINTFN(-1, ("usbd_transfer_cb: short xfer %d<%d (bytes)\n",
985                               reqh->actlen, reqh->length));
986                 reqh->status = USBD_SHORT_XFER;
987         }
988         
989         if (reqh->callback)
990                 reqh->callback(reqh, reqh->priv, reqh->status);
991 }
992
993 static void
994 usbd_sync_transfer_cb(reqh)
995         usbd_request_handle reqh;
996 {
997         usbd_transfer_cb(reqh);
998         if (!reqh->pipe->device->bus->use_polling)
999                 wakeup(reqh);
1000 }
1001
1002 /* Like usbd_transfer(), but waits for completion. */
1003 usbd_status
1004 usbd_sync_transfer(reqh)
1005         usbd_request_handle reqh;
1006 {
1007         usbd_status r;
1008         int s;
1009
1010         reqh->xfercb = usbd_sync_transfer_cb;
1011         r = usbd_do_transfer(reqh);
1012         if (r != USBD_IN_PROGRESS)
1013                 return (r);
1014         s = splusb();
1015         if (!reqh->done) {
1016                 if (reqh->pipe->device->bus->use_polling)
1017                         panic("usbd_sync_transfer: not done\n");
1018                 tsleep(reqh, PRIBIO, "usbsyn", 0);
1019         }
1020         splx(s);
1021         return (reqh->status);
1022 }
1023
1024 usbd_status
1025 usbd_do_request(dev, req, data)
1026         usbd_device_handle dev;
1027         usb_device_request_t *req;
1028         void *data;
1029 {
1030         return (usbd_do_request_flags(dev, req, data, 0, 0));
1031 }
1032
1033 usbd_status
1034 usbd_do_request_flags(dev, req, data, flags, actlen)
1035         usbd_device_handle dev;
1036         usb_device_request_t *req;
1037         void *data;
1038         u_int16_t flags;
1039         int *actlen;
1040 {
1041         usbd_request_handle reqh;
1042         usbd_status r;
1043
1044 #ifdef DIAGNOSTIC
1045         if (!curproc) {
1046                 printf("usbd_do_request: not in process context\n");
1047                 return (USBD_XXX);
1048         }
1049 #endif
1050
1051         reqh = usbd_alloc_request();
1052         if (reqh == 0)
1053                 return (USBD_NOMEM);
1054         r = usbd_setup_default_request(
1055                 reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req, data, 
1056                 UGETW(req->wLength), flags, 0);
1057         if (r != USBD_NORMAL_COMPLETION)
1058                 goto bad;
1059         r = usbd_sync_transfer(reqh);
1060
1061 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
1062         if (reqh->actlen > reqh->length)
1063                 printf("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
1064                        "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
1065                        dev->address, reqh->request.bmRequestType,
1066                        reqh->request.bRequest, UGETW(reqh->request.wValue),
1067                        UGETW(reqh->request.wIndex), 
1068                        UGETW(reqh->request.wLength), 
1069                        reqh->length, reqh->actlen);
1070 #endif
1071
1072         if (actlen)
1073                 *actlen = reqh->actlen;
1074                 
1075         if (r == USBD_STALLED) {
1076                 /* 
1077                  * The control endpoint has stalled.  Control endpoints
1078                  * should not halt, but some may do so anyway so clear
1079                  * any halt condition.
1080                  */
1081                 usb_device_request_t treq;
1082                 usb_status_t status;
1083                 u_int16_t s;
1084                 usbd_status nr;
1085
1086                 treq.bmRequestType = UT_READ_ENDPOINT;
1087                 treq.bRequest = UR_GET_STATUS;
1088                 USETW(treq.wValue, 0);
1089                 USETW(treq.wIndex, 0);
1090                 USETW(treq.wLength, sizeof(usb_status_t));
1091                 nr = usbd_setup_default_request(
1092                         reqh, dev, 0, USBD_DEFAULT_TIMEOUT, &treq, &status, 
1093                         sizeof(usb_status_t), 0, 0);
1094                 if (nr != USBD_NORMAL_COMPLETION)
1095                         goto bad;
1096                 nr = usbd_sync_transfer(reqh);
1097                 if (nr != USBD_NORMAL_COMPLETION)
1098                         goto bad;
1099                 s = UGETW(status.wStatus);
1100                 DPRINTF(("usbd_do_request: status = 0x%04x\n", s));
1101                 if (!(s & UES_HALT))
1102                         goto bad;
1103                 treq.bmRequestType = UT_WRITE_ENDPOINT;
1104                 treq.bRequest = UR_CLEAR_FEATURE;
1105                 USETW(treq.wValue, UF_ENDPOINT_HALT);
1106                 USETW(treq.wIndex, 0);
1107                 USETW(treq.wLength, 0);
1108                 nr = usbd_setup_default_request(
1109                         reqh, dev, 0, USBD_DEFAULT_TIMEOUT, &treq, &status, 
1110                         0, 0, 0);
1111                 if (nr != USBD_NORMAL_COMPLETION)
1112                         goto bad;
1113                 nr = usbd_sync_transfer(reqh);
1114                 if (nr != USBD_NORMAL_COMPLETION)
1115                         goto bad;
1116         }
1117
1118  bad:
1119         usbd_free_request(reqh);
1120         return (r);
1121 }
1122
1123 void
1124 usbd_do_request_async_cb(reqh, priv, status)
1125         usbd_request_handle reqh;
1126         usbd_private_handle priv;
1127         usbd_status status;
1128 {
1129 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
1130         if (reqh->actlen > reqh->length)
1131                 printf("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
1132                        "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
1133                        reqh->pipe->device->address, 
1134                        reqh->request.bmRequestType,
1135                        reqh->request.bRequest, UGETW(reqh->request.wValue),
1136                        UGETW(reqh->request.wIndex), 
1137                        UGETW(reqh->request.wLength), 
1138                        reqh->length, reqh->actlen);
1139 #endif
1140         usbd_free_request(reqh);
1141 }
1142
1143 /*
1144  * Execute a request without waiting for completion.
1145  * Can be used from interrupt context.
1146  */
1147 usbd_status
1148 usbd_do_request_async(dev, req, data)
1149         usbd_device_handle dev;
1150         usb_device_request_t *req;
1151         void *data;
1152 {
1153         usbd_request_handle reqh;
1154         usbd_status r;
1155
1156         reqh = usbd_alloc_request();
1157         if (reqh == 0)
1158                 return (USBD_NOMEM);
1159         r = usbd_setup_default_request(
1160                 reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req, data, 
1161                 UGETW(req->wLength), 0, usbd_do_request_async_cb);
1162         if (r != USBD_NORMAL_COMPLETION) {
1163                 usbd_free_request(reqh);
1164                 return (r);
1165         }
1166         r = usbd_transfer(reqh);
1167         if (r != USBD_IN_PROGRESS)
1168                 return (r);
1169         return (USBD_NORMAL_COMPLETION);
1170 }
1171
1172 struct usbd_quirks *
1173 usbd_get_quirks(dev)
1174         usbd_device_handle dev;
1175 {
1176         return (dev->quirks);
1177 }
1178
1179 void
1180 usbd_set_disco(p, hdl, data)
1181         usbd_pipe_handle p;
1182         void (*hdl) __P((void *));
1183         void *data;
1184 {
1185         p->disco = hdl;
1186         p->discoarg = data;
1187 }
1188
1189 /* XXX do periodic free() of free list */
1190
1191 /*
1192  * Called from keyboard driver when in polling mode.
1193  */
1194 void
1195 usbd_dopoll(iface)
1196         usbd_interface_handle iface;
1197 {
1198         iface->device->bus->do_poll(iface->device->bus);
1199 }
1200
1201 void
1202 usbd_set_polling(iface, on)
1203         usbd_interface_handle iface;
1204         int on;
1205 {
1206         iface->device->bus->use_polling = on;
1207 }
1208
1209
1210 usb_endpoint_descriptor_t *
1211 usbd_get_endpoint_descriptor(iface, address)
1212         usbd_interface_handle iface;
1213         u_int8_t address;
1214 {
1215         struct usbd_endpoint *ep;
1216         int i;
1217
1218         for (i = 0; i < iface->idesc->bNumEndpoints; i++) {
1219                 ep = &iface->endpoints[i];
1220                 if (ep->edesc->bEndpointAddress == address)
1221                         return (iface->endpoints[i].edesc);
1222         }
1223         return (0);
1224 }
1225
1226 #if defined(__FreeBSD__)
1227 void
1228 usbd_print_child(device_t parent, device_t child)
1229 {
1230         /*
1231         struct usb_softc *sc = device_get_softc(child);
1232         */
1233
1234         printf(" at %s%d", device_get_name(parent), device_get_unit(parent));
1235
1236         /* XXX How do we get to the usbd_device_handle???
1237         usbd_device_handle dev = invalidadosch;
1238
1239         printf(" addr %d", dev->addr);
1240
1241         if (bootverbose) {
1242                 if (dev->lowspeed)
1243                         printf(", lowspeed");
1244                 if (dev->self_powered)
1245                         printf(", self powered");
1246                 else
1247                         printf(", %dmA", dev->power);
1248                 printf(", config %d", dev->config);
1249         }
1250          */
1251 }
1252
1253 /* Reconfigure all the USB busses in the system. */
1254 int
1255 usbd_driver_load(module_t mod, int what, void *arg)
1256 {
1257 #if 1
1258         return 0;
1259 #else
1260         devclass_t usb_devclass = devclass_find("usb");
1261         devclass_t ugen_devclass = devclass_find("ugen");
1262         device_t *devlist;
1263         int devcount;
1264         int error;
1265
1266         if ( what == MOD_LOAD || what == MOD_UNLOAD ) {
1267                 if (!usb_devclass)
1268                         return 0;       /* just ignore call */
1269
1270                 /* Detach all the generic devices and do a reconfigure
1271                  * of the bus. This should attach the new driver to anything
1272                  * that is already connected and it can handle.
1273                  * XXX For the moment disabled. The detach does not remove
1274                  * the device from the list of devices attached to the hub.
1275                  * Legacy of converting from NetBSD to FreeBSD.
1276                  */
1277                 if (ugen_devclass) {
1278                         /* detach devices from generic driver if possible */
1279                         error = devclass_get_devices(ugen_devclass, &devlist,
1280                                                      &devcount);
1281                         if (!error)
1282                                 for (devcount--; devcount >= 0; devcount--)
1283                                         (void)DEVICE_DETACH(devlist[devcount]);
1284                         free(devlist, M_TEMP);
1285                 }
1286
1287                 /* Reconfigure the busses, possibly attaching something to the
1288                  * new driver */
1289                 error = devclass_get_devices(usb_devclass, &devlist, &devcount);
1290                 if (error)
1291                         return 0;       /* XXX maybe transient, or error? */
1292
1293                 for (devcount--; devcount >= 0; devcount--)
1294                         USB_RECONFIGURE(devlist[devcount]);
1295
1296                 free(devlist, M_TEMP);
1297         }
1298
1299         return 0;                       /* nothing to do */
1300 #endif
1301 }
1302 #endif
1303
1304 char *
1305 usbd_errstr(usbd_status err)
1306 {
1307         static char buffer[5];          /* XXX static buffer */
1308
1309 #ifdef  USB_DEBUG
1310         if ( err < USBD_ERROR_MAX ) {
1311                 return usbd_error_strs[err];
1312         } else {
1313                 snprintf(buffer, 4, "%d", err);
1314                 return buffer;
1315         }
1316 #else
1317         snprintf(buffer, 4, "%d", err);
1318         return buffer;
1319 #endif
1320 }