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