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