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