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