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