usbdi.c revision 1.22 1 /* $NetBSD: usbdi.c,v 1.22 1999/05/09 14:36:42 augustss Exp $ */
2
3 /*
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (augustss (at) carlstedt.se) at
9 * Carlstedt Research & Technology.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #if defined(__NetBSD__)
44 #include <sys/device.h>
45 #else
46 #include <sys/module.h>
47 #include <sys/bus.h>
48 #include <sys/conf.h>
49 #endif
50 #include <sys/malloc.h>
51 #include <sys/proc.h>
52
53 #include <dev/usb/usb.h>
54
55 #include <dev/usb/usbdi.h>
56 #include <dev/usb/usbdi_util.h>
57 #include <dev/usb/usbdivar.h>
58
59 #if defined(__FreeBSD__)
60 #include "usb_if.h"
61 #endif
62
63 #ifdef USB_DEBUG
64 #define DPRINTF(x) if (usbdebug) printf x
65 #define DPRINTFN(n,x) if (usbdebug>(n)) printf x
66 extern int usbdebug;
67 #else
68 #define DPRINTF(x)
69 #define DPRINTFN(n,x)
70 #endif
71
72 static usbd_status usbd_ar_pipe __P((usbd_pipe_handle pipe));
73 static usbd_status usbd_ar_iface __P((usbd_interface_handle iface));
74 static void usbd_transfer_cb __P((usbd_request_handle reqh));
75 static void usbd_sync_transfer_cb __P((usbd_request_handle reqh));
76 static usbd_status usbd_do_transfer __P((usbd_request_handle reqh));
77 void usbd_do_request_async_cb
78 __P((usbd_request_handle, usbd_private_handle, usbd_status));
79
80 static SIMPLEQ_HEAD(, usbd_request) usbd_free_requests;
81
82 #if defined(__FreeBSD__)
83 #define USB_CDEV_MAJOR 108
84
85 extern struct cdevsw usb_cdevsw;
86 #endif
87
88 usbd_status
89 usbd_open_pipe(iface, address, flags, pipe)
90 usbd_interface_handle iface;
91 u_int8_t address;
92 u_int8_t flags;
93 usbd_pipe_handle *pipe;
94 {
95 usbd_pipe_handle p;
96 struct usbd_endpoint *ep;
97 usbd_status r;
98 int i;
99
100 if (iface->state != USBD_INTERFACE_ACTIVE)
101 return (USBD_INTERFACE_NOT_ACTIVE);
102 for (i = 0; i < iface->idesc->bNumEndpoints; i++) {
103 ep = &iface->endpoints[i];
104 if (ep->edesc->bEndpointAddress == address)
105 goto found;
106 }
107 return (USBD_BAD_ADDRESS);
108 found:
109 if ((flags & USBD_EXCLUSIVE_USE) &&
110 ep->refcnt != 0)
111 return (USBD_IN_USE);
112 r = usbd_setup_pipe(iface->device, iface, ep, &p);
113 if (r != USBD_NORMAL_COMPLETION)
114 return (r);
115 LIST_INSERT_HEAD(&iface->pipes, p, next);
116 *pipe = p;
117 return (USBD_NORMAL_COMPLETION);
118 }
119
120 usbd_status
121 usbd_open_pipe_intr(iface, address, flags, pipe, priv, buffer, length, cb)
122 usbd_interface_handle iface;
123 u_int8_t address;
124 u_int8_t flags;
125 usbd_pipe_handle *pipe;
126 usbd_private_handle priv;
127 void *buffer;
128 u_int32_t length;
129 usbd_callback cb;
130 {
131 usbd_status r;
132 usbd_request_handle reqh;
133 usbd_pipe_handle ipipe;
134
135 reqh = usbd_alloc_request();
136 if (reqh == 0)
137 return (USBD_NOMEM);
138 r = usbd_open_pipe(iface, address, USBD_EXCLUSIVE_USE, &ipipe);
139 if (r != USBD_NORMAL_COMPLETION)
140 goto bad1;
141 r = usbd_setup_request(reqh, ipipe, priv, buffer, length,
142 USBD_XFER_IN | flags, USBD_NO_TIMEOUT, cb);
143 if (r != USBD_NORMAL_COMPLETION)
144 goto bad2;
145 ipipe->intrreqh = reqh;
146 r = usbd_transfer(reqh);
147 *pipe = ipipe;
148 if (r != USBD_IN_PROGRESS)
149 goto bad3;
150 return (USBD_NORMAL_COMPLETION);
151
152 bad3:
153 ipipe->intrreqh = 0;
154 bad2:
155 usbd_close_pipe(ipipe);
156 bad1:
157 usbd_free_request(reqh);
158 return r;
159 }
160
161 usbd_status
162 usbd_open_pipe_iso(iface, address, flags, pipe, priv, bufsize, nbuf, cb)
163 usbd_interface_handle iface;
164 u_int8_t address;
165 u_int8_t flags;
166 usbd_pipe_handle *pipe;
167 usbd_private_handle priv;
168 u_int32_t bufsize;
169 u_int32_t nbuf;
170 usbd_callback cb;
171 {
172 usbd_status r;
173 usbd_pipe_handle p;
174
175 r = usbd_open_pipe(iface, address, USBD_EXCLUSIVE_USE, &p);
176 if (r != USBD_NORMAL_COMPLETION)
177 return (r);
178 if (!p->methods->isobuf) {
179 usbd_close_pipe(p);
180 return (USBD_INVAL);
181 }
182 r = p->methods->isobuf(p, bufsize, nbuf);
183 if (r != USBD_NORMAL_COMPLETION) {
184 usbd_close_pipe(p);
185 return (r);
186 }
187 *pipe = p;
188 return r;
189 }
190
191 usbd_status
192 usbd_close_pipe(pipe)
193 usbd_pipe_handle pipe;
194 {
195 if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
196 return (USBD_INTERFACE_NOT_ACTIVE);
197 if (--pipe->refcnt != 0)
198 return (USBD_NORMAL_COMPLETION);
199 if (SIMPLEQ_FIRST(&pipe->queue) != 0)
200 return (USBD_PENDING_REQUESTS);
201 LIST_REMOVE(pipe, next);
202 pipe->endpoint->refcnt--;
203 pipe->methods->close(pipe);
204 if (pipe->intrreqh)
205 usbd_free_request(pipe->intrreqh);
206 free(pipe, M_USB);
207 return (USBD_NORMAL_COMPLETION);
208 }
209
210 usbd_status
211 usbd_transfer(reqh)
212 usbd_request_handle reqh;
213 {
214 reqh->xfercb = usbd_transfer_cb;
215 return (usbd_do_transfer(reqh));
216 }
217
218 static usbd_status
219 usbd_do_transfer(reqh)
220 usbd_request_handle reqh;
221 {
222 usbd_pipe_handle pipe = reqh->pipe;
223
224 DPRINTFN(10,("usbd_do_transfer: reqh=%p\n", reqh));
225 reqh->done = 0;
226 return (pipe->methods->transfer(reqh));
227 }
228
229 usbd_request_handle
230 usbd_alloc_request()
231 {
232 usbd_request_handle reqh;
233
234 reqh = SIMPLEQ_FIRST(&usbd_free_requests);
235 if (reqh)
236 SIMPLEQ_REMOVE_HEAD(&usbd_free_requests, reqh, next);
237 else
238 reqh = malloc(sizeof(*reqh), M_USB, M_NOWAIT);
239 if (!reqh)
240 return (0);
241 memset(reqh, 0, sizeof *reqh);
242 return (reqh);
243 }
244
245 usbd_status
246 usbd_free_request(reqh)
247 usbd_request_handle reqh;
248 {
249 SIMPLEQ_INSERT_HEAD(&usbd_free_requests, reqh, next);
250 return (USBD_NORMAL_COMPLETION);
251 }
252
253 usbd_status
254 usbd_setup_request(reqh, pipe, priv, buffer, length, flags, timeout, callback)
255 usbd_request_handle reqh;
256 usbd_pipe_handle pipe;
257 usbd_private_handle priv;
258 void *buffer;
259 u_int32_t length;
260 u_int16_t flags;
261 u_int32_t timeout;
262 void (*callback) __P((usbd_request_handle,
263 usbd_private_handle,
264 usbd_status));
265 {
266 reqh->pipe = pipe;
267 reqh->priv = priv;
268 reqh->buffer = buffer;
269 reqh->length = length;
270 reqh->actlen = 0;
271 reqh->flags = flags;
272 reqh->timeout = timeout;
273 reqh->status = USBD_NOT_STARTED;
274 reqh->callback = callback;
275 reqh->retries = 1;
276 reqh->isreq = 0;
277 return (USBD_NORMAL_COMPLETION);
278 }
279
280 usbd_status
281 usbd_setup_device_request(reqh, req)
282 usbd_request_handle reqh;
283 usb_device_request_t *req;
284 {
285 reqh->isreq = 1;
286 reqh->request = *req;
287 return (USBD_NORMAL_COMPLETION);
288 }
289
290 usbd_status
291 usbd_setup_default_request(reqh, dev, priv, timeout, req, buffer,
292 length, flags, callback)
293 usbd_request_handle reqh;
294 usbd_device_handle dev;
295 usbd_private_handle priv;
296 u_int32_t timeout;
297 usb_device_request_t *req;
298 void *buffer;
299 u_int32_t length;
300 u_int16_t flags;
301 void (*callback) __P((usbd_request_handle,
302 usbd_private_handle,
303 usbd_status));
304 {
305 reqh->pipe = dev->default_pipe;
306 reqh->priv = priv;
307 reqh->buffer = buffer;
308 reqh->length = length;
309 reqh->actlen = 0;
310 reqh->flags = flags;
311 reqh->timeout = timeout;
312 reqh->status = USBD_NOT_STARTED;
313 reqh->callback = callback;
314 reqh->request = *req;
315 reqh->retries = 1;
316 reqh->isreq = 1;
317 return (USBD_NORMAL_COMPLETION);
318 }
319
320 usbd_status
321 usbd_set_request_timeout(reqh, timeout)
322 usbd_request_handle reqh;
323 u_int32_t timeout;
324 {
325 reqh->timeout = timeout;
326 return (USBD_NORMAL_COMPLETION);
327 }
328
329 usbd_status
330 usbd_get_request_status(reqh, priv, buffer, count, status)
331 usbd_request_handle reqh;
332 usbd_private_handle *priv;
333 void **buffer;
334 u_int32_t *count;
335 usbd_status *status;
336 {
337 *priv = reqh->priv;
338 *buffer = reqh->buffer;
339 *count = reqh->actlen;
340 *status = reqh->status;
341 return (USBD_NORMAL_COMPLETION);
342 }
343
344 usbd_status
345 usbd_request_device_data(reqh, req)
346 usbd_request_handle reqh;
347 usb_device_request_t *req;
348 {
349 if (!reqh->isreq)
350 return (USBD_INVAL);
351 *req = reqh->request;
352 return (USBD_NORMAL_COMPLETION);
353 }
354
355 #if 0
356 usb_descriptor_t *
357 usbd_get_descriptor(iface, desc_type)
358 usbd_interface_handle *iface;
359 u_int8_t desc_type;
360 XX
361 #endif
362
363 usb_config_descriptor_t *
364 usbd_get_config_descriptor(dev)
365 usbd_device_handle dev;
366 {
367 return (dev->cdesc);
368 }
369
370 usb_interface_descriptor_t *
371 usbd_get_interface_descriptor(iface)
372 usbd_interface_handle iface;
373 {
374 return (iface->idesc);
375 }
376
377 usb_device_descriptor_t *
378 usbd_get_device_descriptor(dev)
379 usbd_device_handle dev;
380 {
381 return (&dev->ddesc);
382 }
383
384 usb_endpoint_descriptor_t *
385 usbd_interface2endpoint_descriptor(iface, index)
386 usbd_interface_handle iface;
387 u_int8_t index;
388 {
389 if (index >= iface->idesc->bNumEndpoints)
390 return (0);
391 return (iface->endpoints[index].edesc);
392 }
393
394 usbd_status
395 usbd_set_configuration(dev, conf)
396 usbd_device_handle dev;
397 u_int8_t conf;
398 {
399 return usbd_set_config_no(dev, conf, 0);
400 }
401
402 usbd_status
403 usbd_retry_request(reqh, retry_count)
404 usbd_request_handle reqh;
405 u_int32_t retry_count;
406 {
407 usbd_status r;
408
409 r = usbd_set_pipe_state(reqh->pipe, USBD_PIPE_ACTIVE);
410 if (r != USBD_NORMAL_COMPLETION)
411 return (r);
412 reqh->retries = retry_count;
413 return (usbd_transfer(reqh));
414 }
415
416 usbd_status
417 usbd_abort_pipe(pipe)
418 usbd_pipe_handle pipe;
419 {
420 usbd_status r;
421 int s, st;
422
423 if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
424 return (USBD_INTERFACE_NOT_ACTIVE);
425 s = splusb();
426 st = pipe->state;
427 r = usbd_ar_pipe(pipe);
428 pipe->state = st;
429 splx(s);
430 return (r);
431 }
432
433 usbd_status
434 usbd_abort_interface(iface)
435 usbd_interface_handle iface;
436 {
437 usbd_status r;
438 int s, st;
439
440 s = splusb();
441 st = iface->state;
442 r = usbd_ar_iface(iface);
443 iface->state = st;
444 splx(s);
445 return (r);
446 }
447
448 usbd_status
449 usbd_reset_pipe(pipe)
450 usbd_pipe_handle pipe;
451 {
452 usbd_status r;
453 int s;
454
455 if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
456 return (USBD_INTERFACE_NOT_ACTIVE);
457 s = splusb();
458 r = usbd_ar_pipe(pipe);
459 /* XXX anything else */
460 pipe->state = USBD_PIPE_ACTIVE;
461 splx(s);
462 return (r);
463 }
464
465 usbd_status
466 usbd_reset_interface(iface)
467 usbd_interface_handle iface;
468 {
469 usbd_status r;
470 int s;
471
472 s = splusb();
473 r = usbd_ar_iface(iface);
474 /* XXX anything else */
475 iface->state = USBD_INTERFACE_ACTIVE;
476 splx(s);
477 return (r);
478 }
479
480 usbd_status
481 usbd_clear_endpoint_stall(pipe)
482 usbd_pipe_handle pipe;
483 {
484 usbd_device_handle dev = pipe->device;
485 usb_device_request_t req;
486 usbd_status r;
487
488 DPRINTFN(8, ("usbd_clear_endpoint_stall\n"));
489 req.bmRequestType = UT_WRITE_ENDPOINT;
490 req.bRequest = UR_CLEAR_FEATURE;
491 USETW(req.wValue, UF_ENDPOINT_HALT);
492 USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);
493 USETW(req.wLength, 0);
494 r = usbd_do_request(dev, &req, 0);
495 #if 0
496 XXX should we do this?
497 if (r == USBD_NORMAL_COMPLETION) {
498 pipe->state = USBD_PIPE_ACTIVE;
499 /* XXX activate pipe */
500 }
501 #endif
502 return (r);
503 }
504
505 usbd_status
506 usbd_clear_endpoint_stall_async(pipe)
507 usbd_pipe_handle pipe;
508 {
509 usbd_device_handle dev = pipe->device;
510 usb_device_request_t req;
511 usbd_status r;
512
513 req.bmRequestType = UT_WRITE_ENDPOINT;
514 req.bRequest = UR_CLEAR_FEATURE;
515 USETW(req.wValue, UF_ENDPOINT_HALT);
516 USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);
517 USETW(req.wLength, 0);
518 r = usbd_do_request_async(dev, &req, 0);
519 return (r);
520 }
521
522 usbd_status
523 usbd_set_pipe_state(pipe, state)
524 usbd_pipe_handle pipe;
525 usbd_pipe_state state;
526 {
527 int s;
528 usbd_status r;
529 usbd_request_handle reqh;
530
531 if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
532 return (USBD_INTERFACE_NOT_ACTIVE);
533 if (state != USBD_PIPE_ACTIVE &&
534 state != USBD_PIPE_STALLED &&
535 state != USBD_PIPE_IDLE)
536 return (USBD_INVAL);
537 pipe->state = state;
538 r = USBD_NORMAL_COMPLETION;
539 if (state == USBD_PIPE_ACTIVE) {
540 s = splusb();
541 if (!pipe->running) {
542 reqh = SIMPLEQ_FIRST(&pipe->queue);
543 if (reqh != 0) {
544 pipe->running = 1;
545 splx(s);
546 r = pipe->methods->start(reqh);
547 } else
548 splx(s);
549 } else
550 splx(s);
551 }
552 return (r);
553 }
554
555 usbd_status
556 usbd_get_pipe_state(pipe, state, endpoint_state, request_count)
557 usbd_pipe_handle pipe;
558 usbd_pipe_state *state;
559 u_int32_t *endpoint_state;
560 u_int32_t *request_count;
561 {
562 int n;
563 usbd_request_handle r;
564
565 *state = pipe->state;
566 *endpoint_state = pipe->endpoint->state;
567 for (r = SIMPLEQ_FIRST(&pipe->queue), n = 0;
568 r != 0;
569 r = SIMPLEQ_NEXT(r, next), n++)
570 ;
571 *request_count = n;
572 return (USBD_NORMAL_COMPLETION);
573 }
574
575 usbd_status
576 usbd_set_interface_state(iface, state)
577 usbd_interface_handle iface;
578 usbd_interface_state state;
579 {
580 int ps;
581 usbd_pipe_handle p;
582
583 if (state == USBD_INTERFACE_ACTIVE)
584 ps = USBD_PIPE_ACTIVE;
585 else if (state == USBD_INTERFACE_STALLED)
586 ps = USBD_PIPE_STALLED;
587 else if (state == USBD_INTERFACE_IDLE)
588 ps = USBD_PIPE_IDLE;
589 else
590 return (USBD_INVAL);
591 iface->state = USBD_INTERFACE_ACTIVE; /* to allow setting the pipe */
592 for (p = LIST_FIRST(&iface->pipes); p != 0; p = LIST_NEXT(p, next))
593 usbd_set_pipe_state(p, ps);
594 iface->state = state;
595 return (USBD_NORMAL_COMPLETION);
596 }
597
598 usbd_status
599 usbd_get_interface_state(iface, state)
600 usbd_interface_handle iface;
601 usbd_interface_state *state;
602 {
603 *state = iface->state;
604 return (USBD_NORMAL_COMPLETION);
605 }
606
607 usbd_status
608 usbd_get_device_state(dev, state)
609 usbd_device_handle dev;
610 usbd_device_state *state;
611 {
612 *state = dev->state;
613 return (USBD_NORMAL_COMPLETION);
614 }
615
616 #if 0
617 usbd_status
618 usbd_set_device_state(dev, state)
619 usbd_device_handle dev;
620 usbd_device_state state;
621 X
622 #endif
623
624 usbd_status
625 usbd_device_address(dev, address)
626 usbd_device_handle dev;
627 u_int8_t *address;
628 {
629 *address = dev->address;
630 return (USBD_NORMAL_COMPLETION);
631 }
632
633 usbd_status
634 usbd_endpoint_address(pipe, address)
635 usbd_pipe_handle pipe;
636 u_int8_t *address;
637 {
638 *address = pipe->endpoint->edesc->bEndpointAddress;
639 return (USBD_NORMAL_COMPLETION);
640 }
641
642 usbd_status
643 usbd_endpoint_count(iface, count)
644 usbd_interface_handle iface;
645 u_int8_t *count;
646 {
647 *count = iface->idesc->bNumEndpoints;
648 return (USBD_NORMAL_COMPLETION);
649 }
650
651 usbd_status
652 usbd_interface_count(dev, count)
653 usbd_device_handle dev;
654 u_int8_t *count;
655 {
656 if (!dev->cdesc)
657 return (USBD_NOT_CONFIGURED);
658 *count = dev->cdesc->bNumInterface;
659 return (USBD_NORMAL_COMPLETION);
660 }
661
662 #if 0
663 u_int8_t
664 usbd_bus_count()
665 {
666 return (usb_bus_count());
667 }
668
669 usbd_status
670 usbd_get_bus_handle(index, bus)
671 u_int8_t index;
672 usbd_bus_handle *bus;
673 {
674 return (usb_get_bus_handle(index, bus));
675 }
676 #endif
677
678 usbd_status
679 usbd_get_root_hub(bus, dev)
680 usbd_bus_handle bus;
681 usbd_device_handle *dev;
682 {
683 *dev = bus->root_hub;
684 return (USBD_NORMAL_COMPLETION);
685 }
686
687 usbd_status
688 usbd_port_count(dev, nports)
689 usbd_device_handle dev;
690 u_int8_t *nports;
691 {
692 if (dev->hub == 0)
693 return (USBD_INVAL);
694 *nports = dev->hub->hubdesc.bNbrPorts;
695 return (USBD_NORMAL_COMPLETION);
696 }
697
698 usbd_status
699 usbd_hub2device_handle(dev, port, devp)
700 usbd_device_handle dev;
701 u_int8_t port;
702 usbd_device_handle *devp;
703 {
704 if (dev->hub == 0 || port >= dev->hub->hubdesc.bNbrPorts ||
705 dev->hub->ports[port].device == 0)
706 return (USBD_INVAL);
707 *devp = dev->hub->ports[port].device;
708 return (USBD_NORMAL_COMPLETION);
709 }
710
711 usbd_status
712 usbd_request2pipe_handle(reqh, pipe)
713 usbd_request_handle reqh;
714 usbd_pipe_handle *pipe;
715 {
716 *pipe = reqh->pipe;
717 return (USBD_NORMAL_COMPLETION);
718 }
719
720 usbd_status
721 usbd_pipe2interface_handle(pipe, iface)
722 usbd_pipe_handle pipe;
723 usbd_interface_handle *iface;
724 {
725 *iface = pipe->iface;
726 return (USBD_NORMAL_COMPLETION);
727 }
728
729 usbd_status
730 usbd_interface2device_handle(iface, dev)
731 usbd_interface_handle iface;
732 usbd_device_handle *dev;
733 {
734 *dev = iface->device;
735 return (USBD_NORMAL_COMPLETION);
736 }
737
738 usbd_status
739 usbd_device2bus_handle(dev, bus)
740 usbd_device_handle dev;
741 usbd_bus_handle *bus;
742 {
743 *bus = dev->bus;
744 return (USBD_NORMAL_COMPLETION);
745 }
746
747 usbd_status
748 usbd_device2interface_handle(dev, ifaceno, iface)
749 usbd_device_handle dev;
750 u_int8_t ifaceno;
751 usbd_interface_handle *iface;
752 {
753 if (!dev->cdesc)
754 return (USBD_NOT_CONFIGURED);
755 if (ifaceno >= dev->cdesc->bNumInterface)
756 return (USBD_INVAL);
757 *iface = &dev->ifaces[ifaceno];
758 return (USBD_NORMAL_COMPLETION);
759 }
760
761 usbd_status
762 usbd_set_interface_private_handle(iface, priv)
763 usbd_interface_handle iface;
764 usbd_private_handle priv;
765 {
766 iface->priv = priv;
767 return (USBD_NORMAL_COMPLETION);
768 }
769
770 usbd_status
771 usbd_get_interface_private_handle(iface, priv)
772 usbd_interface_handle iface;
773 usbd_private_handle *priv;
774 {
775 *priv = iface->priv;
776 return (USBD_NORMAL_COMPLETION);
777 }
778
779 usbd_status
780 usbd_reference_pipe(pipe)
781 usbd_pipe_handle pipe;
782 {
783 pipe->refcnt++;
784 return (USBD_NORMAL_COMPLETION);
785 }
786
787 usbd_status
788 usbd_dereference_pipe(pipe)
789 usbd_pipe_handle pipe;
790 {
791 pipe->refcnt--;
792 return (USBD_NORMAL_COMPLETION);
793 }
794
795 usbd_lock_token
796 usbd_lock()
797 {
798 return (splusb());
799 }
800
801 void
802 usbd_unlock(tok)
803 usbd_lock_token tok;
804 {
805 splx(tok);
806 }
807
808 /* XXXX use altno */
809 usbd_status
810 usbd_set_interface(iface, altidx)
811 usbd_interface_handle iface;
812 int altidx;
813 {
814 usb_device_request_t req;
815 usbd_status r;
816
817 if (LIST_FIRST(&iface->pipes) != 0)
818 return (USBD_IN_USE);
819
820 if (iface->endpoints)
821 free(iface->endpoints, M_USB);
822 iface->endpoints = 0;
823 iface->idesc = 0;
824 iface->state = USBD_INTERFACE_IDLE;
825
826 r = usbd_fill_iface_data(iface->device, iface->index, altidx);
827 if (r != USBD_NORMAL_COMPLETION)
828 return (r);
829
830 req.bmRequestType = UT_WRITE_INTERFACE;
831 req.bRequest = UR_SET_INTERFACE;
832 USETW(req.wValue, iface->idesc->bAlternateSetting);
833 USETW(req.wIndex, iface->idesc->bInterfaceNumber);
834 USETW(req.wLength, 0);
835 return usbd_do_request(iface->device, &req, 0);
836 }
837
838 int
839 usbd_get_no_alts(cdesc, ifaceno)
840 usb_config_descriptor_t *cdesc;
841 int ifaceno;
842 {
843 char *p = (char *)cdesc;
844 char *end = p + UGETW(cdesc->wTotalLength);
845 usb_interface_descriptor_t *d;
846 int n;
847
848 for (n = 0; p < end; p += d->bLength) {
849 d = (usb_interface_descriptor_t *)p;
850 if (p + d->bLength <= end &&
851 d->bDescriptorType == UDESC_INTERFACE &&
852 d->bInterfaceNumber == ifaceno)
853 n++;
854 }
855 return (n);
856 }
857
858 int
859 usbd_get_interface_altindex(iface)
860 usbd_interface_handle iface;
861 {
862 return (iface->altindex);
863 }
864
865 usbd_status
866 usbd_get_interface(iface, aiface)
867 usbd_interface_handle iface;
868 u_int8_t *aiface;
869 {
870 usb_device_request_t req;
871
872 req.bmRequestType = UT_READ_INTERFACE;
873 req.bRequest = UR_GET_INTERFACE;
874 USETW(req.wValue, 0);
875 USETW(req.wIndex, iface->idesc->bInterfaceNumber);
876 USETW(req.wLength, 1);
877 return usbd_do_request(iface->device, &req, aiface);
878 }
879
880 /*** Internal routines ***/
881
882 /* Dequeue all pipe operations, called at splusb(). */
883 static usbd_status
884 usbd_ar_pipe(pipe)
885 usbd_pipe_handle pipe;
886 {
887 usbd_request_handle reqh;
888
889 #if 0
890 for (;;) {
891 reqh = SIMPLEQ_FIRST(&pipe->queue);
892 if (reqh == 0)
893 break;
894 SIMPLEQ_REMOVE_HEAD(&pipe->queue, reqh, next);
895 reqh->status = USBD_CANCELLED;
896 if (reqh->callback)
897 reqh->callback(reqh, reqh->priv, reqh->status);
898 }
899 #else
900 while ((reqh = SIMPLEQ_FIRST(&pipe->queue))) {
901 pipe->methods->abort(reqh);
902 SIMPLEQ_REMOVE_HEAD(&pipe->queue, reqh, next);
903 }
904 #endif
905 return (USBD_NORMAL_COMPLETION);
906 }
907
908 /* Dequeue all interface operations, called at splusb(). */
909 static usbd_status
910 usbd_ar_iface(iface)
911 usbd_interface_handle iface;
912 {
913 usbd_pipe_handle p;
914 usbd_status r, ret = USBD_NORMAL_COMPLETION;
915
916 for (p = LIST_FIRST(&iface->pipes); p != 0; p = LIST_NEXT(p, next)) {
917 r = usbd_ar_pipe(p);
918 if (r != USBD_NORMAL_COMPLETION)
919 ret = r;
920 }
921 return (ret);
922 }
923
924 static int usbd_global_init_done = 0;
925
926 void
927 usbd_init()
928 {
929 #if defined(__FreeBSD__)
930 dev_t dev;
931 #endif
932
933 if (!usbd_global_init_done) {
934 usbd_global_init_done = 1;
935 SIMPLEQ_INIT(&usbd_free_requests);
936
937 #if defined(__FreeBSD__)
938 dev = makedev(USB_CDEV_MAJOR, 0);
939 cdevsw_add(&dev, &usb_cdevsw, NULL);
940 #endif
941 }
942 }
943
944 static void
945 usbd_transfer_cb(reqh)
946 usbd_request_handle reqh;
947 {
948 usbd_pipe_handle pipe = reqh->pipe;
949
950 DPRINTFN(10, ("usbd_transfer_cb: reqh=%p\n", reqh));
951 /* Count completed transfers. */
952 ++pipe->device->bus->stats.requests
953 [pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE];
954
955 /* XXX check retry count */
956 reqh->done = 1;
957 if (reqh->status == USBD_NORMAL_COMPLETION &&
958 reqh->actlen < reqh->length &&
959 !(reqh->flags & USBD_SHORT_XFER_OK)) {
960 DPRINTFN(-1, ("usbd_transfer_cb: short xfer %d<%d (bytes)\n",
961 reqh->actlen, reqh->length));
962 reqh->status = USBD_SHORT_XFER;
963 }
964 if (reqh->callback)
965 reqh->callback(reqh, reqh->priv, reqh->status);
966 }
967
968 static void
969 usbd_sync_transfer_cb(reqh)
970 usbd_request_handle reqh;
971 {
972 DPRINTFN(10, ("usbd_sync_transfer_cb: reqh=%p\n", reqh));
973 usbd_transfer_cb(reqh);
974 if (!reqh->pipe->device->bus->use_polling)
975 wakeup(reqh);
976 }
977
978 /* Like usbd_transfer(), but waits for completion. */
979 usbd_status
980 usbd_sync_transfer(reqh)
981 usbd_request_handle reqh;
982 {
983 usbd_status r;
984 int s;
985
986 reqh->xfercb = usbd_sync_transfer_cb;
987 r = usbd_do_transfer(reqh);
988 if (r != USBD_IN_PROGRESS)
989 return (r);
990 s = splusb();
991 if (!reqh->done) {
992 if (reqh->pipe->device->bus->use_polling)
993 panic("usbd_sync_transfer: not done\n");
994 tsleep(reqh, PRIBIO, "usbsyn", 0);
995 }
996 splx(s);
997 return (reqh->status);
998 }
999
1000 usbd_status
1001 usbd_do_request(dev, req, data)
1002 usbd_device_handle dev;
1003 usb_device_request_t *req;
1004 void *data;
1005 {
1006 return (usbd_do_request_flags(dev, req, data, 0, 0));
1007 }
1008
1009 usbd_status
1010 usbd_do_request_flags(dev, req, data, flags, actlen)
1011 usbd_device_handle dev;
1012 usb_device_request_t *req;
1013 void *data;
1014 u_int16_t flags;
1015 int *actlen;
1016 {
1017 usbd_request_handle reqh;
1018 usbd_status r;
1019
1020 #ifdef DIAGNOSTIC
1021 if (!curproc) {
1022 printf("usbd_do_request: not in process context\n");
1023 return (USBD_XXX);
1024 }
1025 #endif
1026
1027 reqh = usbd_alloc_request();
1028 if (reqh == 0)
1029 return (USBD_NOMEM);
1030 r = usbd_setup_default_request(
1031 reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req, data,
1032 UGETW(req->wLength), flags, 0);
1033 if (r != USBD_NORMAL_COMPLETION)
1034 goto bad;
1035 r = usbd_sync_transfer(reqh);
1036 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
1037 if (reqh->actlen > reqh->length)
1038 printf("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
1039 "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
1040 dev->address, reqh->request.bmRequestType,
1041 reqh->request.bRequest, UGETW(reqh->request.wValue),
1042 UGETW(reqh->request.wIndex),
1043 UGETW(reqh->request.wLength),
1044 reqh->length, reqh->actlen);
1045 #endif
1046 if (actlen)
1047 *actlen = reqh->actlen;
1048 if (r == USBD_STALLED) {
1049 /*
1050 * The control endpoint has stalled. Control endpoints
1051 * should not halt, but some may do so anyway so clear
1052 * any halt condition.
1053 */
1054 usb_device_request_t treq;
1055 usb_status_t status;
1056 u_int16_t s;
1057 usbd_status nr;
1058
1059 treq.bmRequestType = UT_READ_ENDPOINT;
1060 treq.bRequest = UR_GET_STATUS;
1061 USETW(treq.wValue, 0);
1062 USETW(treq.wIndex, 0);
1063 USETW(treq.wLength, sizeof(usb_status_t));
1064 nr = usbd_setup_default_request(
1065 reqh, dev, 0, USBD_DEFAULT_TIMEOUT, &treq, &status,
1066 sizeof(usb_status_t), 0, 0);
1067 if (nr != USBD_NORMAL_COMPLETION)
1068 goto bad;
1069 nr = usbd_sync_transfer(reqh);
1070 if (nr != USBD_NORMAL_COMPLETION)
1071 goto bad;
1072 s = UGETW(status.wStatus);
1073 DPRINTF(("usbd_do_request: status = 0x%04x\n", s));
1074 if (!(s & UES_HALT))
1075 goto bad;
1076 treq.bmRequestType = UT_WRITE_ENDPOINT;
1077 treq.bRequest = UR_CLEAR_FEATURE;
1078 USETW(treq.wValue, UF_ENDPOINT_HALT);
1079 USETW(treq.wIndex, 0);
1080 USETW(treq.wLength, 0);
1081 nr = usbd_setup_default_request(
1082 reqh, dev, 0, USBD_DEFAULT_TIMEOUT, &treq, &status,
1083 0, 0, 0);
1084 if (nr != USBD_NORMAL_COMPLETION)
1085 goto bad;
1086 nr = usbd_sync_transfer(reqh);
1087 if (nr != USBD_NORMAL_COMPLETION)
1088 goto bad;
1089 }
1090
1091 bad:
1092 usbd_free_request(reqh);
1093 return (r);
1094 }
1095
1096 void
1097 usbd_do_request_async_cb(reqh, priv, status)
1098 usbd_request_handle reqh;
1099 usbd_private_handle priv;
1100 usbd_status status;
1101 {
1102 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
1103 if (reqh->actlen > reqh->length)
1104 printf("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
1105 "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
1106 reqh->pipe->device->address,
1107 reqh->request.bmRequestType,
1108 reqh->request.bRequest, UGETW(reqh->request.wValue),
1109 UGETW(reqh->request.wIndex),
1110 UGETW(reqh->request.wLength),
1111 reqh->length, reqh->actlen);
1112 #endif
1113 usbd_free_request(reqh);
1114 }
1115
1116 /*
1117 * Execute a request without waiting for completion.
1118 * Can be used from interrupt context.
1119 */
1120 usbd_status
1121 usbd_do_request_async(dev, req, data)
1122 usbd_device_handle dev;
1123 usb_device_request_t *req;
1124 void *data;
1125 {
1126 usbd_request_handle reqh;
1127 usbd_status r;
1128
1129 reqh = usbd_alloc_request();
1130 if (reqh == 0)
1131 return (USBD_NOMEM);
1132 r = usbd_setup_default_request(
1133 reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req, data,
1134 UGETW(req->wLength), 0, usbd_do_request_async_cb);
1135 if (r != USBD_NORMAL_COMPLETION) {
1136 usbd_free_request(reqh);
1137 return (r);
1138 }
1139 r = usbd_transfer(reqh);
1140 if (r != USBD_IN_PROGRESS)
1141 return (r);
1142 return (USBD_NORMAL_COMPLETION);
1143 }
1144
1145 struct usbd_quirks *
1146 usbd_get_quirks(dev)
1147 usbd_device_handle dev;
1148 {
1149 return (dev->quirks);
1150 }
1151
1152 void
1153 usbd_set_disco(p, hdl, data)
1154 usbd_pipe_handle p;
1155 void (*hdl) __P((void *));
1156 void *data;
1157 {
1158 p->disco = hdl;
1159 p->discoarg = data;
1160 }
1161
1162 /* XXX do periodic free() of free list */
1163
1164 /*
1165 * Called from keyboard driver when in polling mode.
1166 */
1167 void
1168 usbd_dopoll(iface)
1169 usbd_interface_handle iface;
1170 {
1171 iface->device->bus->do_poll(iface->device->bus);
1172 }
1173
1174 void
1175 usbd_set_polling(iface, on)
1176 usbd_interface_handle iface;
1177 int on;
1178 {
1179 iface->device->bus->use_polling = on;
1180 }
1181
1182
1183 usb_endpoint_descriptor_t *
1184 usbd_get_endpoint_descriptor(iface, address)
1185 usbd_interface_handle iface;
1186 u_int8_t address;
1187 {
1188 struct usbd_endpoint *ep;
1189 int i;
1190
1191 for (i = 0; i < iface->idesc->bNumEndpoints; i++) {
1192 ep = &iface->endpoints[i];
1193 if (ep->edesc->bEndpointAddress == address)
1194 return (iface->endpoints[i].edesc);
1195 }
1196 return (0);
1197 }
1198
1199 #if defined(__FreeBSD__)
1200 void
1201 usbd_print_child(device_t parent, device_t child)
1202 {
1203 /*
1204 struct usb_softc *sc = device_get_softc(child);
1205 */
1206
1207 printf(" at %s%d", device_get_name(parent), device_get_unit(parent));
1208
1209 /* XXX How do we get to the usbd_device_handle???
1210 usbd_device_handle dev = invalidadosch;
1211
1212 printf(" addr %d", dev->addr);
1213
1214 if (bootverbose) {
1215 if (dev->lowspeed)
1216 printf(", lowspeed");
1217 if (dev->self_powered)
1218 printf(", self powered");
1219 else
1220 printf(", %dmA", dev->power);
1221 printf(", config %d", dev->config);
1222 }
1223 */
1224 }
1225
1226 /* Reconfigure all the USB busses in the system. */
1227 int
1228 usbd_driver_load(module_t mod, int what, void *arg)
1229 {
1230 devclass_t usb_devclass = devclass_find("usb");
1231 devclass_t ugen_devclass = devclass_find("ugen");
1232 device_t *devlist;
1233 int devcount;
1234 int error;
1235
1236 switch (what) {
1237 case MOD_LOAD:
1238 case MOD_UNLOAD:
1239 if (!usb_devclass)
1240 return 0; /* just ignore call */
1241
1242 if (ugen_devclass) {
1243 /* detach devices from generic driver if possible */
1244 error = devclass_get_devices(ugen_devclass, &devlist,
1245 &devcount);
1246 if (!error)
1247 for (devcount--; devcount >= 0; devcount--)
1248 (void)DEVICE_DETACH(devlist[devcount]);
1249 }
1250
1251 error = devclass_get_devices(usb_devclass, &devlist, &devcount);
1252 if (error)
1253 return 0; /* XXX maybe transient, or error? */
1254
1255 for (devcount--; devcount >= 0; devcount--)
1256 USB_RECONFIGURE(devlist[devcount]);
1257
1258 free(devlist, M_TEMP);
1259 return 0;
1260 }
1261
1262 return 0; /* nothing to do by us */
1263 }
1264
1265 /* Set the description of the device including a malloc and copy. */
1266 void
1267 usbd_device_set_desc(device_t device, char *devinfo)
1268 {
1269 size_t l;
1270 char *desc;
1271
1272 if ( devinfo ) {
1273 l = strlen(devinfo);
1274 desc = malloc(l+1, M_USB, M_NOWAIT);
1275 if (desc)
1276 memcpy(desc, devinfo, l+1);
1277 } else
1278 desc = NULL;
1279
1280 device_set_desc(device, desc);
1281 }
1282
1283 char *
1284 usbd_devname(bdevice *bdev)
1285 {
1286 static char buf[20];
1287 /*
1288 * A static buffer is a loss if this routine is used from an interrupt,
1289 * but it's not fatal.
1290 */
1291
1292 sprintf(buf, "%s%d", device_get_name(*bdev), device_get_unit(*bdev));
1293 return (buf);
1294 }
1295
1296 #endif
1297