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