usbdi.c revision 1.30 1 /* $NetBSD: usbdi.c,v 1.30 1999/08/17 20:59:04 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__) || defined(__OpenBSD__)
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) logprintf x
65 #define DPRINTFN(n,x) if (usbdebug>(n)) logprintf 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 void usbd_transfer_cb __P((usbd_request_handle reqh));
74 static void usbd_sync_transfer_cb __P((usbd_request_handle reqh));
75 static usbd_status usbd_do_transfer __P((usbd_request_handle reqh));
76 void usbd_do_request_async_cb
77 __P((usbd_request_handle, usbd_private_handle, usbd_status));
78
79 static SIMPLEQ_HEAD(, usbd_request) usbd_free_requests;
80
81 #if defined(__FreeBSD__)
82 #define USB_CDEV_MAJOR 108
83
84 extern struct cdevsw usb_cdevsw;
85 #endif
86
87 #ifdef USB_DEBUG
88 void usbd_dump_queue __P((usbd_pipe_handle));
89
90 void
91 usbd_dump_queue(pipe)
92 usbd_pipe_handle pipe;
93 {
94 usbd_request_handle reqh;
95
96 printf("usbd_dump_queue: pipe=%p\n", pipe);
97 for (reqh = SIMPLEQ_FIRST(&pipe->queue);
98 reqh;
99 reqh = SIMPLEQ_NEXT(reqh, next)) {
100 printf(" reqh=%p\n", reqh);
101 }
102 }
103 #endif
104
105 usbd_status
106 usbd_open_pipe(iface, address, flags, pipe)
107 usbd_interface_handle iface;
108 u_int8_t address;
109 u_int8_t flags;
110 usbd_pipe_handle *pipe;
111 {
112 usbd_pipe_handle p;
113 struct usbd_endpoint *ep;
114 usbd_status r;
115 int i;
116
117 for (i = 0; i < iface->idesc->bNumEndpoints; i++) {
118 ep = &iface->endpoints[i];
119 if (ep->edesc->bEndpointAddress == address)
120 goto found;
121 }
122 return (USBD_BAD_ADDRESS);
123 found:
124 if ((flags & USBD_EXCLUSIVE_USE) &&
125 ep->refcnt != 0)
126 return (USBD_IN_USE);
127 r = usbd_setup_pipe(iface->device, iface, ep, &p);
128 if (r != USBD_NORMAL_COMPLETION)
129 return (r);
130 LIST_INSERT_HEAD(&iface->pipes, p, next);
131 *pipe = p;
132 return (USBD_NORMAL_COMPLETION);
133 }
134
135 usbd_status
136 usbd_open_pipe_intr(iface, address, flags, pipe, priv, buffer, length, cb)
137 usbd_interface_handle iface;
138 u_int8_t address;
139 u_int8_t flags;
140 usbd_pipe_handle *pipe;
141 usbd_private_handle priv;
142 void *buffer;
143 u_int32_t length;
144 usbd_callback cb;
145 {
146 usbd_status r;
147 usbd_request_handle reqh;
148 usbd_pipe_handle ipipe;
149
150 reqh = usbd_alloc_request();
151 if (reqh == 0)
152 return (USBD_NOMEM);
153 r = usbd_open_pipe(iface, address, USBD_EXCLUSIVE_USE, &ipipe);
154 if (r != USBD_NORMAL_COMPLETION)
155 goto bad1;
156 r = usbd_setup_request(reqh, ipipe, priv, buffer, length,
157 USBD_XFER_IN | flags, USBD_NO_TIMEOUT, cb);
158 if (r != USBD_NORMAL_COMPLETION)
159 goto bad2;
160 ipipe->intrreqh = reqh;
161 ipipe->repeat = 1;
162 r = usbd_transfer(reqh);
163 *pipe = ipipe;
164 if (r != USBD_IN_PROGRESS)
165 goto bad3;
166 return (USBD_NORMAL_COMPLETION);
167
168 bad3:
169 ipipe->intrreqh = 0;
170 ipipe->repeat = 0;
171 bad2:
172 usbd_close_pipe(ipipe);
173 bad1:
174 usbd_free_request(reqh);
175 return r;
176 }
177
178 usbd_status
179 usbd_open_pipe_iso(iface, address, flags, pipe, priv, bufsize, nbuf)
180 usbd_interface_handle iface;
181 u_int8_t address;
182 u_int8_t flags;
183 usbd_pipe_handle *pipe;
184 usbd_private_handle priv;
185 u_int32_t bufsize;
186 u_int32_t nbuf;
187 {
188 usbd_status r;
189 usbd_pipe_handle p;
190
191 r = usbd_open_pipe(iface, address, USBD_EXCLUSIVE_USE, &p);
192 if (r != USBD_NORMAL_COMPLETION)
193 return (r);
194 if (!p->methods->isobuf) {
195 usbd_close_pipe(p);
196 return (USBD_INVAL);
197 }
198 r = p->methods->isobuf(p, bufsize, nbuf);
199 if (r != USBD_NORMAL_COMPLETION) {
200 usbd_close_pipe(p);
201 return (r);
202 }
203 *pipe = p;
204 return r;
205 }
206
207 usbd_status
208 usbd_close_pipe(pipe)
209 usbd_pipe_handle pipe;
210 {
211 #ifdef DIAGNOSTIC
212 if (pipe == 0) {
213 printf("usbd_close_pipe: pipe==NULL\n");
214 return (USBD_NORMAL_COMPLETION);
215 }
216 #endif
217
218 if (--pipe->refcnt != 0)
219 return (USBD_NORMAL_COMPLETION);
220 if (SIMPLEQ_FIRST(&pipe->queue) != 0)
221 return (USBD_PENDING_REQUESTS);
222 LIST_REMOVE(pipe, next);
223 pipe->endpoint->refcnt--;
224 pipe->methods->close(pipe);
225 if (pipe->intrreqh)
226 usbd_free_request(pipe->intrreqh);
227 free(pipe, M_USB);
228 return (USBD_NORMAL_COMPLETION);
229 }
230
231 usbd_status
232 usbd_transfer(reqh)
233 usbd_request_handle reqh;
234 {
235 reqh->xfercb = usbd_transfer_cb;
236 return (usbd_do_transfer(reqh));
237 }
238
239 static usbd_status
240 usbd_do_transfer(reqh)
241 usbd_request_handle reqh;
242 {
243 usbd_pipe_handle pipe = reqh->pipe;
244
245 DPRINTFN(5,("usbd_do_transfer: reqh=%p\n", reqh));
246 #ifdef USB_DEBUG
247 if (usbdebug > 5)
248 usbd_dump_queue(pipe);
249 #endif
250 reqh->done = 0;
251 return (pipe->methods->transfer(reqh));
252 }
253
254 usbd_request_handle
255 usbd_alloc_request()
256 {
257 usbd_request_handle reqh;
258
259 reqh = SIMPLEQ_FIRST(&usbd_free_requests);
260 if (reqh)
261 SIMPLEQ_REMOVE_HEAD(&usbd_free_requests, reqh, next);
262 else
263 reqh = malloc(sizeof(*reqh), M_USB, M_NOWAIT);
264 if (!reqh)
265 return (0);
266 memset(reqh, 0, sizeof *reqh);
267 DPRINTFN(1,("usbd_alloc_request() = %p\n", reqh));
268 return (reqh);
269 }
270
271 usbd_status
272 usbd_free_request(reqh)
273 usbd_request_handle reqh;
274 {
275 DPRINTFN(1,("usbd_free_request: %p\n", reqh));
276 SIMPLEQ_INSERT_HEAD(&usbd_free_requests, reqh, next);
277 return (USBD_NORMAL_COMPLETION);
278 }
279
280 usbd_status
281 usbd_setup_request(reqh, pipe, priv, buffer, length, flags, timeout, callback)
282 usbd_request_handle reqh;
283 usbd_pipe_handle pipe;
284 usbd_private_handle priv;
285 void *buffer;
286 u_int32_t length;
287 u_int16_t flags;
288 u_int32_t timeout;
289 void (*callback) __P((usbd_request_handle,
290 usbd_private_handle,
291 usbd_status));
292 {
293 reqh->pipe = pipe;
294 reqh->priv = priv;
295 reqh->buffer = buffer;
296 reqh->length = length;
297 reqh->actlen = 0;
298 reqh->flags = flags;
299 reqh->timeout = timeout;
300 reqh->status = USBD_NOT_STARTED;
301 reqh->callback = callback;
302 reqh->retries = 1;
303 reqh->isreq = 0;
304 return (USBD_NORMAL_COMPLETION);
305 }
306
307 usbd_status
308 usbd_setup_default_request(reqh, dev, priv, timeout, req, buffer,
309 length, flags, callback)
310 usbd_request_handle reqh;
311 usbd_device_handle dev;
312 usbd_private_handle priv;
313 u_int32_t timeout;
314 usb_device_request_t *req;
315 void *buffer;
316 u_int32_t length;
317 u_int16_t flags;
318 void (*callback) __P((usbd_request_handle,
319 usbd_private_handle,
320 usbd_status));
321 {
322 reqh->pipe = dev->default_pipe;
323 reqh->priv = priv;
324 reqh->buffer = buffer;
325 reqh->length = length;
326 reqh->actlen = 0;
327 reqh->flags = flags;
328 reqh->timeout = timeout;
329 reqh->status = USBD_NOT_STARTED;
330 reqh->callback = callback;
331 reqh->request = *req;
332 reqh->retries = 1;
333 reqh->isreq = 1;
334 return (USBD_NORMAL_COMPLETION);
335 }
336
337 usbd_status
338 usbd_get_request_status(reqh, priv, buffer, count, status)
339 usbd_request_handle reqh;
340 usbd_private_handle *priv;
341 void **buffer;
342 u_int32_t *count;
343 usbd_status *status;
344 {
345 *priv = reqh->priv;
346 *buffer = reqh->buffer;
347 *count = reqh->actlen;
348 *status = reqh->status;
349 return (USBD_NORMAL_COMPLETION);
350 }
351
352 usb_config_descriptor_t *
353 usbd_get_config_descriptor(dev)
354 usbd_device_handle dev;
355 {
356 return (dev->cdesc);
357 }
358
359 usb_interface_descriptor_t *
360 usbd_get_interface_descriptor(iface)
361 usbd_interface_handle iface;
362 {
363 return (iface->idesc);
364 }
365
366 usb_device_descriptor_t *
367 usbd_get_device_descriptor(dev)
368 usbd_device_handle dev;
369 {
370 return (&dev->ddesc);
371 }
372
373 usb_endpoint_descriptor_t *
374 usbd_interface2endpoint_descriptor(iface, index)
375 usbd_interface_handle iface;
376 u_int8_t index;
377 {
378 if (index >= iface->idesc->bNumEndpoints)
379 return (0);
380 return (iface->endpoints[index].edesc);
381 }
382
383 usbd_status
384 usbd_abort_pipe(pipe)
385 usbd_pipe_handle pipe;
386 {
387 usbd_status r;
388 int s;
389
390 #ifdef DIAGNOSTIC
391 if (pipe == 0) {
392 printf("usbd_close_pipe: pipe==NULL\n");
393 return (USBD_NORMAL_COMPLETION);
394 }
395 #endif
396 s = splusb();
397 r = usbd_ar_pipe(pipe);
398 splx(s);
399 return (r);
400 }
401
402 usbd_status
403 usbd_clear_endpoint_stall(pipe)
404 usbd_pipe_handle pipe;
405 {
406 usbd_device_handle dev = pipe->device;
407 usb_device_request_t req;
408 usbd_status r;
409
410 DPRINTFN(8, ("usbd_clear_endpoint_stall\n"));
411 pipe->methods->cleartoggle(pipe);
412 req.bmRequestType = UT_WRITE_ENDPOINT;
413 req.bRequest = UR_CLEAR_FEATURE;
414 USETW(req.wValue, UF_ENDPOINT_HALT);
415 USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);
416 USETW(req.wLength, 0);
417 r = usbd_do_request(dev, &req, 0);
418 #if 0
419 XXX should we do this?
420 if (r == USBD_NORMAL_COMPLETION) {
421 pipe->state = USBD_PIPE_ACTIVE;
422 /* XXX activate pipe */
423 }
424 #endif
425 return (r);
426 }
427
428 usbd_status
429 usbd_clear_endpoint_stall_async(pipe)
430 usbd_pipe_handle pipe;
431 {
432 usbd_device_handle dev = pipe->device;
433 usb_device_request_t req;
434 usbd_status r;
435
436 pipe->methods->cleartoggle(pipe);
437 req.bmRequestType = UT_WRITE_ENDPOINT;
438 req.bRequest = UR_CLEAR_FEATURE;
439 USETW(req.wValue, UF_ENDPOINT_HALT);
440 USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);
441 USETW(req.wLength, 0);
442 r = usbd_do_request_async(dev, &req, 0);
443 return (r);
444 }
445
446 usbd_status
447 usbd_endpoint_count(iface, count)
448 usbd_interface_handle iface;
449 u_int8_t *count;
450 {
451 *count = iface->idesc->bNumEndpoints;
452 return (USBD_NORMAL_COMPLETION);
453 }
454
455 usbd_status
456 usbd_interface_count(dev, count)
457 usbd_device_handle dev;
458 u_int8_t *count;
459 {
460 if (!dev->cdesc)
461 return (USBD_NOT_CONFIGURED);
462 *count = dev->cdesc->bNumInterface;
463 return (USBD_NORMAL_COMPLETION);
464 }
465
466 usbd_status
467 usbd_interface2device_handle(iface, dev)
468 usbd_interface_handle iface;
469 usbd_device_handle *dev;
470 {
471 *dev = iface->device;
472 return (USBD_NORMAL_COMPLETION);
473 }
474
475 usbd_status
476 usbd_device2interface_handle(dev, ifaceno, iface)
477 usbd_device_handle dev;
478 u_int8_t ifaceno;
479 usbd_interface_handle *iface;
480 {
481 if (!dev->cdesc)
482 return (USBD_NOT_CONFIGURED);
483 if (ifaceno >= dev->cdesc->bNumInterface)
484 return (USBD_INVAL);
485 *iface = &dev->ifaces[ifaceno];
486 return (USBD_NORMAL_COMPLETION);
487 }
488
489 /* XXXX use altno */
490 usbd_status
491 usbd_set_interface(iface, altidx)
492 usbd_interface_handle iface;
493 int altidx;
494 {
495 usb_device_request_t req;
496 usbd_status r;
497
498 if (LIST_FIRST(&iface->pipes) != 0)
499 return (USBD_IN_USE);
500
501 if (iface->endpoints)
502 free(iface->endpoints, M_USB);
503 iface->endpoints = 0;
504 iface->idesc = 0;
505
506 r = usbd_fill_iface_data(iface->device, iface->index, altidx);
507 if (r != USBD_NORMAL_COMPLETION)
508 return (r);
509
510 req.bmRequestType = UT_WRITE_INTERFACE;
511 req.bRequest = UR_SET_INTERFACE;
512 USETW(req.wValue, iface->idesc->bAlternateSetting);
513 USETW(req.wIndex, iface->idesc->bInterfaceNumber);
514 USETW(req.wLength, 0);
515 return usbd_do_request(iface->device, &req, 0);
516 }
517
518 int
519 usbd_get_no_alts(cdesc, ifaceno)
520 usb_config_descriptor_t *cdesc;
521 int ifaceno;
522 {
523 char *p = (char *)cdesc;
524 char *end = p + UGETW(cdesc->wTotalLength);
525 usb_interface_descriptor_t *d;
526 int n;
527
528 for (n = 0; p < end; p += d->bLength) {
529 d = (usb_interface_descriptor_t *)p;
530 if (p + d->bLength <= end &&
531 d->bDescriptorType == UDESC_INTERFACE &&
532 d->bInterfaceNumber == ifaceno)
533 n++;
534 }
535 return (n);
536 }
537
538 int
539 usbd_get_interface_altindex(iface)
540 usbd_interface_handle iface;
541 {
542 return (iface->altindex);
543 }
544
545 usbd_status
546 usbd_get_interface(iface, aiface)
547 usbd_interface_handle iface;
548 u_int8_t *aiface;
549 {
550 usb_device_request_t req;
551
552 req.bmRequestType = UT_READ_INTERFACE;
553 req.bRequest = UR_GET_INTERFACE;
554 USETW(req.wValue, 0);
555 USETW(req.wIndex, iface->idesc->bInterfaceNumber);
556 USETW(req.wLength, 1);
557 return usbd_do_request(iface->device, &req, aiface);
558 }
559
560 /*** Internal routines ***/
561
562 /* Dequeue all pipe operations, called at splusb(). */
563 static usbd_status
564 usbd_ar_pipe(pipe)
565 usbd_pipe_handle pipe;
566 {
567 usbd_request_handle reqh;
568
569 DPRINTFN(2,("usbd_ar_pipe: pipe=%p\n", pipe));
570 #ifdef USB_DEBUG
571 if (usbdebug > 5)
572 usbd_dump_queue(pipe);
573 #endif
574 while ((reqh = SIMPLEQ_FIRST(&pipe->queue))) {
575 DPRINTFN(2,("usbd_ar_pipe: pipe=%p reqh=%p (methods=%p)\n",
576 pipe, reqh, pipe->methods));
577 /* Make the HC abort it (and invoke the callback). */
578 pipe->methods->abort(reqh);
579 }
580 return (USBD_NORMAL_COMPLETION);
581 }
582
583 static int usbd_global_init_done = 0;
584
585 void
586 usbd_init()
587 {
588 #if defined(__FreeBSD__)
589 dev_t dev;
590 #endif
591
592 if (!usbd_global_init_done) {
593 usbd_global_init_done = 1;
594 SIMPLEQ_INIT(&usbd_free_requests);
595
596 #if defined(__FreeBSD__)
597 dev = makedev(USB_CDEV_MAJOR, 0);
598 cdevsw_add(&dev, &usb_cdevsw, NULL);
599 #endif
600 }
601 }
602
603 static void
604 usbd_transfer_cb(reqh)
605 usbd_request_handle reqh;
606 {
607 usbd_pipe_handle pipe = reqh->pipe;
608
609 DPRINTFN(10, ("usbd_transfer_cb: reqh=%p\n", reqh));
610 /* Count completed transfers. */
611 #ifdef DIAGNOSTIC
612 if (!pipe)
613 printf("usbd_transfer_cb: pipe==0, reqh=%p\n", reqh);
614 else
615 #endif
616 ++pipe->device->bus->stats.requests
617 [pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE];
618
619 /* XXX check retry count */
620 reqh->done = 1;
621 if (reqh->status == USBD_NORMAL_COMPLETION &&
622 reqh->actlen < reqh->length &&
623 !(reqh->flags & USBD_SHORT_XFER_OK)) {
624 DPRINTFN(-1, ("usbd_transfer_cb: short xfer %d<%d (bytes)\n",
625 reqh->actlen, reqh->length));
626 reqh->status = USBD_SHORT_XFER;
627 }
628 if (reqh->callback)
629 reqh->callback(reqh, reqh->priv, reqh->status);
630 }
631
632 static void
633 usbd_sync_transfer_cb(reqh)
634 usbd_request_handle reqh;
635 {
636 DPRINTFN(10, ("usbd_sync_transfer_cb: reqh=%p\n", reqh));
637 usbd_transfer_cb(reqh);
638 if (!reqh->pipe->device->bus->use_polling)
639 wakeup(reqh);
640 }
641
642 /* Like usbd_transfer(), but waits for completion. */
643 usbd_status
644 usbd_sync_transfer(reqh)
645 usbd_request_handle reqh;
646 {
647 usbd_status r;
648 int s;
649
650 reqh->xfercb = usbd_sync_transfer_cb;
651 r = usbd_do_transfer(reqh);
652 if (r != USBD_IN_PROGRESS)
653 return (r);
654 s = splusb();
655 if (!reqh->done) {
656 if (reqh->pipe->device->bus->use_polling)
657 panic("usbd_sync_transfer: not done\n");
658 tsleep(reqh, PRIBIO, "usbsyn", 0);
659 }
660 splx(s);
661 return (reqh->status);
662 }
663
664 usbd_status
665 usbd_do_request(dev, req, data)
666 usbd_device_handle dev;
667 usb_device_request_t *req;
668 void *data;
669 {
670 return (usbd_do_request_flags(dev, req, data, 0, 0));
671 }
672
673 usbd_status
674 usbd_do_request_flags(dev, req, data, flags, actlen)
675 usbd_device_handle dev;
676 usb_device_request_t *req;
677 void *data;
678 u_int16_t flags;
679 int *actlen;
680 {
681 usbd_request_handle reqh;
682 usbd_status r;
683
684 #ifdef DIAGNOSTIC
685 if (!curproc) {
686 printf("usbd_do_request: not in process context\n");
687 return (USBD_XXX);
688 }
689 #endif
690
691 reqh = usbd_alloc_request();
692 if (reqh == 0)
693 return (USBD_NOMEM);
694 r = usbd_setup_default_request(
695 reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req, data,
696 UGETW(req->wLength), flags, 0);
697 if (r != USBD_NORMAL_COMPLETION)
698 goto bad;
699 r = usbd_sync_transfer(reqh);
700 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
701 if (reqh->actlen > reqh->length)
702 printf("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
703 "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
704 dev->address, reqh->request.bmRequestType,
705 reqh->request.bRequest, UGETW(reqh->request.wValue),
706 UGETW(reqh->request.wIndex),
707 UGETW(reqh->request.wLength),
708 reqh->length, reqh->actlen);
709 #endif
710 if (actlen)
711 *actlen = reqh->actlen;
712 if (r == USBD_STALLED) {
713 /*
714 * The control endpoint has stalled. Control endpoints
715 * should not halt, but some may do so anyway so clear
716 * any halt condition.
717 */
718 usb_device_request_t treq;
719 usb_status_t status;
720 u_int16_t s;
721 usbd_status nr;
722
723 treq.bmRequestType = UT_READ_ENDPOINT;
724 treq.bRequest = UR_GET_STATUS;
725 USETW(treq.wValue, 0);
726 USETW(treq.wIndex, 0);
727 USETW(treq.wLength, sizeof(usb_status_t));
728 nr = usbd_setup_default_request(
729 reqh, dev, 0, USBD_DEFAULT_TIMEOUT, &treq, &status,
730 sizeof(usb_status_t), 0, 0);
731 if (nr != USBD_NORMAL_COMPLETION)
732 goto bad;
733 nr = usbd_sync_transfer(reqh);
734 if (nr != USBD_NORMAL_COMPLETION)
735 goto bad;
736 s = UGETW(status.wStatus);
737 DPRINTF(("usbd_do_request: status = 0x%04x\n", s));
738 if (!(s & UES_HALT))
739 goto bad;
740 treq.bmRequestType = UT_WRITE_ENDPOINT;
741 treq.bRequest = UR_CLEAR_FEATURE;
742 USETW(treq.wValue, UF_ENDPOINT_HALT);
743 USETW(treq.wIndex, 0);
744 USETW(treq.wLength, 0);
745 nr = usbd_setup_default_request(
746 reqh, dev, 0, USBD_DEFAULT_TIMEOUT, &treq, &status,
747 0, 0, 0);
748 if (nr != USBD_NORMAL_COMPLETION)
749 goto bad;
750 nr = usbd_sync_transfer(reqh);
751 if (nr != USBD_NORMAL_COMPLETION)
752 goto bad;
753 }
754
755 bad:
756 usbd_free_request(reqh);
757 return (r);
758 }
759
760 void
761 usbd_do_request_async_cb(reqh, priv, status)
762 usbd_request_handle reqh;
763 usbd_private_handle priv;
764 usbd_status status;
765 {
766 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
767 if (reqh->actlen > reqh->length)
768 printf("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
769 "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
770 reqh->pipe->device->address,
771 reqh->request.bmRequestType,
772 reqh->request.bRequest, UGETW(reqh->request.wValue),
773 UGETW(reqh->request.wIndex),
774 UGETW(reqh->request.wLength),
775 reqh->length, reqh->actlen);
776 #endif
777 usbd_free_request(reqh);
778 }
779
780 /*
781 * Execute a request without waiting for completion.
782 * Can be used from interrupt context.
783 */
784 usbd_status
785 usbd_do_request_async(dev, req, data)
786 usbd_device_handle dev;
787 usb_device_request_t *req;
788 void *data;
789 {
790 usbd_request_handle reqh;
791 usbd_status r;
792
793 reqh = usbd_alloc_request();
794 if (reqh == 0)
795 return (USBD_NOMEM);
796 r = usbd_setup_default_request(
797 reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req, data,
798 UGETW(req->wLength), 0, usbd_do_request_async_cb);
799 if (r != USBD_NORMAL_COMPLETION) {
800 usbd_free_request(reqh);
801 return (r);
802 }
803 r = usbd_transfer(reqh);
804 if (r != USBD_IN_PROGRESS)
805 return (r);
806 return (USBD_NORMAL_COMPLETION);
807 }
808
809 struct usbd_quirks *
810 usbd_get_quirks(dev)
811 usbd_device_handle dev;
812 {
813 return (dev->quirks);
814 }
815
816 /* XXX do periodic free() of free list */
817
818 /*
819 * Called from keyboard driver when in polling mode.
820 */
821 void
822 usbd_dopoll(iface)
823 usbd_interface_handle iface;
824 {
825 iface->device->bus->do_poll(iface->device->bus);
826 }
827
828 void
829 usbd_set_polling(iface, on)
830 usbd_interface_handle iface;
831 int on;
832 {
833 iface->device->bus->use_polling = on;
834 }
835
836
837 usb_endpoint_descriptor_t *
838 usbd_get_endpoint_descriptor(iface, address)
839 usbd_interface_handle iface;
840 u_int8_t address;
841 {
842 struct usbd_endpoint *ep;
843 int i;
844
845 for (i = 0; i < iface->idesc->bNumEndpoints; i++) {
846 ep = &iface->endpoints[i];
847 if (ep->edesc->bEndpointAddress == address)
848 return (iface->endpoints[i].edesc);
849 }
850 return (0);
851 }
852
853 #if defined(__FreeBSD__)
854 void
855 usbd_print_child(device_t parent, device_t child)
856 {
857 /*
858 struct usb_softc *sc = device_get_softc(child);
859 */
860
861 printf(" at %s%d", device_get_name(parent), device_get_unit(parent));
862
863 /* XXX How do we get to the usbd_device_handle???
864 usbd_device_handle dev = invalidadosch;
865
866 printf(" addr %d", dev->addr);
867
868 if (bootverbose) {
869 if (dev->lowspeed)
870 printf(", lowspeed");
871 if (dev->self_powered)
872 printf(", self powered");
873 else
874 printf(", %dmA", dev->power);
875 printf(", config %d", dev->config);
876 }
877 */
878 }
879
880 /* Reconfigure all the USB busses in the system. */
881 int
882 usbd_driver_load(module_t mod, int what, void *arg)
883 {
884 devclass_t usb_devclass = devclass_find("usb");
885 devclass_t ugen_devclass = devclass_find("ugen");
886 device_t *devlist;
887 int devcount;
888 int error;
889
890 switch (what) {
891 case MOD_LOAD:
892 case MOD_UNLOAD:
893 if (!usb_devclass)
894 return 0; /* just ignore call */
895
896 if (ugen_devclass) {
897 /* detach devices from generic driver if possible */
898 error = devclass_get_devices(ugen_devclass, &devlist,
899 &devcount);
900 if (!error)
901 for (devcount--; devcount >= 0; devcount--)
902 (void)DEVICE_DETACH(devlist[devcount]);
903 }
904
905 error = devclass_get_devices(usb_devclass, &devlist, &devcount);
906 if (error)
907 return 0; /* XXX maybe transient, or error? */
908
909 for (devcount--; devcount >= 0; devcount--)
910 USB_RECONFIGURE(devlist[devcount]);
911
912 free(devlist, M_TEMP);
913 return 0;
914 }
915
916 return 0; /* nothing to do by us */
917 }
918
919 /* Set the description of the device including a malloc and copy. */
920 void
921 usbd_device_set_desc(device_t device, char *devinfo)
922 {
923 size_t l;
924 char *desc;
925
926 if ( devinfo ) {
927 l = strlen(devinfo);
928 desc = malloc(l+1, M_USB, M_NOWAIT);
929 if (desc)
930 memcpy(desc, devinfo, l+1);
931 } else
932 desc = NULL;
933
934 device_set_desc(device, desc);
935 }
936
937 char *
938 usbd_devname(bdevice *bdev)
939 {
940 static char buf[20];
941 /*
942 * A static buffer is a loss if this routine is used from an interrupt,
943 * but it's not fatal.
944 */
945
946 sprintf(buf, "%s%d", device_get_name(*bdev), device_get_unit(*bdev));
947 return (buf);
948 }
949
950 #endif
951