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