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