Annotation of sys/dev/usb/usbdi.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: usbdi.c,v 1.33 2007/06/18 11:37:04 mbalmer Exp $ */
! 2: /* $NetBSD: usbdi.c,v 1.103 2002/09/27 15:37:38 provos Exp $ */
! 3: /* $FreeBSD: src/sys/dev/usb/usbdi.c,v 1.28 1999/11/17 22:33:49 n_hibma Exp $ */
! 4:
! 5: /*
! 6: * Copyright (c) 1998 The NetBSD Foundation, Inc.
! 7: * All rights reserved.
! 8: *
! 9: * This code is derived from software contributed to The NetBSD Foundation
! 10: * by Lennart Augustsson (lennart@augustsson.net) at
! 11: * Carlstedt Research & Technology.
! 12: *
! 13: * Redistribution and use in source and binary forms, with or without
! 14: * modification, are permitted provided that the following conditions
! 15: * are met:
! 16: * 1. Redistributions of source code must retain the above copyright
! 17: * notice, this list of conditions and the following disclaimer.
! 18: * 2. Redistributions in binary form must reproduce the above copyright
! 19: * notice, this list of conditions and the following disclaimer in the
! 20: * documentation and/or other materials provided with the distribution.
! 21: * 3. All advertising materials mentioning features or use of this software
! 22: * must display the following acknowledgement:
! 23: * This product includes software developed by the NetBSD
! 24: * Foundation, Inc. and its contributors.
! 25: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 26: * contributors may be used to endorse or promote products derived
! 27: * from this software without specific prior written permission.
! 28: *
! 29: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 30: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 31: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 32: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 33: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 34: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 35: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 36: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 37: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 38: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 39: * POSSIBILITY OF SUCH DAMAGE.
! 40: */
! 41:
! 42: #include <sys/param.h>
! 43: #include <sys/systm.h>
! 44: #include <sys/kernel.h>
! 45: #include <sys/device.h>
! 46: #include <sys/malloc.h>
! 47: #include <sys/proc.h>
! 48:
! 49: #include <machine/bus.h>
! 50:
! 51: #include <dev/usb/usb.h>
! 52: #include <dev/usb/usbdi.h>
! 53: #include <dev/usb/usbdi_util.h>
! 54: #include <dev/usb/usbdivar.h>
! 55: #include <dev/usb/usb_mem.h>
! 56:
! 57: #ifdef USB_DEBUG
! 58: #define DPRINTF(x) do { if (usbdebug) printf x; } while (0)
! 59: #define DPRINTFN(n,x) do { if (usbdebug>(n)) printf x; } while (0)
! 60: extern int usbdebug;
! 61: #else
! 62: #define DPRINTF(x)
! 63: #define DPRINTFN(n,x)
! 64: #endif
! 65:
! 66: usbd_status usbd_ar_pipe(usbd_pipe_handle pipe);
! 67: void usbd_do_request_async_cb(usbd_xfer_handle, usbd_private_handle,
! 68: usbd_status);
! 69: void usbd_start_next(usbd_pipe_handle pipe);
! 70: usbd_status usbd_open_pipe_ival(usbd_interface_handle, u_int8_t, u_int8_t,
! 71: usbd_pipe_handle *, int);
! 72:
! 73: int usbd_nbuses = 0;
! 74:
! 75: void
! 76: usbd_init(void)
! 77: {
! 78: usbd_nbuses++;
! 79: }
! 80:
! 81: void
! 82: usbd_finish(void)
! 83: {
! 84: --usbd_nbuses;
! 85: }
! 86:
! 87: static __inline int
! 88: usbd_xfer_isread(usbd_xfer_handle xfer)
! 89: {
! 90: if (xfer->rqflags & URQ_REQUEST)
! 91: return (xfer->request.bmRequestType & UT_READ);
! 92: else
! 93: return (xfer->pipe->endpoint->edesc->bEndpointAddress &
! 94: UE_DIR_IN);
! 95: }
! 96:
! 97: #ifdef USB_DEBUG
! 98: void
! 99: usbd_dump_iface(struct usbd_interface *iface)
! 100: {
! 101: printf("usbd_dump_iface: iface=%p\n", iface);
! 102: if (iface == NULL)
! 103: return;
! 104: printf(" device=%p idesc=%p index=%d altindex=%d priv=%p\n",
! 105: iface->device, iface->idesc, iface->index, iface->altindex,
! 106: iface->priv);
! 107: }
! 108:
! 109: void
! 110: usbd_dump_device(struct usbd_device *dev)
! 111: {
! 112: printf("usbd_dump_device: dev=%p\n", dev);
! 113: if (dev == NULL)
! 114: return;
! 115: printf(" bus=%p default_pipe=%p\n", dev->bus, dev->default_pipe);
! 116: printf(" address=%d config=%d depth=%d speed=%d self_powered=%d "
! 117: "power=%d langid=%d\n", dev->address, dev->config, dev->depth,
! 118: dev->speed, dev->self_powered, dev->power, dev->langid);
! 119: }
! 120:
! 121: void
! 122: usbd_dump_endpoint(struct usbd_endpoint *endp)
! 123: {
! 124: printf("usbd_dump_endpoint: endp=%p\n", endp);
! 125: if (endp == NULL)
! 126: return;
! 127: printf(" edesc=%p refcnt=%d\n", endp->edesc, endp->refcnt);
! 128: if (endp->edesc)
! 129: printf(" bEndpointAddress=0x%02x\n",
! 130: endp->edesc->bEndpointAddress);
! 131: }
! 132:
! 133: void
! 134: usbd_dump_queue(usbd_pipe_handle pipe)
! 135: {
! 136: usbd_xfer_handle xfer;
! 137:
! 138: printf("usbd_dump_queue: pipe=%p\n", pipe);
! 139: SIMPLEQ_FOREACH(xfer, &pipe->queue, next) {
! 140: printf(" xfer=%p\n", xfer);
! 141: }
! 142: }
! 143:
! 144: void
! 145: usbd_dump_pipe(usbd_pipe_handle pipe)
! 146: {
! 147: printf("usbd_dump_pipe: pipe=%p\n", pipe);
! 148: if (pipe == NULL)
! 149: return;
! 150: usbd_dump_iface(pipe->iface);
! 151: usbd_dump_device(pipe->device);
! 152: usbd_dump_endpoint(pipe->endpoint);
! 153: printf(" (usbd_dump_pipe:)\n refcnt=%d running=%d aborting=%d\n",
! 154: pipe->refcnt, pipe->running, pipe->aborting);
! 155: printf(" intrxfer=%p, repeat=%d, interval=%d\n", pipe->intrxfer,
! 156: pipe->repeat, pipe->interval);
! 157: }
! 158: #endif
! 159:
! 160: usbd_status
! 161: usbd_open_pipe(usbd_interface_handle iface, u_int8_t address, u_int8_t flags,
! 162: usbd_pipe_handle *pipe)
! 163: {
! 164: return (usbd_open_pipe_ival(iface, address, flags, pipe,
! 165: USBD_DEFAULT_INTERVAL));
! 166: }
! 167:
! 168: usbd_status
! 169: usbd_open_pipe_ival(usbd_interface_handle iface, u_int8_t address,
! 170: u_int8_t flags, usbd_pipe_handle *pipe, int ival)
! 171: {
! 172: usbd_pipe_handle p;
! 173: struct usbd_endpoint *ep;
! 174: usbd_status err;
! 175: int i;
! 176:
! 177: DPRINTFN(3,("usbd_open_pipe: iface=%p address=0x%x flags=0x%x\n",
! 178: iface, address, flags));
! 179:
! 180: for (i = 0; i < iface->idesc->bNumEndpoints; i++) {
! 181: ep = &iface->endpoints[i];
! 182: if (ep->edesc == NULL)
! 183: return (USBD_IOERROR);
! 184: if (ep->edesc->bEndpointAddress == address)
! 185: goto found;
! 186: }
! 187: return (USBD_BAD_ADDRESS);
! 188: found:
! 189: if ((flags & USBD_EXCLUSIVE_USE) && ep->refcnt != 0)
! 190: return (USBD_IN_USE);
! 191: err = usbd_setup_pipe(iface->device, iface, ep, ival, &p);
! 192: if (err)
! 193: return (err);
! 194: LIST_INSERT_HEAD(&iface->pipes, p, next);
! 195: *pipe = p;
! 196: return (USBD_NORMAL_COMPLETION);
! 197: }
! 198:
! 199: usbd_status
! 200: usbd_open_pipe_intr(usbd_interface_handle iface, u_int8_t address,
! 201: u_int8_t flags, usbd_pipe_handle *pipe, usbd_private_handle priv,
! 202: void *buffer, u_int32_t len, usbd_callback cb, int ival)
! 203: {
! 204: usbd_status err;
! 205: usbd_xfer_handle xfer;
! 206: usbd_pipe_handle ipipe;
! 207:
! 208: DPRINTFN(3,("usbd_open_pipe_intr: address=0x%x flags=0x%x len=%d\n",
! 209: address, flags, len));
! 210:
! 211: err = usbd_open_pipe_ival(iface, address, USBD_EXCLUSIVE_USE, &ipipe,
! 212: ival);
! 213: if (err)
! 214: return (err);
! 215: xfer = usbd_alloc_xfer(iface->device);
! 216: if (xfer == NULL) {
! 217: err = USBD_NOMEM;
! 218: goto bad1;
! 219: }
! 220: usbd_setup_xfer(xfer, ipipe, priv, buffer, len, flags,
! 221: USBD_NO_TIMEOUT, cb);
! 222: ipipe->intrxfer = xfer;
! 223: ipipe->repeat = 1;
! 224: err = usbd_transfer(xfer);
! 225: *pipe = ipipe;
! 226: if (err != USBD_IN_PROGRESS)
! 227: goto bad2;
! 228: return (USBD_NORMAL_COMPLETION);
! 229:
! 230: bad2:
! 231: ipipe->intrxfer = NULL;
! 232: ipipe->repeat = 0;
! 233: usbd_free_xfer(xfer);
! 234: bad1:
! 235: usbd_close_pipe(ipipe);
! 236: return (err);
! 237: }
! 238:
! 239: usbd_status
! 240: usbd_close_pipe(usbd_pipe_handle pipe)
! 241: {
! 242: #ifdef DIAGNOSTIC
! 243: if (pipe == NULL) {
! 244: printf("usbd_close_pipe: pipe==NULL\n");
! 245: return (USBD_NORMAL_COMPLETION);
! 246: }
! 247: #endif
! 248:
! 249: if (--pipe->refcnt != 0)
! 250: return (USBD_NORMAL_COMPLETION);
! 251: if (! SIMPLEQ_EMPTY(&pipe->queue))
! 252: return (USBD_PENDING_REQUESTS);
! 253: LIST_REMOVE(pipe, next);
! 254: pipe->endpoint->refcnt--;
! 255: pipe->methods->close(pipe);
! 256: if (pipe->intrxfer != NULL)
! 257: usbd_free_xfer(pipe->intrxfer);
! 258: free(pipe, M_USB);
! 259: return (USBD_NORMAL_COMPLETION);
! 260: }
! 261:
! 262: usbd_status
! 263: usbd_transfer(usbd_xfer_handle xfer)
! 264: {
! 265: usbd_pipe_handle pipe = xfer->pipe;
! 266: usb_dma_t *dmap = &xfer->dmabuf;
! 267: usbd_status err;
! 268: u_int size;
! 269: int s;
! 270:
! 271: DPRINTFN(5,("usbd_transfer: xfer=%p, flags=%d, pipe=%p, running=%d\n",
! 272: xfer, xfer->flags, pipe, pipe->running));
! 273: #ifdef USB_DEBUG
! 274: if (usbdebug > 5)
! 275: usbd_dump_queue(pipe);
! 276: #endif
! 277: xfer->done = 0;
! 278:
! 279: if (pipe->aborting)
! 280: return (USBD_CANCELLED);
! 281:
! 282: size = xfer->length;
! 283: /* If there is no buffer, allocate one. */
! 284: if (!(xfer->rqflags & URQ_DEV_DMABUF) && size != 0) {
! 285: struct usbd_bus *bus = pipe->device->bus;
! 286:
! 287: #ifdef DIAGNOSTIC
! 288: if (xfer->rqflags & URQ_AUTO_DMABUF)
! 289: printf("usbd_transfer: has old buffer!\n");
! 290: #endif
! 291: err = bus->methods->allocm(bus, dmap, size);
! 292: if (err)
! 293: return (err);
! 294: xfer->rqflags |= URQ_AUTO_DMABUF;
! 295: }
! 296:
! 297: /* Copy data if going out. */
! 298: if (!(xfer->flags & USBD_NO_COPY) && size != 0 &&
! 299: !usbd_xfer_isread(xfer))
! 300: memcpy(KERNADDR(dmap, 0), xfer->buffer, size);
! 301:
! 302: err = pipe->methods->transfer(xfer);
! 303:
! 304: if (err != USBD_IN_PROGRESS && err) {
! 305: /* The transfer has not been queued, so free buffer. */
! 306: if (xfer->rqflags & URQ_AUTO_DMABUF) {
! 307: struct usbd_bus *bus = pipe->device->bus;
! 308:
! 309: bus->methods->freem(bus, &xfer->dmabuf);
! 310: xfer->rqflags &= ~URQ_AUTO_DMABUF;
! 311: }
! 312: }
! 313:
! 314: if (!(xfer->flags & USBD_SYNCHRONOUS))
! 315: return (err);
! 316:
! 317: /* Sync transfer, wait for completion. */
! 318: if (err != USBD_IN_PROGRESS)
! 319: return (err);
! 320: s = splusb();
! 321: while (!xfer->done) {
! 322: if (pipe->device->bus->use_polling)
! 323: panic("usbd_transfer: not done");
! 324: tsleep(xfer, PRIBIO, "usbsyn", 0);
! 325: }
! 326: splx(s);
! 327: return (xfer->status);
! 328: }
! 329:
! 330: /* Like usbd_transfer(), but waits for completion. */
! 331: usbd_status
! 332: usbd_sync_transfer(usbd_xfer_handle xfer)
! 333: {
! 334: xfer->flags |= USBD_SYNCHRONOUS;
! 335: return (usbd_transfer(xfer));
! 336: }
! 337:
! 338: void *
! 339: usbd_alloc_buffer(usbd_xfer_handle xfer, u_int32_t size)
! 340: {
! 341: struct usbd_bus *bus = xfer->device->bus;
! 342: usbd_status err;
! 343:
! 344: #ifdef DIAGNOSTIC
! 345: if (xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF))
! 346: printf("usbd_alloc_buffer: xfer already has a buffer\n");
! 347: #endif
! 348: err = bus->methods->allocm(bus, &xfer->dmabuf, size);
! 349: if (err)
! 350: return (NULL);
! 351: xfer->rqflags |= URQ_DEV_DMABUF;
! 352: return (KERNADDR(&xfer->dmabuf, 0));
! 353: }
! 354:
! 355: void
! 356: usbd_free_buffer(usbd_xfer_handle xfer)
! 357: {
! 358: #ifdef DIAGNOSTIC
! 359: if (!(xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF))) {
! 360: printf("usbd_free_buffer: no buffer\n");
! 361: return;
! 362: }
! 363: #endif
! 364: xfer->rqflags &= ~(URQ_DEV_DMABUF | URQ_AUTO_DMABUF);
! 365: xfer->device->bus->methods->freem(xfer->device->bus, &xfer->dmabuf);
! 366: }
! 367:
! 368: void *
! 369: usbd_get_buffer(usbd_xfer_handle xfer)
! 370: {
! 371: if (!(xfer->rqflags & URQ_DEV_DMABUF))
! 372: return (0);
! 373: return (KERNADDR(&xfer->dmabuf, 0));
! 374: }
! 375:
! 376: usbd_xfer_handle
! 377: usbd_alloc_xfer(usbd_device_handle dev)
! 378: {
! 379: usbd_xfer_handle xfer;
! 380:
! 381: xfer = dev->bus->methods->allocx(dev->bus);
! 382: if (xfer == NULL)
! 383: return (NULL);
! 384: xfer->device = dev;
! 385: timeout_set(&xfer->timeout_handle, NULL, NULL);
! 386: DPRINTFN(5,("usbd_alloc_xfer() = %p\n", xfer));
! 387: return (xfer);
! 388: }
! 389:
! 390: usbd_status
! 391: usbd_free_xfer(usbd_xfer_handle xfer)
! 392: {
! 393: DPRINTFN(5,("usbd_free_xfer: %p\n", xfer));
! 394: if (xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF))
! 395: usbd_free_buffer(xfer);
! 396: xfer->device->bus->methods->freex(xfer->device->bus, xfer);
! 397: return (USBD_NORMAL_COMPLETION);
! 398: }
! 399:
! 400: void
! 401: usbd_setup_xfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
! 402: usbd_private_handle priv, void *buffer, u_int32_t length, u_int16_t flags,
! 403: u_int32_t timeout, usbd_callback callback)
! 404: {
! 405: xfer->pipe = pipe;
! 406: xfer->priv = priv;
! 407: xfer->buffer = buffer;
! 408: xfer->length = length;
! 409: xfer->actlen = 0;
! 410: xfer->flags = flags;
! 411: xfer->timeout = timeout;
! 412: xfer->status = USBD_NOT_STARTED;
! 413: xfer->callback = callback;
! 414: xfer->rqflags &= ~URQ_REQUEST;
! 415: xfer->nframes = 0;
! 416: }
! 417:
! 418: void
! 419: usbd_setup_default_xfer(usbd_xfer_handle xfer, usbd_device_handle dev,
! 420: usbd_private_handle priv, u_int32_t timeout, usb_device_request_t *req,
! 421: void *buffer, u_int32_t length, u_int16_t flags, usbd_callback callback)
! 422: {
! 423: xfer->pipe = dev->default_pipe;
! 424: xfer->priv = priv;
! 425: xfer->buffer = buffer;
! 426: xfer->length = length;
! 427: xfer->actlen = 0;
! 428: xfer->flags = flags;
! 429: xfer->timeout = timeout;
! 430: xfer->status = USBD_NOT_STARTED;
! 431: xfer->callback = callback;
! 432: xfer->request = *req;
! 433: xfer->rqflags |= URQ_REQUEST;
! 434: xfer->nframes = 0;
! 435: }
! 436:
! 437: void
! 438: usbd_setup_isoc_xfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
! 439: usbd_private_handle priv, u_int16_t *frlengths, u_int32_t nframes,
! 440: u_int16_t flags, usbd_callback callback)
! 441: {
! 442: xfer->pipe = pipe;
! 443: xfer->priv = priv;
! 444: xfer->buffer = 0;
! 445: xfer->length = 0;
! 446: xfer->actlen = 0;
! 447: xfer->flags = flags;
! 448: xfer->timeout = USBD_NO_TIMEOUT;
! 449: xfer->status = USBD_NOT_STARTED;
! 450: xfer->callback = callback;
! 451: xfer->rqflags &= ~URQ_REQUEST;
! 452: xfer->frlengths = frlengths;
! 453: xfer->nframes = nframes;
! 454: }
! 455:
! 456: void
! 457: usbd_get_xfer_status(usbd_xfer_handle xfer, usbd_private_handle *priv,
! 458: void **buffer, u_int32_t *count, usbd_status *status)
! 459: {
! 460: if (priv != NULL)
! 461: *priv = xfer->priv;
! 462: if (buffer != NULL)
! 463: *buffer = xfer->buffer;
! 464: if (count != NULL)
! 465: *count = xfer->actlen;
! 466: if (status != NULL)
! 467: *status = xfer->status;
! 468: }
! 469:
! 470: usb_config_descriptor_t *
! 471: usbd_get_config_descriptor(usbd_device_handle dev)
! 472: {
! 473: #ifdef DIAGNOSTIC
! 474: if (dev == NULL) {
! 475: printf("usbd_get_config_descriptor: dev == NULL\n");
! 476: return (NULL);
! 477: }
! 478: #endif
! 479: return (dev->cdesc);
! 480: }
! 481:
! 482: usb_interface_descriptor_t *
! 483: usbd_get_interface_descriptor(usbd_interface_handle iface)
! 484: {
! 485: #ifdef DIAGNOSTIC
! 486: if (iface == NULL) {
! 487: printf("usbd_get_interface_descriptor: dev == NULL\n");
! 488: return (NULL);
! 489: }
! 490: #endif
! 491: return (iface->idesc);
! 492: }
! 493:
! 494: usb_device_descriptor_t *
! 495: usbd_get_device_descriptor(usbd_device_handle dev)
! 496: {
! 497: return (&dev->ddesc);
! 498: }
! 499:
! 500: usb_endpoint_descriptor_t *
! 501: usbd_interface2endpoint_descriptor(usbd_interface_handle iface, u_int8_t index)
! 502: {
! 503: if (index >= iface->idesc->bNumEndpoints)
! 504: return (0);
! 505: return (iface->endpoints[index].edesc);
! 506: }
! 507:
! 508: usbd_status
! 509: usbd_abort_pipe(usbd_pipe_handle pipe)
! 510: {
! 511: usbd_status err;
! 512: int s;
! 513:
! 514: #ifdef DIAGNOSTIC
! 515: if (pipe == NULL) {
! 516: printf("usbd_abort_pipe: pipe==NULL\n");
! 517: return (USBD_NORMAL_COMPLETION);
! 518: }
! 519: #endif
! 520: s = splusb();
! 521: err = usbd_ar_pipe(pipe);
! 522: splx(s);
! 523: return (err);
! 524: }
! 525:
! 526: usbd_status
! 527: usbd_clear_endpoint_stall(usbd_pipe_handle pipe)
! 528: {
! 529: usbd_device_handle dev = pipe->device;
! 530: usb_device_request_t req;
! 531: usbd_status err;
! 532:
! 533: DPRINTFN(8, ("usbd_clear_endpoint_stall\n"));
! 534:
! 535: /*
! 536: * Clearing en endpoint stall resets the endpoint toggle, so
! 537: * do the same to the HC toggle.
! 538: */
! 539: pipe->methods->cleartoggle(pipe);
! 540:
! 541: req.bmRequestType = UT_WRITE_ENDPOINT;
! 542: req.bRequest = UR_CLEAR_FEATURE;
! 543: USETW(req.wValue, UF_ENDPOINT_HALT);
! 544: USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);
! 545: USETW(req.wLength, 0);
! 546: err = usbd_do_request(dev, &req, 0);
! 547: #if 0
! 548: XXX should we do this?
! 549: if (!err) {
! 550: pipe->state = USBD_PIPE_ACTIVE;
! 551: /* XXX activate pipe */
! 552: }
! 553: #endif
! 554: return (err);
! 555: }
! 556:
! 557: usbd_status
! 558: usbd_clear_endpoint_stall_async(usbd_pipe_handle pipe)
! 559: {
! 560: usbd_device_handle dev = pipe->device;
! 561: usb_device_request_t req;
! 562: usbd_status err;
! 563:
! 564: pipe->methods->cleartoggle(pipe);
! 565:
! 566: req.bmRequestType = UT_WRITE_ENDPOINT;
! 567: req.bRequest = UR_CLEAR_FEATURE;
! 568: USETW(req.wValue, UF_ENDPOINT_HALT);
! 569: USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);
! 570: USETW(req.wLength, 0);
! 571: err = usbd_do_request_async(dev, &req, 0);
! 572: return (err);
! 573: }
! 574:
! 575: void
! 576: usbd_clear_endpoint_toggle(usbd_pipe_handle pipe)
! 577: {
! 578: pipe->methods->cleartoggle(pipe);
! 579: }
! 580:
! 581: usbd_status
! 582: usbd_endpoint_count(usbd_interface_handle iface, u_int8_t *count)
! 583: {
! 584: #ifdef DIAGNOSTIC
! 585: if (iface == NULL || iface->idesc == NULL) {
! 586: printf("usbd_endpoint_count: NULL pointer\n");
! 587: return (USBD_INVAL);
! 588: }
! 589: #endif
! 590: *count = iface->idesc->bNumEndpoints;
! 591: return (USBD_NORMAL_COMPLETION);
! 592: }
! 593:
! 594: usbd_status
! 595: usbd_interface_count(usbd_device_handle dev, u_int8_t *count)
! 596: {
! 597: if (dev->cdesc == NULL)
! 598: return (USBD_NOT_CONFIGURED);
! 599: *count = dev->cdesc->bNumInterface;
! 600: return (USBD_NORMAL_COMPLETION);
! 601: }
! 602:
! 603: void
! 604: usbd_interface2device_handle(usbd_interface_handle iface,
! 605: usbd_device_handle *dev)
! 606: {
! 607: *dev = iface->device;
! 608: }
! 609:
! 610: usbd_status
! 611: usbd_device2interface_handle(usbd_device_handle dev, u_int8_t ifaceno,
! 612: usbd_interface_handle *iface)
! 613: {
! 614: if (dev->cdesc == NULL)
! 615: return (USBD_NOT_CONFIGURED);
! 616: if (ifaceno >= dev->cdesc->bNumInterface)
! 617: return (USBD_INVAL);
! 618: *iface = &dev->ifaces[ifaceno];
! 619: return (USBD_NORMAL_COMPLETION);
! 620: }
! 621:
! 622: usbd_device_handle
! 623: usbd_pipe2device_handle(usbd_pipe_handle pipe)
! 624: {
! 625: return (pipe->device);
! 626: }
! 627:
! 628: /* XXXX use altno */
! 629: usbd_status
! 630: usbd_set_interface(usbd_interface_handle iface, int altidx)
! 631: {
! 632: usb_device_request_t req;
! 633: usbd_status err;
! 634: void *endpoints;
! 635:
! 636: if (LIST_FIRST(&iface->pipes) != 0)
! 637: return (USBD_IN_USE);
! 638:
! 639: endpoints = iface->endpoints;
! 640: err = usbd_fill_iface_data(iface->device, iface->index, altidx);
! 641: if (err)
! 642: return (err);
! 643:
! 644: /* new setting works, we can free old endpoints */
! 645: if (endpoints != NULL)
! 646: free(endpoints, M_USB);
! 647:
! 648: #ifdef DIAGNOSTIC
! 649: if (iface->idesc == NULL) {
! 650: printf("usbd_set_interface: NULL pointer\n");
! 651: return (USBD_INVAL);
! 652: }
! 653: #endif
! 654:
! 655: req.bmRequestType = UT_WRITE_INTERFACE;
! 656: req.bRequest = UR_SET_INTERFACE;
! 657: USETW(req.wValue, iface->idesc->bAlternateSetting);
! 658: USETW(req.wIndex, iface->idesc->bInterfaceNumber);
! 659: USETW(req.wLength, 0);
! 660: return (usbd_do_request(iface->device, &req, 0));
! 661: }
! 662:
! 663: int
! 664: usbd_get_no_alts(usb_config_descriptor_t *cdesc, int ifaceno)
! 665: {
! 666: char *p = (char *)cdesc;
! 667: char *end = p + UGETW(cdesc->wTotalLength);
! 668: usb_interface_descriptor_t *d;
! 669: int n;
! 670:
! 671: for (n = 0; p < end; p += d->bLength) {
! 672: d = (usb_interface_descriptor_t *)p;
! 673: if (p + d->bLength <= end &&
! 674: d->bDescriptorType == UDESC_INTERFACE &&
! 675: d->bInterfaceNumber == ifaceno)
! 676: n++;
! 677: }
! 678: return (n);
! 679: }
! 680:
! 681: int
! 682: usbd_get_interface_altindex(usbd_interface_handle iface)
! 683: {
! 684: return (iface->altindex);
! 685: }
! 686:
! 687: usbd_status
! 688: usbd_get_interface(usbd_interface_handle iface, u_int8_t *aiface)
! 689: {
! 690: usb_device_request_t req;
! 691:
! 692: req.bmRequestType = UT_READ_INTERFACE;
! 693: req.bRequest = UR_GET_INTERFACE;
! 694: USETW(req.wValue, 0);
! 695: USETW(req.wIndex, iface->idesc->bInterfaceNumber);
! 696: USETW(req.wLength, 1);
! 697: return (usbd_do_request(iface->device, &req, aiface));
! 698: }
! 699:
! 700: /*** Internal routines ***/
! 701:
! 702: /* Dequeue all pipe operations, called at splusb(). */
! 703: usbd_status
! 704: usbd_ar_pipe(usbd_pipe_handle pipe)
! 705: {
! 706: usbd_xfer_handle xfer;
! 707:
! 708: SPLUSBCHECK;
! 709:
! 710: DPRINTFN(2,("usbd_ar_pipe: pipe=%p\n", pipe));
! 711: #ifdef USB_DEBUG
! 712: if (usbdebug > 5)
! 713: usbd_dump_queue(pipe);
! 714: #endif
! 715: pipe->repeat = 0;
! 716: pipe->aborting = 1;
! 717: while ((xfer = SIMPLEQ_FIRST(&pipe->queue)) != NULL) {
! 718: DPRINTFN(2,("usbd_ar_pipe: pipe=%p xfer=%p (methods=%p)\n",
! 719: pipe, xfer, pipe->methods));
! 720: /* Make the HC abort it (and invoke the callback). */
! 721: pipe->methods->abort(xfer);
! 722: /* XXX only for non-0 usbd_clear_endpoint_stall(pipe); */
! 723: }
! 724: pipe->aborting = 0;
! 725: return (USBD_NORMAL_COMPLETION);
! 726: }
! 727:
! 728: /* Called at splusb() */
! 729: void
! 730: usb_transfer_complete(usbd_xfer_handle xfer)
! 731: {
! 732: usbd_pipe_handle pipe = xfer->pipe;
! 733: usb_dma_t *dmap = &xfer->dmabuf;
! 734: int repeat = pipe->repeat;
! 735: int polling;
! 736:
! 737: SPLUSBCHECK;
! 738:
! 739: DPRINTFN(5, ("usb_transfer_complete: pipe=%p xfer=%p status=%d "
! 740: "actlen=%d\n", pipe, xfer, xfer->status, xfer->actlen));
! 741: #ifdef DIAGNOSTIC
! 742: if (xfer->busy_free != XFER_ONQU) {
! 743: printf("usb_transfer_complete: xfer=%p not busy 0x%08x\n",
! 744: xfer, xfer->busy_free);
! 745: return;
! 746: }
! 747: #endif
! 748:
! 749: #ifdef DIAGNOSTIC
! 750: if (pipe == NULL) {
! 751: printf("usbd_transfer_cb: pipe==0, xfer=%p\n", xfer);
! 752: return;
! 753: }
! 754: #endif
! 755: polling = pipe->device->bus->use_polling;
! 756: /* XXXX */
! 757: if (polling)
! 758: pipe->running = 0;
! 759:
! 760: if (!(xfer->flags & USBD_NO_COPY) && xfer->actlen != 0 &&
! 761: usbd_xfer_isread(xfer)) {
! 762: #ifdef DIAGNOSTIC
! 763: if (xfer->actlen > xfer->length) {
! 764: printf("usb_transfer_complete: actlen > len %d > %d\n",
! 765: xfer->actlen, xfer->length);
! 766: xfer->actlen = xfer->length;
! 767: }
! 768: #endif
! 769: memcpy(xfer->buffer, KERNADDR(dmap, 0), xfer->actlen);
! 770: }
! 771:
! 772: /* if we allocated the buffer in usbd_transfer() we free it here. */
! 773: if (xfer->rqflags & URQ_AUTO_DMABUF) {
! 774: if (!repeat) {
! 775: struct usbd_bus *bus = pipe->device->bus;
! 776: bus->methods->freem(bus, dmap);
! 777: xfer->rqflags &= ~URQ_AUTO_DMABUF;
! 778: }
! 779: }
! 780:
! 781: if (!repeat) {
! 782: /* Remove request from queue. */
! 783: #ifdef DIAGNOSTIC
! 784: if (xfer != SIMPLEQ_FIRST(&pipe->queue))
! 785: printf("usb_transfer_complete: bad dequeue %p != %p\n",
! 786: xfer, SIMPLEQ_FIRST(&pipe->queue));
! 787: xfer->busy_free = XFER_BUSY;
! 788: #endif
! 789: SIMPLEQ_REMOVE_HEAD(&pipe->queue, next);
! 790: }
! 791: DPRINTFN(5,("usb_transfer_complete: repeat=%d new head=%p\n", repeat,
! 792: SIMPLEQ_FIRST(&pipe->queue)));
! 793:
! 794: /* Count completed transfers. */
! 795: ++pipe->device->bus->stats.uds_requests
! 796: [pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE];
! 797:
! 798: xfer->done = 1;
! 799: if (!xfer->status && xfer->actlen < xfer->length &&
! 800: !(xfer->flags & USBD_SHORT_XFER_OK)) {
! 801: DPRINTFN(-1,("usbd_transfer_cb: short transfer %d<%d\n",
! 802: xfer->actlen, xfer->length));
! 803: xfer->status = USBD_SHORT_XFER;
! 804: }
! 805:
! 806: if (xfer->callback)
! 807: xfer->callback(xfer, xfer->priv, xfer->status);
! 808:
! 809: #ifdef DIAGNOSTIC
! 810: if (pipe->methods->done != NULL)
! 811: pipe->methods->done(xfer);
! 812: else
! 813: printf("usb_transfer_complete: pipe->methods->done == NULL\n");
! 814: #else
! 815: pipe->methods->done(xfer);
! 816: #endif
! 817:
! 818: if ((xfer->flags & USBD_SYNCHRONOUS) && !polling)
! 819: wakeup(xfer);
! 820:
! 821: if (!repeat) {
! 822: /* XXX should we stop the queue on all errors? */
! 823: if ((xfer->status == USBD_CANCELLED ||
! 824: xfer->status == USBD_TIMEOUT) &&
! 825: pipe->iface != NULL) /* not control pipe */
! 826: pipe->running = 0;
! 827: else
! 828: usbd_start_next(pipe);
! 829: }
! 830: }
! 831:
! 832: usbd_status
! 833: usb_insert_transfer(usbd_xfer_handle xfer)
! 834: {
! 835: usbd_pipe_handle pipe = xfer->pipe;
! 836: usbd_status err;
! 837: int s;
! 838:
! 839: DPRINTFN(5,("usb_insert_transfer: pipe=%p running=%d timeout=%d\n",
! 840: pipe, pipe->running, xfer->timeout));
! 841: #ifdef DIAGNOSTIC
! 842: if (xfer->busy_free != XFER_BUSY) {
! 843: printf("usb_insert_transfer: xfer=%p not busy 0x%08x\n", xfer,
! 844: xfer->busy_free);
! 845: return (USBD_INVAL);
! 846: }
! 847: xfer->busy_free = XFER_ONQU;
! 848: #endif
! 849: s = splusb();
! 850: SIMPLEQ_INSERT_TAIL(&pipe->queue, xfer, next);
! 851: if (pipe->running)
! 852: err = USBD_IN_PROGRESS;
! 853: else {
! 854: pipe->running = 1;
! 855: err = USBD_NORMAL_COMPLETION;
! 856: }
! 857: splx(s);
! 858: return (err);
! 859: }
! 860:
! 861: /* Called at splusb() */
! 862: void
! 863: usbd_start_next(usbd_pipe_handle pipe)
! 864: {
! 865: usbd_xfer_handle xfer;
! 866: usbd_status err;
! 867:
! 868: SPLUSBCHECK;
! 869:
! 870: #ifdef DIAGNOSTIC
! 871: if (pipe == NULL) {
! 872: printf("usbd_start_next: pipe == NULL\n");
! 873: return;
! 874: }
! 875: if (pipe->methods == NULL || pipe->methods->start == NULL) {
! 876: printf("usbd_start_next: pipe=%p no start method\n", pipe);
! 877: return;
! 878: }
! 879: #endif
! 880:
! 881: /* Get next request in queue. */
! 882: xfer = SIMPLEQ_FIRST(&pipe->queue);
! 883: DPRINTFN(5, ("usbd_start_next: pipe=%p, xfer=%p\n", pipe, xfer));
! 884: if (xfer == NULL) {
! 885: pipe->running = 0;
! 886: } else {
! 887: err = pipe->methods->start(xfer);
! 888: if (err != USBD_IN_PROGRESS) {
! 889: printf("usbd_start_next: error=%d\n", err);
! 890: pipe->running = 0;
! 891: /* XXX do what? */
! 892: }
! 893: }
! 894: }
! 895:
! 896: usbd_status
! 897: usbd_do_request(usbd_device_handle dev, usb_device_request_t *req, void *data)
! 898: {
! 899: return (usbd_do_request_flags(dev, req, data, 0, 0,
! 900: USBD_DEFAULT_TIMEOUT));
! 901: }
! 902:
! 903: usbd_status
! 904: usbd_do_request_flags(usbd_device_handle dev, usb_device_request_t *req,
! 905: void *data, u_int16_t flags, int *actlen, u_int32_t timo)
! 906: {
! 907: return (usbd_do_request_flags_pipe(dev, dev->default_pipe, req, data,
! 908: flags, actlen, timo));
! 909: }
! 910:
! 911: usbd_status
! 912: usbd_do_request_flags_pipe(usbd_device_handle dev, usbd_pipe_handle pipe,
! 913: usb_device_request_t *req, void *data, u_int16_t flags, int *actlen,
! 914: u_int32_t timeout)
! 915: {
! 916: usbd_xfer_handle xfer;
! 917: usbd_status err;
! 918:
! 919: #ifdef DIAGNOSTIC
! 920: if (dev->bus->intr_context) {
! 921: printf("usbd_do_request: not in process context\n");
! 922: return (USBD_INVAL);
! 923: }
! 924: #endif
! 925:
! 926: xfer = usbd_alloc_xfer(dev);
! 927: if (xfer == NULL)
! 928: return (USBD_NOMEM);
! 929: usbd_setup_default_xfer(xfer, dev, 0, timeout, req, data,
! 930: UGETW(req->wLength), flags, 0);
! 931: xfer->pipe = pipe;
! 932: err = usbd_sync_transfer(xfer);
! 933: #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
! 934: if (xfer->actlen > xfer->length)
! 935: DPRINTF(("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
! 936: "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
! 937: dev->address, xfer->request.bmRequestType,
! 938: xfer->request.bRequest, UGETW(xfer->request.wValue),
! 939: UGETW(xfer->request.wIndex), UGETW(xfer->request.wLength),
! 940: xfer->length, xfer->actlen));
! 941: #endif
! 942: if (actlen != NULL)
! 943: *actlen = xfer->actlen;
! 944: if (err == USBD_STALLED) {
! 945: /*
! 946: * The control endpoint has stalled. Control endpoints
! 947: * should not halt, but some may do so anyway so clear
! 948: * any halt condition.
! 949: */
! 950: usb_device_request_t treq;
! 951: usb_status_t status;
! 952: u_int16_t s;
! 953: usbd_status nerr;
! 954:
! 955: treq.bmRequestType = UT_READ_ENDPOINT;
! 956: treq.bRequest = UR_GET_STATUS;
! 957: USETW(treq.wValue, 0);
! 958: USETW(treq.wIndex, 0);
! 959: USETW(treq.wLength, sizeof(usb_status_t));
! 960: usbd_setup_default_xfer(xfer, dev, 0, USBD_DEFAULT_TIMEOUT,
! 961: &treq, &status,sizeof(usb_status_t), 0, 0);
! 962: nerr = usbd_sync_transfer(xfer);
! 963: if (nerr)
! 964: goto bad;
! 965: s = UGETW(status.wStatus);
! 966: DPRINTF(("usbd_do_request: status = 0x%04x\n", s));
! 967: if (!(s & UES_HALT))
! 968: goto bad;
! 969: treq.bmRequestType = UT_WRITE_ENDPOINT;
! 970: treq.bRequest = UR_CLEAR_FEATURE;
! 971: USETW(treq.wValue, UF_ENDPOINT_HALT);
! 972: USETW(treq.wIndex, 0);
! 973: USETW(treq.wLength, 0);
! 974: usbd_setup_default_xfer(xfer, dev, 0, USBD_DEFAULT_TIMEOUT,
! 975: &treq, &status, 0, 0, 0);
! 976: nerr = usbd_sync_transfer(xfer);
! 977: if (nerr)
! 978: goto bad;
! 979: }
! 980:
! 981: bad:
! 982: usbd_free_xfer(xfer);
! 983: return (err);
! 984: }
! 985:
! 986: void
! 987: usbd_do_request_async_cb(usbd_xfer_handle xfer, usbd_private_handle priv,
! 988: usbd_status status)
! 989: {
! 990: #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
! 991: if (xfer->actlen > xfer->length)
! 992: DPRINTF(("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
! 993: "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
! 994: xfer->pipe->device->address, xfer->request.bmRequestType,
! 995: xfer->request.bRequest, UGETW(xfer->request.wValue),
! 996: UGETW(xfer->request.wIndex), UGETW(xfer->request.wLength),
! 997: xfer->length, xfer->actlen));
! 998: #endif
! 999: usbd_free_xfer(xfer);
! 1000: }
! 1001:
! 1002: /*
! 1003: * Execute a request without waiting for completion.
! 1004: * Can be used from interrupt context.
! 1005: */
! 1006: usbd_status
! 1007: usbd_do_request_async(usbd_device_handle dev, usb_device_request_t *req,
! 1008: void *data)
! 1009: {
! 1010: usbd_xfer_handle xfer;
! 1011: usbd_status err;
! 1012:
! 1013: xfer = usbd_alloc_xfer(dev);
! 1014: if (xfer == NULL)
! 1015: return (USBD_NOMEM);
! 1016: usbd_setup_default_xfer(xfer, dev, 0, USBD_DEFAULT_TIMEOUT, req,
! 1017: data, UGETW(req->wLength), 0, usbd_do_request_async_cb);
! 1018: err = usbd_transfer(xfer);
! 1019: if (err != USBD_IN_PROGRESS) {
! 1020: usbd_free_xfer(xfer);
! 1021: return (err);
! 1022: }
! 1023: return (USBD_NORMAL_COMPLETION);
! 1024: }
! 1025:
! 1026: const struct usbd_quirks *
! 1027: usbd_get_quirks(usbd_device_handle dev)
! 1028: {
! 1029: #ifdef DIAGNOSTIC
! 1030: if (dev == NULL) {
! 1031: printf("usbd_get_quirks: dev == NULL\n");
! 1032: return 0;
! 1033: }
! 1034: #endif
! 1035: return (dev->quirks);
! 1036: }
! 1037:
! 1038: /* XXX do periodic free() of free list */
! 1039:
! 1040: /*
! 1041: * Called from keyboard driver when in polling mode.
! 1042: */
! 1043: void
! 1044: usbd_dopoll(usbd_interface_handle iface)
! 1045: {
! 1046: iface->device->bus->methods->do_poll(iface->device->bus);
! 1047: }
! 1048:
! 1049: void
! 1050: usbd_set_polling(usbd_device_handle dev, int on)
! 1051: {
! 1052: if (on)
! 1053: dev->bus->use_polling++;
! 1054: else
! 1055: dev->bus->use_polling--;
! 1056: /* When polling we need to make sure there is nothing pending to do. */
! 1057: if (dev->bus->use_polling)
! 1058: dev->bus->methods->soft_intr(dev->bus);
! 1059: }
! 1060:
! 1061: usb_endpoint_descriptor_t *
! 1062: usbd_get_endpoint_descriptor(usbd_interface_handle iface, u_int8_t address)
! 1063: {
! 1064: struct usbd_endpoint *ep;
! 1065: int i;
! 1066:
! 1067: for (i = 0; i < iface->idesc->bNumEndpoints; i++) {
! 1068: ep = &iface->endpoints[i];
! 1069: if (ep->edesc->bEndpointAddress == address)
! 1070: return (iface->endpoints[i].edesc);
! 1071: }
! 1072: return (0);
! 1073: }
! 1074:
! 1075: /*
! 1076: * usbd_ratecheck() can limit the number of error messages that occurs.
! 1077: * When a device is unplugged it may take up to 0.25s for the hub driver
! 1078: * to notice it. If the driver continuosly tries to do I/O operations
! 1079: * this can generate a large number of messages.
! 1080: */
! 1081: int
! 1082: usbd_ratecheck(struct timeval *last)
! 1083: {
! 1084: static struct timeval errinterval = { 0, 250000 }; /* 0.25 s*/
! 1085:
! 1086: return (ratecheck(last, &errinterval));
! 1087: }
! 1088:
! 1089: /*
! 1090: * Search for a vendor/product pair in an array. The item size is
! 1091: * given as an argument.
! 1092: */
! 1093: const struct usb_devno *
! 1094: usb_match_device(const struct usb_devno *tbl, u_int nentries, u_int sz,
! 1095: u_int16_t vendor, u_int16_t product)
! 1096: {
! 1097: while (nentries-- > 0) {
! 1098: u_int16_t tproduct = tbl->ud_product;
! 1099: if (tbl->ud_vendor == vendor &&
! 1100: (tproduct == product || tproduct == USB_PRODUCT_ANY))
! 1101: return (tbl);
! 1102: tbl = (const struct usb_devno *)((const char *)tbl + sz);
! 1103: }
! 1104: return (NULL);
! 1105: }
! 1106:
! 1107: void
! 1108: usb_desc_iter_init(usbd_device_handle dev, usbd_desc_iter_t *iter)
! 1109: {
! 1110: const usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev);
! 1111:
! 1112: iter->cur = (const uByte *)cd;
! 1113: iter->end = (const uByte *)cd + UGETW(cd->wTotalLength);
! 1114: }
! 1115:
! 1116: const usb_descriptor_t *
! 1117: usb_desc_iter_next(usbd_desc_iter_t *iter)
! 1118: {
! 1119: const usb_descriptor_t *desc;
! 1120:
! 1121: if (iter->cur + sizeof(usb_descriptor_t) >= iter->end) {
! 1122: if (iter->cur != iter->end)
! 1123: printf("usb_desc_iter_next: bad descriptor\n");
! 1124: return NULL;
! 1125: }
! 1126: desc = (const usb_descriptor_t *)iter->cur;
! 1127: if (desc->bLength == 0) {
! 1128: printf("usb_desc_iter_next: descriptor length = 0\n");
! 1129: return NULL;
! 1130: }
! 1131: iter->cur += desc->bLength;
! 1132: if (iter->cur > iter->end) {
! 1133: printf("usb_desc_iter_next: descriptor length too large\n");
! 1134: return NULL;
! 1135: }
! 1136: return desc;
! 1137: }
CVSweb