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