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