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