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