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