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