usbdi.c revision 1.3 1 /* $NetBSD: usbdi.c,v 1.3 1998/07/23 13:44:22 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 return (pipe->methods->transfer(reqh));
218 }
219
220
221 usbd_request_handle
222 usbd_alloc_request()
223 {
224 usbd_request_handle reqh;
225
226 reqh = SIMPLEQ_FIRST(&usbd_free_requests);
227 if (reqh)
228 SIMPLEQ_REMOVE_HEAD(&usbd_free_requests, reqh, next);
229 else
230 reqh = malloc(sizeof(*reqh), M_USB, M_NOWAIT);
231 if (!reqh)
232 return (0);
233 memset(reqh, 0, sizeof *reqh);
234 return (reqh);
235 }
236
237 usbd_status
238 usbd_free_request(reqh)
239 usbd_request_handle reqh;
240 {
241 SIMPLEQ_INSERT_HEAD(&usbd_free_requests, reqh, next);
242 return (USBD_NORMAL_COMPLETION);
243 }
244
245 usbd_status
246 usbd_setup_request(reqh, pipe, priv, buffer, length, flags, timeout, callback)
247 usbd_request_handle reqh;
248 usbd_pipe_handle pipe;
249 usbd_private_handle priv;
250 void *buffer;
251 u_int32_t length;
252 u_int16_t flags;
253 u_int32_t timeout;
254 void (*callback) __P((usbd_request_handle,
255 usbd_private_handle,
256 usbd_status));
257 {
258 reqh->pipe = pipe;
259 reqh->isreq = 0;
260 reqh->priv = priv;
261 reqh->buffer = buffer;
262 reqh->length = length;
263 reqh->actlen = 0;
264 reqh->flags = flags;
265 reqh->callback = callback;
266 reqh->status = USBD_NOT_STARTED;
267 reqh->retries = 1;
268 return (USBD_NORMAL_COMPLETION);
269 }
270
271 usbd_status
272 usbd_setup_device_request(reqh, req)
273 usbd_request_handle reqh;
274 usb_device_request_t *req;
275 {
276 reqh->isreq = 1;
277 reqh->request = *req;
278 return (USBD_NORMAL_COMPLETION);
279 }
280
281 usbd_status
282 usbd_setup_default_request(reqh, dev, priv, timeout, req, buffer,
283 length, flags, callback)
284 usbd_request_handle reqh;
285 usbd_device_handle dev;
286 usbd_private_handle priv;
287 u_int32_t timeout;
288 usb_device_request_t *req;
289 void *buffer;
290 u_int32_t length;
291 u_int16_t flags;
292 void (*callback) __P((usbd_request_handle,
293 usbd_private_handle,
294 usbd_status));
295 {
296 reqh->pipe = dev->default_pipe;
297 reqh->priv = priv;
298 reqh->buffer = buffer;
299 reqh->length = length;
300 reqh->actlen = 0;
301 reqh->flags = flags;
302 reqh->timeout = timeout;
303 reqh->status = USBD_NOT_STARTED;
304 reqh->callback = callback;
305 reqh->request = *req;
306 reqh->isreq = 1;
307 reqh->retries = 1;
308 return (USBD_NORMAL_COMPLETION);
309 }
310
311 usbd_status
312 usbd_set_request_timeout(reqh, timeout)
313 usbd_request_handle reqh;
314 u_int32_t timeout;
315 {
316 reqh->timeout = timeout;
317 return (USBD_NORMAL_COMPLETION);
318 }
319
320 usbd_status
321 usbd_get_request_status(reqh, priv, buffer, count, status)
322 usbd_request_handle reqh;
323 usbd_private_handle *priv;
324 void **buffer;
325 u_int32_t *count;
326 usbd_status *status;
327 {
328 *priv = reqh->priv;
329 *buffer = reqh->buffer;
330 *count = reqh->actlen;
331 *status = reqh->status;
332 return (USBD_NORMAL_COMPLETION);
333 }
334
335 usbd_status
336 usbd_request_device_data(reqh, req)
337 usbd_request_handle reqh;
338 usb_device_request_t *req;
339 {
340 if (!reqh->isreq)
341 return (USBD_INVAL);
342 *req = reqh->request;
343 return (USBD_NORMAL_COMPLETION);
344 }
345
346 #if 0
347 usb_descriptor_t *
348 usbd_get_descriptor(iface, desc_type)
349 usbd_interface_handle *iface;
350 u_int8_t desc_type;
351 XX
352 #endif
353
354 usb_config_descriptor_t *
355 usbd_get_config_descriptor(dev)
356 usbd_device_handle dev;
357 {
358 return (dev->cdesc);
359 }
360
361 usb_interface_descriptor_t *
362 usbd_get_interface_descriptor(iface)
363 usbd_interface_handle iface;
364 {
365 return (iface->idesc);
366 }
367
368 usb_device_descriptor_t *
369 usbd_get_device_descriptor(dev)
370 usbd_device_handle dev;
371 {
372 return (&dev->ddesc);
373 }
374
375 usb_endpoint_descriptor_t *
376 usbd_interface2endpoint_descriptor(iface, index)
377 usbd_interface_handle iface;
378 u_int8_t index;
379 {
380 if (index >= iface->idesc->bNumEndpoints)
381 return 0;
382 return (iface->endpoints[index].edesc);
383 }
384
385 usbd_status usbd_set_configuration(dev, conf)
386 usbd_device_handle dev;
387 u_int16_t conf;
388 {
389 return usbd_set_config_no(dev, conf);
390 }
391
392 usbd_status
393 usbd_retry_request(reqh, retry_count)
394 usbd_request_handle reqh;
395 u_int32_t retry_count;
396 {
397 usbd_status r;
398
399 r = usbd_set_pipe_state(reqh->pipe, USBD_PIPE_ACTIVE);
400 if (r != USBD_NORMAL_COMPLETION)
401 return (r);
402 reqh->retries = retry_count;
403 return (usbd_transfer(reqh));
404 }
405
406 usbd_status
407 usbd_abort_pipe(pipe)
408 usbd_pipe_handle pipe;
409 {
410 usbd_status r;
411 int s, st;
412
413 if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
414 return (USBD_INTERFACE_NOT_ACTIVE);
415 s = splusb();
416 st = pipe->state;
417 r = usbd_ar_pipe(pipe);
418 pipe->state = st;
419 splx(s);
420 return (r);
421 }
422
423 usbd_status
424 usbd_abort_interface(iface)
425 usbd_interface_handle iface;
426 {
427 usbd_status r;
428 int s, st;
429
430 s = splusb();
431 st = iface->state;
432 r = usbd_ar_iface(iface);
433 iface->state = st;
434 splx(s);
435 return (r);
436 }
437
438 usbd_status
439 usbd_reset_pipe(pipe)
440 usbd_pipe_handle pipe;
441 {
442 usbd_status r;
443 int s;
444
445 if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
446 return (USBD_INTERFACE_NOT_ACTIVE);
447 s = splusb();
448 r = usbd_ar_pipe(pipe);
449 /* XXX anything else */
450 pipe->state = USBD_PIPE_ACTIVE;
451 splx(s);
452 return (r);
453 }
454
455 usbd_status
456 usbd_reset_interface(iface)
457 usbd_interface_handle iface;
458 {
459 usbd_status r;
460 int s;
461
462 s = splusb();
463 r = usbd_ar_iface(iface);
464 /* XXX anything else */
465 iface->state = USBD_INTERFACE_ACTIVE;
466 splx(s);
467 return (r);
468 }
469
470 usbd_status
471 usbd_clear_endpoint_stall(pipe)
472 usbd_pipe_handle pipe;
473 {
474 usbd_device_handle dev = pipe->device;
475 usb_device_request_t req;
476 usbd_status r;
477
478 req.bmRequestType = UT_WRITE_ENDPOINT;
479 req.bRequest = UR_CLEAR_FEATURE;
480 USETW(req.wValue, UF_ENDPOINT_STALL);
481 USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress); /* XXX mask/ */
482 USETW(req.wLength, 0);
483 r = usbd_do_request(dev, &req, 0);
484 #if 0
485 XXX should we do this?
486 if (r == USBD_NORMAL_COMPLETION) {
487 pipe->state = USBD_PIPE_ACTIVE;
488 /* XXX activate pipe */
489 }
490 #endif
491 return (r);
492 }
493
494 usbd_status
495 usbd_set_pipe_state(pipe, state)
496 usbd_pipe_handle pipe;
497 usbd_pipe_state state;
498 {
499 int s;
500
501 if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
502 return (USBD_INTERFACE_NOT_ACTIVE);
503 if (state != USBD_PIPE_ACTIVE &&
504 state != USBD_PIPE_STALLED &&
505 state != USBD_PIPE_IDLE)
506 return (USBD_INVAL);
507 pipe->state = state;
508 if (state == USBD_PIPE_ACTIVE) {
509 s = splusb();
510 usbd_start(pipe);
511 splx(s);
512 }
513 return (USBD_NORMAL_COMPLETION);
514 }
515
516 usbd_status
517 usbd_get_pipe_state(pipe, state, endpoint_state, request_count)
518 usbd_pipe_handle pipe;
519 usbd_pipe_state *state;
520 u_int32_t *endpoint_state;
521 u_int32_t *request_count;
522 {
523 int n;
524 usbd_request_handle r;
525
526 *state = pipe->state;
527 *endpoint_state = pipe->endpoint->state;
528 for (r = SIMPLEQ_FIRST(&pipe->queue), n = 0;
529 r != 0;
530 r = SIMPLEQ_NEXT(r, next), n++)
531 ;
532 *request_count = n;
533 return (USBD_NORMAL_COMPLETION);
534 }
535
536 usbd_status
537 usbd_set_interface_state(iface, state)
538 usbd_interface_handle iface;
539 usbd_interface_state state;
540 {
541 int ps;
542 usbd_pipe_handle p;
543
544 if (state == USBD_INTERFACE_ACTIVE)
545 ps = USBD_PIPE_ACTIVE;
546 else if (state == USBD_INTERFACE_STALLED)
547 ps = USBD_PIPE_STALLED;
548 else if (state == USBD_INTERFACE_IDLE)
549 ps = USBD_PIPE_IDLE;
550 else
551 return (USBD_INVAL);
552 iface->state = USBD_INTERFACE_ACTIVE; /* to allow setting the pipe */
553 for (p = LIST_FIRST(&iface->pipes); p != 0; p = LIST_NEXT(p, next))
554 usbd_set_pipe_state(p, ps);
555 iface->state = state;
556 return (USBD_NORMAL_COMPLETION);
557 }
558
559 usbd_status
560 usbd_get_interface_state(iface, state)
561 usbd_interface_handle iface;
562 usbd_interface_state *state;
563 {
564 *state = iface->state;
565 return (USBD_NORMAL_COMPLETION);
566 }
567
568 usbd_status
569 usbd_get_device_state(dev, state)
570 usbd_device_handle dev;
571 usbd_device_state *state;
572 {
573 *state = dev->state;
574 return (USBD_NORMAL_COMPLETION);
575 }
576
577 #if 0
578 usbd_status
579 usbd_set_device_state(dev, state)
580 usbd_device_handle dev;
581 usbd_device_state state;
582 X
583 #endif
584
585 usbd_status
586 usbd_device_address(dev, address)
587 usbd_device_handle dev;
588 u_int8_t *address;
589 {
590 *address = dev->address;
591 return (USBD_NORMAL_COMPLETION);
592 }
593
594 usbd_status
595 usbd_endpoint_address(pipe, address)
596 usbd_pipe_handle pipe;
597 u_int8_t *address;
598 {
599 *address = pipe->endpoint->edesc->bEndpointAddress;
600 return (USBD_NORMAL_COMPLETION);
601 }
602
603 usbd_status
604 usbd_endpoint_count(iface, count)
605 usbd_interface_handle iface;
606 u_int8_t *count;
607 {
608 *count = iface->idesc->bNumEndpoints;
609 return (USBD_NORMAL_COMPLETION);
610 }
611
612 usbd_status
613 usbd_interface_count(dev, count)
614 usbd_device_handle dev;
615 u_int8_t *count;
616 {
617 if (!dev->cdesc)
618 return (USBD_NOT_CONFIGURED);
619 *count = dev->cdesc->bNumInterface;
620 return (USBD_NORMAL_COMPLETION);
621 }
622
623 u_int8_t
624 usbd_bus_count()
625 {
626 return (usb_bus_count());
627 }
628
629 usbd_status
630 usbd_get_bus_handle(index, bus)
631 u_int8_t index;
632 usbd_bus_handle *bus;
633 {
634 return (usb_get_bus_handle(index, bus));
635 }
636
637 usbd_status
638 usbd_get_root_hub(bus, dev)
639 usbd_bus_handle bus;
640 usbd_device_handle *dev;
641 {
642 *dev = bus->root_hub;
643 return (USBD_NORMAL_COMPLETION);
644 }
645
646 usbd_status
647 usbd_port_count(dev, nports)
648 usbd_device_handle dev;
649 u_int8_t *nports;
650 {
651 if (dev->hub == 0)
652 return (USBD_INVAL);
653 *nports = dev->hub->hubdesc.bNbrPorts;
654 return (USBD_NORMAL_COMPLETION);
655 }
656
657 usbd_status
658 usbd_hub2device_handle(dev, port, devp)
659 usbd_device_handle dev;
660 u_int8_t port;
661 usbd_device_handle *devp;
662 {
663 if (dev->hub == 0 || port >= dev->hub->hubdesc.bNbrPorts ||
664 dev->hub->ports[port].device == 0)
665 return (USBD_INVAL);
666 *devp = dev->hub->ports[port].device;
667 return (USBD_NORMAL_COMPLETION);
668 }
669
670 usbd_status
671 usbd_request2pipe_handle(reqh, pipe)
672 usbd_request_handle reqh;
673 usbd_pipe_handle *pipe;
674 {
675 *pipe = reqh->pipe;
676 return (USBD_NORMAL_COMPLETION);
677 }
678
679 usbd_status
680 usbd_pipe2interface_handle(pipe, iface)
681 usbd_pipe_handle pipe;
682 usbd_interface_handle *iface;
683 {
684 *iface = pipe->iface;
685 return (USBD_NORMAL_COMPLETION);
686 }
687
688 usbd_status
689 usbd_interface2device_handle(iface, dev)
690 usbd_interface_handle iface;
691 usbd_device_handle *dev;
692 {
693 *dev = iface->device;
694 return (USBD_NORMAL_COMPLETION);
695 }
696
697 usbd_status
698 usbd_device2bus_handle(dev, bus)
699 usbd_device_handle dev;
700 usbd_bus_handle *bus;
701 {
702 *bus = dev->bus;
703 return (USBD_NORMAL_COMPLETION);
704 }
705
706 usbd_status
707 usbd_device2interface_handle(dev, ifaceno, iface)
708 usbd_device_handle dev;
709 u_int8_t ifaceno;
710 usbd_interface_handle *iface;
711 {
712 if (!dev->cdesc)
713 return (USBD_NOT_CONFIGURED);
714 if (ifaceno >= dev->cdesc->bNumInterface)
715 return (USBD_INVAL);
716 *iface = &dev->ifaces[ifaceno];
717 return (USBD_NORMAL_COMPLETION);
718 }
719
720 usbd_status
721 usbd_set_interface_private_handle(iface, priv)
722 usbd_interface_handle iface;
723 usbd_private_handle priv;
724 {
725 iface->priv = priv;
726 return (USBD_NORMAL_COMPLETION);
727 }
728
729 usbd_status
730 usbd_get_interface_private_handle(iface, priv)
731 usbd_interface_handle iface;
732 usbd_private_handle *priv;
733 {
734 *priv = iface->priv;
735 return (USBD_NORMAL_COMPLETION);
736 }
737
738 usbd_status
739 usbd_reference_pipe(pipe)
740 usbd_pipe_handle pipe;
741 {
742 pipe->refcnt++;
743 return (USBD_NORMAL_COMPLETION);
744 }
745
746 usbd_status
747 usbd_dereference_pipe(pipe)
748 usbd_pipe_handle pipe;
749 {
750 pipe->refcnt--;
751 return (USBD_NORMAL_COMPLETION);
752 }
753
754 usbd_lock_token
755 usbd_lock()
756 {
757 return (splusb());
758 }
759
760 void
761 usbd_unlock(tok)
762 usbd_lock_token tok;
763 {
764 splx(tok);
765 }
766
767 /* XXX need to check that the interface is idle */
768 usbd_status
769 usbd_set_interface(iface, aiface)
770 usbd_interface_handle iface;
771 int aiface;
772 {
773 usb_device_request_t req;
774
775 req.bmRequestType = UT_WRITE_INTERFACE;
776 req.bRequest = UR_SET_INTERFACE;
777 USETW(req.wValue, aiface);
778 USETW(req.wIndex, iface->idesc->iInterface);
779 USETW(req.wLength, 0);
780 return usbd_do_request(iface->device, &req, 0);
781 }
782
783 /*** Internal routines ***/
784
785 /* Dequeue all pipe operations, called at splusb(). */
786 static usbd_status
787 usbd_ar_pipe(pipe)
788 usbd_pipe_handle pipe;
789 {
790 usbd_request_handle reqh;
791
792 reqh = SIMPLEQ_FIRST(&pipe->queue);
793 if (reqh != 0) {
794 pipe->methods->abort(reqh);
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 /* XXX check retry count */
844 reqh->done = 1;
845 if (reqh->status == USBD_NORMAL_COMPLETION &&
846 reqh->actlen < reqh->length &&
847 !(reqh->flags & USBD_SHORT_XFER_OK)) {
848 DPRINTFN(-1, ("usbd_transfer_cb: short xfer %d < %d\n",
849 reqh->actlen, reqh->length));
850 reqh->status = USBD_SHORT_XFER;
851 }
852 if (reqh->callback)
853 reqh->callback(reqh, reqh->priv, reqh->status);
854
855 if (pipe->state != USBD_PIPE_ACTIVE) {
856 pipe->running = 0;
857 return;
858 }
859 nreqh = SIMPLEQ_FIRST(&pipe->queue);
860 DPRINTFN(5, ("usbd_transfer_cb: nreqh=%p\n", nreqh));
861 if (!nreqh)
862 pipe->running = 0;
863 else {
864 SIMPLEQ_REMOVE_HEAD(&pipe->queue, nreqh, next);
865 r = pipe->methods->transfer(nreqh);
866 if (r != USBD_IN_PROGRESS)
867 printf("usbd_transfer_cb: error=%d\n", r);
868 }
869 }
870
871 static void
872 usbd_sync_transfer_cb(reqh)
873 usbd_request_handle reqh;
874 {
875 usbd_transfer_cb(reqh);
876 if (!usbd_use_polling)
877 wakeup(reqh);
878 }
879
880 /* Like usbd_transfer(), but waits for completion. */
881 usbd_status
882 usbd_sync_transfer(reqh)
883 usbd_request_handle reqh;
884 {
885 usbd_status r;
886 int s;
887
888 reqh->xfercb = usbd_sync_transfer_cb;
889 r = usbd_do_transfer(reqh);
890 if (r != USBD_IN_PROGRESS)
891 return (r);
892 s = splusb();
893 if (!reqh->done) {
894 if (usbd_use_polling)
895 panic("usbd_sync_transfer: not done\n");
896 tsleep(reqh, PRIBIO, "usbsyn", 0);
897 }
898 splx(s);
899 return (reqh->status);
900 }
901
902 usbd_status
903 usbd_do_request(dev, req, data)
904 usbd_device_handle dev;
905 usb_device_request_t *req;
906 void *data;
907 {
908 usbd_request_handle reqh;
909 usbd_status r;
910
911 reqh = usbd_alloc_request();
912 if (reqh == 0)
913 return (USBD_NOMEM);
914 r = usbd_setup_default_request(
915 reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req, data,
916 UGETW(req->wLength), 0, 0);
917 if (r != USBD_NORMAL_COMPLETION) {
918 usbd_free_request(reqh);
919 return (r);
920 }
921 r = usbd_sync_transfer(reqh);
922 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
923 if (reqh->actlen > reqh->length)
924 printf("usbd_do_request: overrun addr=%d type=0x%02x req=0x%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
925 dev->address, reqh->request.bmRequestType,
926 reqh->request.bRequest, UGETW(reqh->request.wValue),
927 UGETW(reqh->request.wIndex),
928 UGETW(reqh->request.wLength),
929 reqh->length, reqh->actlen);
930 #endif
931 usbd_free_request(reqh);
932 return (r);
933 }
934
935 struct usbd_quirks *
936 usbd_get_quirks(dev)
937 usbd_device_handle dev;
938 {
939 return (dev->quirks);
940 }
941
942 void
943 usbd_set_disco(p, hdl, data)
944 usbd_pipe_handle p;
945 void (*hdl) __P((void *));
946 void *data;
947 {
948 p->disco = hdl;
949 p->discoarg = data;
950 }
951
952 /* XXX do periodic free() of free list */
953
954