Annotation of sys/dev/usb/usb_subr.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: usb_subr.c,v 1.57 2007/07/21 16:28:50 deraadt Exp $ */
! 2: /* $NetBSD: usb_subr.c,v 1.103 2003/01/10 11:19:13 augustss Exp $ */
! 3: /* $FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.18 1999/11/17 22:33:47 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/malloc.h>
! 46: #include <sys/device.h>
! 47: #include <sys/selinfo.h>
! 48: #include <sys/proc.h>
! 49:
! 50: #include <machine/bus.h>
! 51:
! 52: #include <dev/usb/usb.h>
! 53:
! 54: #include <dev/usb/usbdi.h>
! 55: #include <dev/usb/usbdi_util.h>
! 56: #include <dev/usb/usbdivar.h>
! 57: #include <dev/usb/usbdevs.h>
! 58: #include <dev/usb/usb_quirks.h>
! 59:
! 60: #ifdef USB_DEBUG
! 61: #define DPRINTF(x) do { if (usbdebug) printf x; } while (0)
! 62: #define DPRINTFN(n,x) do { if (usbdebug>(n)) printf x; } while (0)
! 63: extern int usbdebug;
! 64: #else
! 65: #define DPRINTF(x)
! 66: #define DPRINTFN(n,x)
! 67: #endif
! 68:
! 69: usbd_status usbd_set_config(usbd_device_handle, int);
! 70: void usbd_devinfo(usbd_device_handle, int, char *, size_t);
! 71: void usbd_devinfo_vp(usbd_device_handle, char *, char *,
! 72: int);
! 73: char *usbd_get_string(usbd_device_handle, int, char *);
! 74: int usbd_getnewaddr(usbd_bus_handle);
! 75: int usbd_print(void *, const char *);
! 76: int usbd_submatch(struct device *, void *, void *);
! 77: void usbd_free_iface_data(usbd_device_handle, int);
! 78: void usbd_kill_pipe(usbd_pipe_handle);
! 79: usbd_status usbd_probe_and_attach(struct device *,
! 80: usbd_device_handle, int, int);
! 81:
! 82: u_int32_t usb_cookie_no = 0;
! 83:
! 84: #ifdef USBVERBOSE
! 85: #include <dev/usb/usbdevs_data.h>
! 86: #endif /* USBVERBOSE */
! 87:
! 88: const char * const usbd_error_strs[] = {
! 89: "NORMAL_COMPLETION",
! 90: "IN_PROGRESS",
! 91: "PENDING_REQUESTS",
! 92: "NOT_STARTED",
! 93: "INVAL",
! 94: "NOMEM",
! 95: "CANCELLED",
! 96: "BAD_ADDRESS",
! 97: "IN_USE",
! 98: "NO_ADDR",
! 99: "SET_ADDR_FAILED",
! 100: "NO_POWER",
! 101: "TOO_DEEP",
! 102: "IOERROR",
! 103: "NOT_CONFIGURED",
! 104: "TIMEOUT",
! 105: "SHORT_XFER",
! 106: "STALLED",
! 107: "INTERRUPTED",
! 108: "XXX",
! 109: };
! 110:
! 111: const char *
! 112: usbd_errstr(usbd_status err)
! 113: {
! 114: static char buffer[5];
! 115:
! 116: if (err < USBD_ERROR_MAX)
! 117: return (usbd_error_strs[err]);
! 118: else {
! 119: snprintf(buffer, sizeof(buffer), "%d", err);
! 120: return (buffer);
! 121: }
! 122: }
! 123:
! 124: usbd_status
! 125: usbd_get_string_desc(usbd_device_handle dev, int sindex, int langid,
! 126: usb_string_descriptor_t *sdesc, int *sizep)
! 127: {
! 128: usb_device_request_t req;
! 129: usbd_status err;
! 130: int actlen;
! 131:
! 132: req.bmRequestType = UT_READ_DEVICE;
! 133: req.bRequest = UR_GET_DESCRIPTOR;
! 134: USETW2(req.wValue, UDESC_STRING, sindex);
! 135: USETW(req.wIndex, langid);
! 136: USETW(req.wLength, 1); /* only size byte first */
! 137: err = usbd_do_request_flags(dev, &req, sdesc, USBD_SHORT_XFER_OK,
! 138: &actlen, USBD_DEFAULT_TIMEOUT);
! 139: if (err)
! 140: return (err);
! 141:
! 142: if (actlen < 1)
! 143: return (USBD_SHORT_XFER);
! 144:
! 145: USETW(req.wLength, sdesc->bLength); /* the whole string */
! 146: err = usbd_do_request_flags(dev, &req, sdesc, USBD_SHORT_XFER_OK,
! 147: &actlen, USBD_DEFAULT_TIMEOUT);
! 148: if (err)
! 149: return (err);
! 150:
! 151: if (actlen != sdesc->bLength) {
! 152: DPRINTFN(-1, ("usbd_get_string_desc: expected %d, got %d\n",
! 153: sdesc->bLength, actlen));
! 154: }
! 155:
! 156: *sizep = actlen;
! 157: return (USBD_NORMAL_COMPLETION);
! 158: }
! 159:
! 160: char *
! 161: usbd_get_string(usbd_device_handle dev, int si, char *buf)
! 162: {
! 163: int swap = dev->quirks->uq_flags & UQ_SWAP_UNICODE;
! 164: usb_string_descriptor_t us;
! 165: char *s;
! 166: int i, n;
! 167: u_int16_t c;
! 168: usbd_status err;
! 169: int size;
! 170:
! 171: if (si == 0)
! 172: return (0);
! 173: if (dev->quirks->uq_flags & UQ_NO_STRINGS)
! 174: return (0);
! 175: if (dev->langid == USBD_NOLANG) {
! 176: /* Set up default language */
! 177: err = usbd_get_string_desc(dev, USB_LANGUAGE_TABLE, 0, &us,
! 178: &size);
! 179: if (err || size < 4)
! 180: dev->langid = 0; /* Well, just pick English then */
! 181: else {
! 182: /* Pick the first language as the default. */
! 183: dev->langid = UGETW(us.bString[0]);
! 184: }
! 185: }
! 186: err = usbd_get_string_desc(dev, si, dev->langid, &us, &size);
! 187: if (err)
! 188: return (0);
! 189: s = buf;
! 190: n = size / 2 - 1;
! 191: for (i = 0; i < n; i++) {
! 192: c = UGETW(us.bString[i]);
! 193: /* Convert from Unicode, handle buggy strings. */
! 194: if ((c & 0xff00) == 0)
! 195: *s++ = c;
! 196: else if ((c & 0x00ff) == 0 && swap)
! 197: *s++ = c >> 8;
! 198: else
! 199: *s++ = '?';
! 200: }
! 201: *s++ = 0;
! 202: return (buf);
! 203: }
! 204:
! 205: static void
! 206: usbd_trim_spaces(char *p)
! 207: {
! 208: char *q, *e;
! 209:
! 210: if (p == NULL)
! 211: return;
! 212: q = e = p;
! 213: while (*q == ' ') /* skip leading spaces */
! 214: q++;
! 215: while ((*p = *q++)) /* copy string */
! 216: if (*p++ != ' ') /* remember last non-space */
! 217: e = p;
! 218: *e = 0; /* kill trailing spaces */
! 219: }
! 220:
! 221: void
! 222: usbd_devinfo_vp(usbd_device_handle dev, char *v, char *p, int usedev)
! 223: {
! 224: usb_device_descriptor_t *udd = &dev->ddesc;
! 225: char *vendor = 0, *product = 0;
! 226: #ifdef USBVERBOSE
! 227: const struct usb_known_vendor *ukv;
! 228: const struct usb_known_product *ukp;
! 229: #endif
! 230:
! 231: if (dev == NULL) {
! 232: v[0] = p[0] = '\0';
! 233: return;
! 234: }
! 235:
! 236: if (usedev) {
! 237: vendor = usbd_get_string(dev, udd->iManufacturer, v);
! 238: usbd_trim_spaces(vendor);
! 239: product = usbd_get_string(dev, udd->iProduct, p);
! 240: usbd_trim_spaces(product);
! 241: } else {
! 242: vendor = NULL;
! 243: product = NULL;
! 244: }
! 245: #ifdef USBVERBOSE
! 246: if (vendor == NULL || product == NULL) {
! 247: for(ukv = usb_known_vendors;
! 248: ukv->vendorname != NULL;
! 249: ukv++) {
! 250: if (ukv->vendor == UGETW(udd->idVendor)) {
! 251: vendor = ukv->vendorname;
! 252: break;
! 253: }
! 254: }
! 255: if (vendor != NULL) {
! 256: for(ukp = usb_known_products;
! 257: ukp->productname != NULL;
! 258: ukp++) {
! 259: if (ukp->vendor == UGETW(udd->idVendor) &&
! 260: (ukp->product == UGETW(udd->idProduct))) {
! 261: product = ukp->productname;
! 262: break;
! 263: }
! 264: }
! 265: }
! 266: }
! 267: #endif
! 268: if (vendor != NULL && *vendor)
! 269: strlcpy(v, vendor, USB_MAX_STRING_LEN); /* XXX */
! 270: else
! 271: snprintf(v, USB_MAX_STRING_LEN, "vendor 0x%04x", /* XXX */
! 272: UGETW(udd->idVendor));
! 273: if (product != NULL && *product)
! 274: strlcpy(p, product, USB_MAX_STRING_LEN); /* XXX */
! 275: else
! 276: snprintf(p, USB_MAX_STRING_LEN, "product 0x%04x", /* XXX */
! 277: UGETW(udd->idProduct));
! 278: }
! 279:
! 280: int
! 281: usbd_printBCD(char *cp, size_t len, int bcd)
! 282: {
! 283: int l;
! 284:
! 285: l = snprintf(cp, len, "%x.%02x", bcd >> 8, bcd & 0xff);
! 286: if (l == -1 || len == 0)
! 287: return (0);
! 288: if (l >= len)
! 289: return len - 1;
! 290: return (l);
! 291: }
! 292:
! 293: void
! 294: usbd_devinfo(usbd_device_handle dev, int showclass, char *base, size_t len)
! 295: {
! 296: usb_device_descriptor_t *udd = &dev->ddesc;
! 297: char vendor[USB_MAX_STRING_LEN];
! 298: char product[USB_MAX_STRING_LEN];
! 299: char *cp = base;
! 300: int bcdDevice, bcdUSB;
! 301:
! 302: usbd_devinfo_vp(dev, vendor, product, 1);
! 303: snprintf(cp, len, "%s %s", vendor, product);
! 304: cp += strlen(cp);
! 305: if (showclass) {
! 306: snprintf(cp, base + len - cp, ", class %d/%d",
! 307: udd->bDeviceClass, udd->bDeviceSubClass);
! 308: cp += strlen(cp);
! 309: }
! 310: bcdUSB = UGETW(udd->bcdUSB);
! 311: bcdDevice = UGETW(udd->bcdDevice);
! 312: snprintf(cp, base + len - cp, ", rev ");
! 313: cp += strlen(cp);
! 314: usbd_printBCD(cp, base + len - cp, bcdUSB);
! 315: cp += strlen(cp);
! 316: snprintf(cp, base + len - cp, "/");
! 317: cp += strlen(cp);
! 318: usbd_printBCD(cp, base + len - cp, bcdDevice);
! 319: cp += strlen(cp);
! 320: snprintf(cp, base + len - cp, ", addr %d", dev->address);
! 321: }
! 322:
! 323: char *
! 324: usbd_devinfo_alloc(usbd_device_handle dev, int showclass)
! 325: {
! 326: char *devinfop;
! 327:
! 328: devinfop = malloc(DEVINFOSIZE, M_TEMP, M_WAITOK);
! 329: usbd_devinfo(dev, showclass, devinfop, DEVINFOSIZE);
! 330: return devinfop;
! 331: }
! 332:
! 333: void
! 334: usbd_devinfo_free(char *devinfop)
! 335: {
! 336: free(devinfop, M_TEMP);
! 337: }
! 338:
! 339: /* Delay for a certain number of ms */
! 340: void
! 341: usb_delay_ms(usbd_bus_handle bus, u_int ms)
! 342: {
! 343: /* Wait at least two clock ticks so we know the time has passed. */
! 344: if (bus->use_polling || cold)
! 345: delay((ms+1) * 1000);
! 346: else
! 347: tsleep(&ms, PRIBIO, "usbdly", (ms*hz+999)/1000 + 1);
! 348: }
! 349:
! 350: /* Delay given a device handle. */
! 351: void
! 352: usbd_delay_ms(usbd_device_handle dev, u_int ms)
! 353: {
! 354: usb_delay_ms(dev->bus, ms);
! 355: }
! 356:
! 357: usbd_status
! 358: usbd_reset_port(usbd_device_handle dev, int port, usb_port_status_t *ps)
! 359: {
! 360: usb_device_request_t req;
! 361: usbd_status err;
! 362: int n;
! 363:
! 364: req.bmRequestType = UT_WRITE_CLASS_OTHER;
! 365: req.bRequest = UR_SET_FEATURE;
! 366: USETW(req.wValue, UHF_PORT_RESET);
! 367: USETW(req.wIndex, port);
! 368: USETW(req.wLength, 0);
! 369: err = usbd_do_request(dev, &req, 0);
! 370: DPRINTFN(1,("usbd_reset_port: port %d reset done, error=%s\n",
! 371: port, usbd_errstr(err)));
! 372: if (err)
! 373: return (err);
! 374: n = 10;
! 375: do {
! 376: /* Wait for device to recover from reset. */
! 377: usbd_delay_ms(dev, USB_PORT_RESET_DELAY);
! 378: err = usbd_get_port_status(dev, port, ps);
! 379: if (err) {
! 380: DPRINTF(("usbd_reset_port: get status failed %d\n",
! 381: err));
! 382: return (err);
! 383: }
! 384: /* If the device disappeared, just give up. */
! 385: if (!(UGETW(ps->wPortStatus) & UPS_CURRENT_CONNECT_STATUS))
! 386: return (USBD_NORMAL_COMPLETION);
! 387: } while ((UGETW(ps->wPortChange) & UPS_C_PORT_RESET) == 0 && --n > 0);
! 388: if (n == 0)
! 389: return (USBD_TIMEOUT);
! 390: err = usbd_clear_port_feature(dev, port, UHF_C_PORT_RESET);
! 391: #ifdef USB_DEBUG
! 392: if (err)
! 393: DPRINTF(("usbd_reset_port: clear port feature failed %d\n",
! 394: err));
! 395: #endif
! 396:
! 397: /* Wait for the device to recover from reset. */
! 398: usbd_delay_ms(dev, USB_PORT_RESET_RECOVERY);
! 399: return (err);
! 400: }
! 401:
! 402: usb_interface_descriptor_t *
! 403: usbd_find_idesc(usb_config_descriptor_t *cd, int ifaceidx, int altidx)
! 404: {
! 405: char *p = (char *)cd;
! 406: char *end = p + UGETW(cd->wTotalLength);
! 407: usb_interface_descriptor_t *d;
! 408: int curidx, lastidx, curaidx = 0;
! 409:
! 410: for (curidx = lastidx = -1; p < end; ) {
! 411: d = (usb_interface_descriptor_t *)p;
! 412: DPRINTFN(4,("usbd_find_idesc: idx=%d(%d) altidx=%d(%d) len=%d "
! 413: "type=%d\n",
! 414: ifaceidx, curidx, altidx, curaidx,
! 415: d->bLength, d->bDescriptorType));
! 416: if (d->bLength == 0) /* bad descriptor */
! 417: break;
! 418: p += d->bLength;
! 419: if (p <= end && d->bDescriptorType == UDESC_INTERFACE) {
! 420: if (d->bInterfaceNumber != lastidx) {
! 421: lastidx = d->bInterfaceNumber;
! 422: curidx++;
! 423: curaidx = 0;
! 424: } else
! 425: curaidx++;
! 426: if (ifaceidx == curidx && altidx == curaidx)
! 427: return (d);
! 428: }
! 429: }
! 430: return (NULL);
! 431: }
! 432:
! 433: usb_endpoint_descriptor_t *
! 434: usbd_find_edesc(usb_config_descriptor_t *cd, int ifaceidx, int altidx,
! 435: int endptidx)
! 436: {
! 437: char *p = (char *)cd;
! 438: char *end = p + UGETW(cd->wTotalLength);
! 439: usb_interface_descriptor_t *d;
! 440: usb_endpoint_descriptor_t *e;
! 441: int curidx;
! 442:
! 443: d = usbd_find_idesc(cd, ifaceidx, altidx);
! 444: if (d == NULL)
! 445: return (NULL);
! 446: if (endptidx >= d->bNumEndpoints) /* quick exit */
! 447: return (NULL);
! 448:
! 449: curidx = -1;
! 450: for (p = (char *)d + d->bLength; p < end; ) {
! 451: e = (usb_endpoint_descriptor_t *)p;
! 452: if (e->bLength == 0) /* bad descriptor */
! 453: break;
! 454: p += e->bLength;
! 455: if (p <= end && e->bDescriptorType == UDESC_INTERFACE)
! 456: return (NULL);
! 457: if (p <= end && e->bDescriptorType == UDESC_ENDPOINT) {
! 458: curidx++;
! 459: if (curidx == endptidx)
! 460: return (e);
! 461: }
! 462: }
! 463: return (NULL);
! 464: }
! 465:
! 466: usbd_status
! 467: usbd_fill_iface_data(usbd_device_handle dev, int ifaceidx, int altidx)
! 468: {
! 469: usbd_interface_handle ifc = &dev->ifaces[ifaceidx];
! 470: usb_interface_descriptor_t *idesc;
! 471: char *p, *end;
! 472: int endpt, nendpt;
! 473:
! 474: DPRINTFN(4,("usbd_fill_iface_data: ifaceidx=%d altidx=%d\n",
! 475: ifaceidx, altidx));
! 476: idesc = usbd_find_idesc(dev->cdesc, ifaceidx, altidx);
! 477: if (idesc == NULL)
! 478: return (USBD_INVAL);
! 479: ifc->device = dev;
! 480: ifc->idesc = idesc;
! 481: ifc->index = ifaceidx;
! 482: ifc->altindex = altidx;
! 483: nendpt = ifc->idesc->bNumEndpoints;
! 484: DPRINTFN(4,("usbd_fill_iface_data: found idesc nendpt=%d\n", nendpt));
! 485: if (nendpt != 0) {
! 486: ifc->endpoints = malloc(nendpt * sizeof(struct usbd_endpoint),
! 487: M_USB, M_NOWAIT);
! 488: if (ifc->endpoints == NULL)
! 489: return (USBD_NOMEM);
! 490: } else
! 491: ifc->endpoints = NULL;
! 492: ifc->priv = NULL;
! 493: p = (char *)ifc->idesc + ifc->idesc->bLength;
! 494: end = (char *)dev->cdesc + UGETW(dev->cdesc->wTotalLength);
! 495: #define ed ((usb_endpoint_descriptor_t *)p)
! 496: for (endpt = 0; endpt < nendpt; endpt++) {
! 497: DPRINTFN(10,("usbd_fill_iface_data: endpt=%d\n", endpt));
! 498: for (; p < end; p += ed->bLength) {
! 499: DPRINTFN(10,("usbd_fill_iface_data: p=%p end=%p "
! 500: "len=%d type=%d\n", p, end, ed->bLength,
! 501: ed->bDescriptorType));
! 502: if (p + ed->bLength <= end && ed->bLength != 0 &&
! 503: ed->bDescriptorType == UDESC_ENDPOINT)
! 504: goto found;
! 505: if (ed->bLength == 0 ||
! 506: ed->bDescriptorType == UDESC_INTERFACE)
! 507: break;
! 508: }
! 509: /* passed end, or bad desc */
! 510: printf("usbd_fill_iface_data: bad descriptor(s): %s\n",
! 511: ed->bLength == 0 ? "0 length" :
! 512: ed->bDescriptorType == UDESC_INTERFACE ? "iface desc" :
! 513: "out of data");
! 514: goto bad;
! 515: found:
! 516: ifc->endpoints[endpt].edesc = ed;
! 517: if (dev->speed == USB_SPEED_HIGH) {
! 518: u_int mps;
! 519: /* Control and bulk endpoints have max packet
! 520: limits. */
! 521: switch (UE_GET_XFERTYPE(ed->bmAttributes)) {
! 522: case UE_CONTROL:
! 523: mps = USB_2_MAX_CTRL_PACKET;
! 524: goto check;
! 525: case UE_BULK:
! 526: mps = USB_2_MAX_BULK_PACKET;
! 527: check:
! 528: if (UGETW(ed->wMaxPacketSize) != mps) {
! 529: USETW(ed->wMaxPacketSize, mps);
! 530: #ifdef DIAGNOSTIC
! 531: printf("usbd_fill_iface_data: bad max "
! 532: "packet size\n");
! 533: #endif
! 534: }
! 535: break;
! 536: default:
! 537: break;
! 538: }
! 539: }
! 540: ifc->endpoints[endpt].refcnt = 0;
! 541: ifc->endpoints[endpt].savedtoggle = 0;
! 542: p += ed->bLength;
! 543: }
! 544: #undef ed
! 545: LIST_INIT(&ifc->pipes);
! 546: return (USBD_NORMAL_COMPLETION);
! 547:
! 548: bad:
! 549: if (ifc->endpoints != NULL) {
! 550: free(ifc->endpoints, M_USB);
! 551: ifc->endpoints = NULL;
! 552: }
! 553: return (USBD_INVAL);
! 554: }
! 555:
! 556: void
! 557: usbd_free_iface_data(usbd_device_handle dev, int ifcno)
! 558: {
! 559: usbd_interface_handle ifc = &dev->ifaces[ifcno];
! 560: if (ifc->endpoints)
! 561: free(ifc->endpoints, M_USB);
! 562: }
! 563:
! 564: usbd_status
! 565: usbd_set_config(usbd_device_handle dev, int conf)
! 566: {
! 567: usb_device_request_t req;
! 568:
! 569: req.bmRequestType = UT_WRITE_DEVICE;
! 570: req.bRequest = UR_SET_CONFIG;
! 571: USETW(req.wValue, conf);
! 572: USETW(req.wIndex, 0);
! 573: USETW(req.wLength, 0);
! 574: return (usbd_do_request(dev, &req, 0));
! 575: }
! 576:
! 577: usbd_status
! 578: usbd_set_config_no(usbd_device_handle dev, int no, int msg)
! 579: {
! 580: int index;
! 581: usb_config_descriptor_t cd;
! 582: usbd_status err;
! 583:
! 584: if (no == USB_UNCONFIG_NO)
! 585: return (usbd_set_config_index(dev, USB_UNCONFIG_INDEX, msg));
! 586:
! 587: DPRINTFN(5,("usbd_set_config_no: %d\n", no));
! 588: /* Figure out what config index to use. */
! 589: for (index = 0; index < dev->ddesc.bNumConfigurations; index++) {
! 590: err = usbd_get_config_desc(dev, index, &cd);
! 591: if (err)
! 592: return (err);
! 593: if (cd.bConfigurationValue == no)
! 594: return (usbd_set_config_index(dev, index, msg));
! 595: }
! 596: return (USBD_INVAL);
! 597: }
! 598:
! 599: usbd_status
! 600: usbd_set_config_index(usbd_device_handle dev, int index, int msg)
! 601: {
! 602: usb_status_t ds;
! 603: usb_config_descriptor_t cd, *cdp;
! 604: usbd_status err;
! 605: int i, ifcidx, nifc, len, selfpowered, power;
! 606:
! 607: DPRINTFN(5,("usbd_set_config_index: dev=%p index=%d\n", dev, index));
! 608:
! 609: /* XXX check that all interfaces are idle */
! 610: if (dev->config != USB_UNCONFIG_NO) {
! 611: DPRINTF(("usbd_set_config_index: free old config\n"));
! 612: /* Free all configuration data structures. */
! 613: nifc = dev->cdesc->bNumInterface;
! 614: for (ifcidx = 0; ifcidx < nifc; ifcidx++)
! 615: usbd_free_iface_data(dev, ifcidx);
! 616: free(dev->ifaces, M_USB);
! 617: free(dev->cdesc, M_USB);
! 618: dev->ifaces = NULL;
! 619: dev->cdesc = NULL;
! 620: dev->config = USB_UNCONFIG_NO;
! 621: }
! 622:
! 623: if (index == USB_UNCONFIG_INDEX) {
! 624: /* We are unconfiguring the device, so leave unallocated. */
! 625: DPRINTF(("usbd_set_config_index: set config 0\n"));
! 626: err = usbd_set_config(dev, USB_UNCONFIG_NO);
! 627: if (err)
! 628: DPRINTF(("usbd_set_config_index: setting config=0 "
! 629: "failed, error=%s\n", usbd_errstr(err)));
! 630: return (err);
! 631: }
! 632:
! 633: /* Get the short descriptor. */
! 634: err = usbd_get_config_desc(dev, index, &cd);
! 635: if (err)
! 636: return (err);
! 637: len = UGETW(cd.wTotalLength);
! 638: cdp = malloc(len, M_USB, M_NOWAIT);
! 639: if (cdp == NULL)
! 640: return (USBD_NOMEM);
! 641: /* Get the full descriptor. */
! 642: for (i = 0; i < 3; i++) {
! 643: err = usbd_get_desc(dev, UDESC_CONFIG, index, len, cdp);
! 644: if (!err)
! 645: break;
! 646: usbd_delay_ms(dev, 200);
! 647: }
! 648: if (err)
! 649: goto bad;
! 650:
! 651: if (cdp->bDescriptorType != UDESC_CONFIG) {
! 652: DPRINTFN(-1,("usbd_set_config_index: bad desc %d\n",
! 653: cdp->bDescriptorType));
! 654: err = USBD_INVAL;
! 655: goto bad;
! 656: }
! 657:
! 658: /* Figure out if the device is self or bus powered. */
! 659: selfpowered = 0;
! 660: if (!(dev->quirks->uq_flags & UQ_BUS_POWERED) &&
! 661: (cdp->bmAttributes & UC_SELF_POWERED)) {
! 662: /* May be self powered. */
! 663: if (cdp->bmAttributes & UC_BUS_POWERED) {
! 664: /* Must ask device. */
! 665: if (dev->quirks->uq_flags & UQ_POWER_CLAIM) {
! 666: /*
! 667: * Hub claims to be self powered, but isn't.
! 668: * It seems that the power status can be
! 669: * determined by the hub characteristics.
! 670: */
! 671: usb_hub_descriptor_t hd;
! 672: usb_device_request_t req;
! 673: req.bmRequestType = UT_READ_CLASS_DEVICE;
! 674: req.bRequest = UR_GET_DESCRIPTOR;
! 675: USETW(req.wValue, 0);
! 676: USETW(req.wIndex, 0);
! 677: USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE);
! 678: err = usbd_do_request(dev, &req, &hd);
! 679: if (!err &&
! 680: (UGETW(hd.wHubCharacteristics) &
! 681: UHD_PWR_INDIVIDUAL))
! 682: selfpowered = 1;
! 683: DPRINTF(("usbd_set_config_index: charac=0x%04x"
! 684: ", error=%s\n",
! 685: UGETW(hd.wHubCharacteristics),
! 686: usbd_errstr(err)));
! 687: } else {
! 688: err = usbd_get_device_status(dev, &ds);
! 689: if (!err &&
! 690: (UGETW(ds.wStatus) & UDS_SELF_POWERED))
! 691: selfpowered = 1;
! 692: DPRINTF(("usbd_set_config_index: status=0x%04x"
! 693: ", error=%s\n",
! 694: UGETW(ds.wStatus), usbd_errstr(err)));
! 695: }
! 696: } else
! 697: selfpowered = 1;
! 698: }
! 699: DPRINTF(("usbd_set_config_index: (addr %d) cno=%d attr=0x%02x, "
! 700: "selfpowered=%d, power=%d\n",
! 701: cdp->bConfigurationValue, dev->address, cdp->bmAttributes,
! 702: selfpowered, cdp->bMaxPower * 2));
! 703:
! 704: /* Check if we have enough power. */
! 705: #ifdef USB_DEBUG
! 706: if (dev->powersrc == NULL) {
! 707: DPRINTF(("usbd_set_config_index: No power source?\n"));
! 708: return (USBD_IOERROR);
! 709: }
! 710: #endif
! 711: power = cdp->bMaxPower * 2;
! 712: if (power > dev->powersrc->power) {
! 713: DPRINTF(("power exceeded %d %d\n", power,dev->powersrc->power));
! 714: /* XXX print nicer message. */
! 715: if (msg)
! 716: printf("%s: device addr %d (config %d) exceeds power "
! 717: "budget, %d mA > %d mA\n",
! 718: dev->bus->bdev.dv_xname, dev->address,
! 719: cdp->bConfigurationValue,
! 720: power, dev->powersrc->power);
! 721: err = USBD_NO_POWER;
! 722: goto bad;
! 723: }
! 724: dev->power = power;
! 725: dev->self_powered = selfpowered;
! 726:
! 727: /* Set the actual configuration value. */
! 728: DPRINTF(("usbd_set_config_index: set config %d\n",
! 729: cdp->bConfigurationValue));
! 730: err = usbd_set_config(dev, cdp->bConfigurationValue);
! 731: if (err) {
! 732: DPRINTF(("usbd_set_config_index: setting config=%d failed, "
! 733: "error=%s\n", cdp->bConfigurationValue, usbd_errstr(err)));
! 734: goto bad;
! 735: }
! 736:
! 737: /* Allocate and fill interface data. */
! 738: nifc = cdp->bNumInterface;
! 739: dev->ifaces = malloc(nifc * sizeof(struct usbd_interface),
! 740: M_USB, M_NOWAIT);
! 741: if (dev->ifaces == NULL) {
! 742: err = USBD_NOMEM;
! 743: goto bad;
! 744: }
! 745: DPRINTFN(5,("usbd_set_config_index: dev=%p cdesc=%p\n", dev, cdp));
! 746: dev->cdesc = cdp;
! 747: dev->config = cdp->bConfigurationValue;
! 748: for (ifcidx = 0; ifcidx < nifc; ifcidx++) {
! 749: err = usbd_fill_iface_data(dev, ifcidx, 0);
! 750: if (err) {
! 751: while (--ifcidx >= 0)
! 752: usbd_free_iface_data(dev, ifcidx);
! 753: goto bad;
! 754: }
! 755: }
! 756:
! 757: return (USBD_NORMAL_COMPLETION);
! 758:
! 759: bad:
! 760: free(cdp, M_USB);
! 761: return (err);
! 762: }
! 763:
! 764: /* XXX add function for alternate settings */
! 765:
! 766: usbd_status
! 767: usbd_setup_pipe(usbd_device_handle dev, usbd_interface_handle iface,
! 768: struct usbd_endpoint *ep, int ival, usbd_pipe_handle *pipe)
! 769: {
! 770: usbd_pipe_handle p;
! 771: usbd_status err;
! 772:
! 773: DPRINTFN(1,("usbd_setup_pipe: dev=%p iface=%p ep=%p pipe=%p\n",
! 774: dev, iface, ep, pipe));
! 775: p = malloc(dev->bus->pipe_size, M_USB, M_NOWAIT);
! 776: if (p == NULL)
! 777: return (USBD_NOMEM);
! 778: p->device = dev;
! 779: p->iface = iface;
! 780: p->endpoint = ep;
! 781: ep->refcnt++;
! 782: p->refcnt = 1;
! 783: p->intrxfer = 0;
! 784: p->running = 0;
! 785: p->aborting = 0;
! 786: p->repeat = 0;
! 787: p->interval = ival;
! 788: SIMPLEQ_INIT(&p->queue);
! 789: err = dev->bus->methods->open_pipe(p);
! 790: if (err) {
! 791: DPRINTFN(-1,("usbd_setup_pipe: endpoint=0x%x failed, error="
! 792: "%s\n",
! 793: ep->edesc->bEndpointAddress, usbd_errstr(err)));
! 794: free(p, M_USB);
! 795: return (err);
! 796: }
! 797: *pipe = p;
! 798: return (USBD_NORMAL_COMPLETION);
! 799: }
! 800:
! 801: /* Abort the device control pipe. */
! 802: void
! 803: usbd_kill_pipe(usbd_pipe_handle pipe)
! 804: {
! 805: usbd_abort_pipe(pipe);
! 806: pipe->methods->close(pipe);
! 807: pipe->endpoint->refcnt--;
! 808: free(pipe, M_USB);
! 809: }
! 810:
! 811: int
! 812: usbd_getnewaddr(usbd_bus_handle bus)
! 813: {
! 814: int addr;
! 815:
! 816: for (addr = 1; addr < USB_MAX_DEVICES; addr++)
! 817: if (bus->devices[addr] == 0)
! 818: return (addr);
! 819: return (-1);
! 820: }
! 821:
! 822:
! 823: usbd_status
! 824: usbd_probe_and_attach(struct device *parent, usbd_device_handle dev, int port,
! 825: int addr)
! 826: {
! 827: struct usb_attach_arg uaa;
! 828: usb_device_descriptor_t *dd = &dev->ddesc;
! 829: int found, i, confi, nifaces, len;
! 830: usbd_status err;
! 831: struct device *dv;
! 832: usbd_interface_handle *ifaces;
! 833:
! 834: uaa.device = dev;
! 835: uaa.iface = NULL;
! 836: uaa.ifaces = NULL;
! 837: uaa.nifaces = 0;
! 838: uaa.usegeneric = 0;
! 839: uaa.port = port;
! 840: uaa.configno = UHUB_UNK_CONFIGURATION;
! 841: uaa.ifaceno = UHUB_UNK_INTERFACE;
! 842: uaa.vendor = UGETW(dd->idVendor);
! 843: uaa.product = UGETW(dd->idProduct);
! 844: uaa.release = UGETW(dd->bcdDevice);
! 845:
! 846: /* First try with device specific drivers. */
! 847: DPRINTF(("usbd_probe_and_attach: trying device specific drivers\n"));
! 848: dv = config_found_sm(parent, &uaa, usbd_print, usbd_submatch);
! 849: if (dv) {
! 850: dev->subdevs = malloc(2 * sizeof dv, M_USB, M_NOWAIT);
! 851: if (dev->subdevs == NULL)
! 852: return (USBD_NOMEM);
! 853: dev->subdevs[0] = dv;
! 854: dev->subdevs[1] = 0;
! 855: return (USBD_NORMAL_COMPLETION);
! 856: }
! 857:
! 858: DPRINTF(("usbd_probe_and_attach: no device specific driver found\n"));
! 859:
! 860: DPRINTF(("usbd_probe_and_attach: looping over %d configurations\n",
! 861: dd->bNumConfigurations));
! 862: /* Next try with interface drivers. */
! 863: for (confi = 0; confi < dd->bNumConfigurations; confi++) {
! 864: DPRINTFN(1,("usbd_probe_and_attach: trying config idx=%d\n",
! 865: confi));
! 866: err = usbd_set_config_index(dev, confi, 1);
! 867: if (err) {
! 868: #ifdef USB_DEBUG
! 869: DPRINTF(("%s: port %d, set config at addr %d failed, "
! 870: "error=%s\n", parent->dv_xname, port,
! 871: addr, usbd_errstr(err)));
! 872: #else
! 873: printf("%s: port %d, set config at addr %d failed\n",
! 874: parent->dv_xname, port, addr);
! 875: #endif
! 876:
! 877: return (err);
! 878: }
! 879: nifaces = dev->cdesc->bNumInterface;
! 880: uaa.configno = dev->cdesc->bConfigurationValue;
! 881: ifaces = malloc(nifaces * sizeof(usbd_interface_handle),
! 882: M_USB, M_NOWAIT);
! 883: if (ifaces == NULL)
! 884: return (USBD_NOMEM);
! 885: for (i = 0; i < nifaces; i++)
! 886: ifaces[i] = &dev->ifaces[i];
! 887: uaa.ifaces = ifaces;
! 888: uaa.nifaces = nifaces;
! 889: len = (nifaces+1) * sizeof dv;
! 890: dev->subdevs = malloc(len, M_USB, M_NOWAIT);
! 891: if (dev->subdevs == NULL) {
! 892: free(ifaces, M_USB);
! 893: return (USBD_NOMEM);
! 894: }
! 895: bzero(dev->subdevs, len);
! 896:
! 897: found = 0;
! 898: for (i = 0; i < nifaces; i++) {
! 899: if (ifaces[i] == NULL)
! 900: continue; /* interface already claimed */
! 901: uaa.iface = ifaces[i];
! 902: uaa.ifaceno = ifaces[i]->idesc->bInterfaceNumber;
! 903: dv = config_found_sm(parent, &uaa, usbd_print,
! 904: usbd_submatch);
! 905:
! 906: if (dv != NULL) {
! 907: dev->subdevs[found++] = dv;
! 908: ifaces[i] = NULL; /* consumed */
! 909: }
! 910: }
! 911: free(ifaces, M_USB);
! 912: if (found != 0) {
! 913: return (USBD_NORMAL_COMPLETION);
! 914: }
! 915: free(dev->subdevs, M_USB);
! 916: dev->subdevs = 0;
! 917: }
! 918: /* No interfaces were attached in any of the configurations. */
! 919:
! 920: if (dd->bNumConfigurations > 1) /* don't change if only 1 config */
! 921: usbd_set_config_index(dev, 0, 0);
! 922:
! 923: DPRINTF(("usbd_probe_and_attach: no interface drivers found\n"));
! 924:
! 925: /* Finally try the generic driver. */
! 926: uaa.iface = NULL;
! 927: uaa.usegeneric = 1;
! 928: uaa.configno = UHUB_UNK_CONFIGURATION;
! 929: uaa.ifaceno = UHUB_UNK_INTERFACE;
! 930: dv = config_found_sm(parent, &uaa, usbd_print, usbd_submatch);
! 931: if (dv != NULL) {
! 932: dev->subdevs = malloc(2 * sizeof dv, M_USB, M_NOWAIT);
! 933: if (dev->subdevs == 0)
! 934: return (USBD_NOMEM);
! 935: dev->subdevs[0] = dv;
! 936: dev->subdevs[1] = 0;
! 937: return (USBD_NORMAL_COMPLETION);
! 938: }
! 939:
! 940: /*
! 941: * The generic attach failed, but leave the device as it is.
! 942: * We just did not find any drivers, that's all. The device is
! 943: * fully operational and not harming anyone.
! 944: */
! 945: DPRINTF(("usbd_probe_and_attach: generic attach failed\n"));
! 946: return (USBD_NORMAL_COMPLETION);
! 947: }
! 948:
! 949:
! 950: /*
! 951: * Called when a new device has been put in the powered state,
! 952: * but not yet in the addressed state.
! 953: * Get initial descriptor, set the address, get full descriptor,
! 954: * and attach a driver.
! 955: */
! 956: usbd_status
! 957: usbd_new_device(struct device *parent, usbd_bus_handle bus, int depth,
! 958: int speed, int port, struct usbd_port *up)
! 959: {
! 960: usbd_device_handle dev, adev;
! 961: struct usbd_device *hub;
! 962: usb_device_descriptor_t *dd;
! 963: usbd_status err;
! 964: int addr;
! 965: int i;
! 966: int p;
! 967:
! 968: DPRINTF(("usbd_new_device bus=%p port=%d depth=%d speed=%d\n",
! 969: bus, port, depth, speed));
! 970: addr = usbd_getnewaddr(bus);
! 971: if (addr < 0) {
! 972: printf("%s: No free USB addresses, new device ignored.\n",
! 973: bus->bdev.dv_xname);
! 974: return (USBD_NO_ADDR);
! 975: }
! 976:
! 977: dev = malloc(sizeof *dev, M_USB, M_NOWAIT);
! 978: if (dev == NULL)
! 979: return (USBD_NOMEM);
! 980: memset(dev, 0, sizeof *dev);
! 981:
! 982: dev->bus = bus;
! 983:
! 984: /* Set up default endpoint handle. */
! 985: dev->def_ep.edesc = &dev->def_ep_desc;
! 986:
! 987: /* Set up default endpoint descriptor. */
! 988: dev->def_ep_desc.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE;
! 989: dev->def_ep_desc.bDescriptorType = UDESC_ENDPOINT;
! 990: dev->def_ep_desc.bEndpointAddress = USB_CONTROL_ENDPOINT;
! 991: dev->def_ep_desc.bmAttributes = UE_CONTROL;
! 992: USETW(dev->def_ep_desc.wMaxPacketSize, USB_MAX_IPACKET);
! 993: dev->def_ep_desc.bInterval = 0;
! 994:
! 995: dev->quirks = &usbd_no_quirk;
! 996: dev->address = USB_START_ADDR;
! 997: dev->ddesc.bMaxPacketSize = 0;
! 998: dev->depth = depth;
! 999: dev->powersrc = up;
! 1000: dev->myhub = up->parent;
! 1001:
! 1002: up->device = dev;
! 1003:
! 1004: /* Locate port on upstream high speed hub */
! 1005: for (adev = dev, hub = up->parent;
! 1006: hub != NULL && hub->speed != USB_SPEED_HIGH;
! 1007: adev = hub, hub = hub->myhub)
! 1008: ;
! 1009: if (hub) {
! 1010: for (p = 0; p < hub->hub->hubdesc.bNbrPorts; p++) {
! 1011: if (hub->hub->ports[p].device == adev) {
! 1012: dev->myhsport = &hub->hub->ports[p];
! 1013: goto found;
! 1014: }
! 1015: }
! 1016: panic("usbd_new_device: cannot find HS port");
! 1017: found:
! 1018: DPRINTFN(1,("usbd_new_device: high speed port %d\n", p));
! 1019: } else {
! 1020: dev->myhsport = NULL;
! 1021: }
! 1022: dev->speed = speed;
! 1023: dev->langid = USBD_NOLANG;
! 1024: dev->cookie.cookie = ++usb_cookie_no;
! 1025:
! 1026: /* Establish the default pipe. */
! 1027: err = usbd_setup_pipe(dev, 0, &dev->def_ep, USBD_DEFAULT_INTERVAL,
! 1028: &dev->default_pipe);
! 1029: if (err) {
! 1030: usbd_remove_device(dev, up);
! 1031: return (err);
! 1032: }
! 1033:
! 1034: dd = &dev->ddesc;
! 1035: /* Try a few times in case the device is slow (i.e. outside specs.) */
! 1036: for (i = 0; i < 5; i++) {
! 1037: /* Get the first 8 bytes of the device descriptor. */
! 1038: err = usbd_get_desc(dev, UDESC_DEVICE, 0, USB_MAX_IPACKET, dd);
! 1039: if (!err)
! 1040: break;
! 1041: /* progressively increase the delay */
! 1042: usbd_delay_ms(dev, 200 * (i + 1));
! 1043: }
! 1044: if (err) {
! 1045: DPRINTFN(-1, ("usbd_new_device: addr=%d, getting first desc "
! 1046: "failed\n", addr));
! 1047: usbd_remove_device(dev, up);
! 1048: return (err);
! 1049: }
! 1050:
! 1051: if (speed == USB_SPEED_HIGH) {
! 1052: /* Max packet size must be 64 (sec 5.5.3). */
! 1053: if (dd->bMaxPacketSize != USB_2_MAX_CTRL_PACKET) {
! 1054: #ifdef DIAGNOSTIC
! 1055: printf("usbd_new_device: addr=%d bad max packet size\n",
! 1056: addr);
! 1057: #endif
! 1058: dd->bMaxPacketSize = USB_2_MAX_CTRL_PACKET;
! 1059: }
! 1060: }
! 1061:
! 1062: DPRINTF(("usbd_new_device: adding unit addr=%d, rev=%02x, class=%d, "
! 1063: "subclass=%d, protocol=%d, maxpacket=%d, len=%d, speed=%d\n",
! 1064: addr,UGETW(dd->bcdUSB), dd->bDeviceClass, dd->bDeviceSubClass,
! 1065: dd->bDeviceProtocol, dd->bMaxPacketSize, dd->bLength,
! 1066: dev->speed));
! 1067:
! 1068: if (dd->bDescriptorType != UDESC_DEVICE) {
! 1069: /* Illegal device descriptor */
! 1070: DPRINTFN(-1,("usbd_new_device: illegal descriptor %d\n",
! 1071: dd->bDescriptorType));
! 1072: usbd_remove_device(dev, up);
! 1073: return (USBD_INVAL);
! 1074: }
! 1075:
! 1076: if (dd->bLength < USB_DEVICE_DESCRIPTOR_SIZE) {
! 1077: DPRINTFN(-1,("usbd_new_device: bad length %d\n", dd->bLength));
! 1078: usbd_remove_device(dev, up);
! 1079: return (USBD_INVAL);
! 1080: }
! 1081:
! 1082: USETW(dev->def_ep_desc.wMaxPacketSize, dd->bMaxPacketSize);
! 1083:
! 1084: err = usbd_reload_device_desc(dev);
! 1085: if (err) {
! 1086: DPRINTFN(-1, ("usbd_new_device: addr=%d, getting full desc "
! 1087: "failed\n", addr));
! 1088: usbd_remove_device(dev, up);
! 1089: return (err);
! 1090: }
! 1091:
! 1092: /* Set the address */
! 1093: DPRINTFN(5,("usbd_new_device: setting device address=%d\n", addr));
! 1094: err = usbd_set_address(dev, addr);
! 1095: if (err) {
! 1096: DPRINTFN(-1,("usbd_new_device: set address %d failed\n", addr));
! 1097: err = USBD_SET_ADDR_FAILED;
! 1098: usbd_remove_device(dev, up);
! 1099: return (err);
! 1100: }
! 1101: /* Allow device time to set new address */
! 1102: usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE);
! 1103:
! 1104: dev->address = addr; /* New device address now */
! 1105: bus->devices[addr] = dev;
! 1106:
! 1107: /* Assume 100mA bus powered for now. Changed when configured. */
! 1108: dev->power = USB_MIN_POWER;
! 1109: dev->self_powered = 0;
! 1110:
! 1111: DPRINTF(("usbd_new_device: new dev (addr %d), dev=%p, parent=%p\n",
! 1112: addr, dev, parent));
! 1113:
! 1114: usbd_add_dev_event(USB_EVENT_DEVICE_ATTACH, dev);
! 1115:
! 1116: err = usbd_probe_and_attach(parent, dev, port, addr);
! 1117: if (err) {
! 1118: usbd_remove_device(dev, up);
! 1119: return (err);
! 1120: }
! 1121:
! 1122: return (USBD_NORMAL_COMPLETION);
! 1123: }
! 1124:
! 1125: usbd_status
! 1126: usbd_reload_device_desc(usbd_device_handle dev)
! 1127: {
! 1128: usbd_status err;
! 1129:
! 1130: /* Get the full device descriptor. */
! 1131: err = usbd_get_device_desc(dev, &dev->ddesc);
! 1132: if (err)
! 1133: return (err);
! 1134:
! 1135: /* Figure out what's wrong with this device. */
! 1136: dev->quirks = usbd_find_quirk(&dev->ddesc);
! 1137:
! 1138: return (USBD_NORMAL_COMPLETION);
! 1139: }
! 1140:
! 1141: void
! 1142: usbd_remove_device(usbd_device_handle dev, struct usbd_port *up)
! 1143: {
! 1144: DPRINTF(("usbd_remove_device: %p\n", dev));
! 1145:
! 1146: if (dev->default_pipe != NULL)
! 1147: usbd_kill_pipe(dev->default_pipe);
! 1148: up->device = NULL;
! 1149: dev->bus->devices[dev->address] = NULL;
! 1150:
! 1151: free(dev, M_USB);
! 1152: }
! 1153:
! 1154: int
! 1155: usbd_print(void *aux, const char *pnp)
! 1156: {
! 1157: struct usb_attach_arg *uaa = aux;
! 1158: char devinfo[1024];
! 1159:
! 1160: DPRINTFN(15, ("usbd_print dev=%p\n", uaa->device));
! 1161: if (pnp) {
! 1162: if (!uaa->usegeneric)
! 1163: return (QUIET);
! 1164: usbd_devinfo(uaa->device, 1, devinfo, sizeof devinfo);
! 1165: printf("%s, %s", devinfo, pnp);
! 1166: }
! 1167: if (uaa->port != 0)
! 1168: printf(" port %d", uaa->port);
! 1169: if (uaa->configno != UHUB_UNK_CONFIGURATION)
! 1170: printf(" configuration %d", uaa->configno);
! 1171: if (uaa->ifaceno != UHUB_UNK_INTERFACE)
! 1172: printf(" interface %d", uaa->ifaceno);
! 1173: #if 0
! 1174: /*
! 1175: * It gets very crowded with these locators on the attach line.
! 1176: * They are not really needed since they are printed in the clear
! 1177: * by each driver.
! 1178: */
! 1179: if (uaa->vendor != UHUB_UNK_VENDOR)
! 1180: printf(" vendor 0x%04x", uaa->vendor);
! 1181: if (uaa->product != UHUB_UNK_PRODUCT)
! 1182: printf(" product 0x%04x", uaa->product);
! 1183: if (uaa->release != UHUB_UNK_RELEASE)
! 1184: printf(" release 0x%04x", uaa->release);
! 1185: #endif
! 1186: return (UNCONF);
! 1187: }
! 1188:
! 1189: int
! 1190: usbd_submatch(struct device *parent, void *match, void *aux)
! 1191: {
! 1192: struct cfdata *cf = match;
! 1193: struct usb_attach_arg *uaa = aux;
! 1194:
! 1195: DPRINTFN(5,("usbd_submatch port=%d,%d configno=%d,%d "
! 1196: "ifaceno=%d,%d vendor=%d,%d product=%d,%d release=%d,%d\n",
! 1197: uaa->port, cf->uhubcf_port,
! 1198: uaa->configno, cf->uhubcf_configuration,
! 1199: uaa->ifaceno, cf->uhubcf_interface,
! 1200: uaa->vendor, cf->uhubcf_vendor,
! 1201: uaa->product, cf->uhubcf_product,
! 1202: uaa->release, cf->uhubcf_release));
! 1203: if (uaa->port != 0 && /* root hub has port 0, it should match */
! 1204: ((uaa->port != 0 &&
! 1205: cf->uhubcf_port != UHUB_UNK_PORT &&
! 1206: cf->uhubcf_port != uaa->port) ||
! 1207: (uaa->configno != UHUB_UNK_CONFIGURATION &&
! 1208: cf->uhubcf_configuration != UHUB_UNK_CONFIGURATION &&
! 1209: cf->uhubcf_configuration != uaa->configno) ||
! 1210: (uaa->ifaceno != UHUB_UNK_INTERFACE &&
! 1211: cf->uhubcf_interface != UHUB_UNK_INTERFACE &&
! 1212: cf->uhubcf_interface != uaa->ifaceno) ||
! 1213: (uaa->vendor != UHUB_UNK_VENDOR &&
! 1214: cf->uhubcf_vendor != UHUB_UNK_VENDOR &&
! 1215: cf->uhubcf_vendor != uaa->vendor) ||
! 1216: (uaa->product != UHUB_UNK_PRODUCT &&
! 1217: cf->uhubcf_product != UHUB_UNK_PRODUCT &&
! 1218: cf->uhubcf_product != uaa->product) ||
! 1219: (uaa->release != UHUB_UNK_RELEASE &&
! 1220: cf->uhubcf_release != UHUB_UNK_RELEASE &&
! 1221: cf->uhubcf_release != uaa->release)
! 1222: )
! 1223: )
! 1224: return 0;
! 1225: if (cf->uhubcf_vendor != UHUB_UNK_VENDOR &&
! 1226: cf->uhubcf_vendor == uaa->vendor &&
! 1227: cf->uhubcf_product != UHUB_UNK_PRODUCT &&
! 1228: cf->uhubcf_product == uaa->product) {
! 1229: /* We have a vendor&product locator match */
! 1230: if (cf->uhubcf_release != UHUB_UNK_RELEASE &&
! 1231: cf->uhubcf_release == uaa->release)
! 1232: uaa->matchlvl = UMATCH_VENDOR_PRODUCT_REV;
! 1233: else
! 1234: uaa->matchlvl = UMATCH_VENDOR_PRODUCT;
! 1235: } else
! 1236: uaa->matchlvl = 0;
! 1237: return ((*cf->cf_attach->ca_match)(parent, cf, aux));
! 1238: }
! 1239:
! 1240: void
! 1241: usbd_fill_deviceinfo(usbd_device_handle dev, struct usb_device_info *di,
! 1242: int usedev)
! 1243: {
! 1244: struct usbd_port *p;
! 1245: int i, err, s;
! 1246:
! 1247: di->udi_bus = dev->bus->bdev.dv_unit;
! 1248: di->udi_addr = dev->address;
! 1249: di->udi_cookie = dev->cookie;
! 1250: usbd_devinfo_vp(dev, di->udi_vendor, di->udi_product, usedev);
! 1251: usbd_printBCD(di->udi_release, sizeof di->udi_release,
! 1252: UGETW(dev->ddesc.bcdDevice));
! 1253: di->udi_vendorNo = UGETW(dev->ddesc.idVendor);
! 1254: di->udi_productNo = UGETW(dev->ddesc.idProduct);
! 1255: di->udi_releaseNo = UGETW(dev->ddesc.bcdDevice);
! 1256: di->udi_class = dev->ddesc.bDeviceClass;
! 1257: di->udi_subclass = dev->ddesc.bDeviceSubClass;
! 1258: di->udi_protocol = dev->ddesc.bDeviceProtocol;
! 1259: di->udi_config = dev->config;
! 1260: di->udi_power = dev->self_powered ? 0 : dev->power;
! 1261: di->udi_speed = dev->speed;
! 1262:
! 1263: if (dev->subdevs != NULL) {
! 1264: for (i = 0; dev->subdevs[i] && i < USB_MAX_DEVNAMES; i++) {
! 1265: strncpy(di->udi_devnames[i],
! 1266: dev->subdevs[i]->dv_xname, USB_MAX_DEVNAMELEN);
! 1267: di->udi_devnames[i][USB_MAX_DEVNAMELEN-1] = '\0';
! 1268: }
! 1269: } else
! 1270: i = 0;
! 1271:
! 1272: for (/*i is set */; i < USB_MAX_DEVNAMES; i++)
! 1273: di->udi_devnames[i][0] = 0; /* empty */
! 1274:
! 1275: if (dev->hub) {
! 1276: for (i = 0;
! 1277: i < sizeof(di->udi_ports) / sizeof(di->udi_ports[0]) &&
! 1278: i < dev->hub->hubdesc.bNbrPorts; i++) {
! 1279: p = &dev->hub->ports[i];
! 1280: if (p->device)
! 1281: err = p->device->address;
! 1282: else {
! 1283: s = UGETW(p->status.wPortStatus);
! 1284: if (s & UPS_PORT_ENABLED)
! 1285: err = USB_PORT_ENABLED;
! 1286: else if (s & UPS_SUSPEND)
! 1287: err = USB_PORT_SUSPENDED;
! 1288: else if (s & UPS_PORT_POWER)
! 1289: err = USB_PORT_POWERED;
! 1290: else
! 1291: err = USB_PORT_DISABLED;
! 1292: }
! 1293: di->udi_ports[i] = err;
! 1294: }
! 1295: di->udi_nports = dev->hub->hubdesc.bNbrPorts;
! 1296: } else
! 1297: di->udi_nports = 0;
! 1298: }
! 1299:
! 1300: void
! 1301: usb_free_device(usbd_device_handle dev)
! 1302: {
! 1303: int ifcidx, nifc;
! 1304:
! 1305: if (dev->default_pipe != NULL)
! 1306: usbd_kill_pipe(dev->default_pipe);
! 1307: if (dev->ifaces != NULL) {
! 1308: nifc = dev->cdesc->bNumInterface;
! 1309: for (ifcidx = 0; ifcidx < nifc; ifcidx++)
! 1310: usbd_free_iface_data(dev, ifcidx);
! 1311: free(dev->ifaces, M_USB);
! 1312: }
! 1313: if (dev->cdesc != NULL)
! 1314: free(dev->cdesc, M_USB);
! 1315: if (dev->subdevs != NULL)
! 1316: free(dev->subdevs, M_USB);
! 1317: free(dev, M_USB);
! 1318: }
! 1319:
! 1320: /*
! 1321: * The general mechanism for detaching drivers works as follows: Each
! 1322: * driver is responsible for maintaining a reference count on the
! 1323: * number of outstanding references to its softc (e.g. from
! 1324: * processing hanging in a read or write). The detach method of the
! 1325: * driver decrements this counter and flags in the softc that the
! 1326: * driver is dying and then wakes any sleepers. It then sleeps on the
! 1327: * softc. Each place that can sleep must maintain the reference
! 1328: * count. When the reference count drops to -1 (0 is the normal value
! 1329: * of the reference count) the a wakeup on the softc is performed
! 1330: * signaling to the detach waiter that all references are gone.
! 1331: */
! 1332:
! 1333: /*
! 1334: * Called from process context when we discover that a port has
! 1335: * been disconnected.
! 1336: */
! 1337: void
! 1338: usb_disconnect_port(struct usbd_port *up, struct device *parent)
! 1339: {
! 1340: usbd_device_handle dev = up->device;
! 1341: int i;
! 1342:
! 1343: DPRINTFN(3,("uhub_disconnect: up=%p dev=%p port=%d\n",
! 1344: up, dev, up->portno));
! 1345:
! 1346: #ifdef DIAGNOSTIC
! 1347: if (dev == NULL) {
! 1348: printf("usb_disconnect_port: no device\n");
! 1349: return;
! 1350: }
! 1351: #endif
! 1352:
! 1353: if (dev->subdevs != NULL) {
! 1354: DPRINTFN(3,("usb_disconnect_port: disconnect subdevs\n"));
! 1355: for (i = 0; dev->subdevs[i]; i++) {
! 1356: DPRINTF(("%s: at %s", dev->subdevs[i]->dv_xname,
! 1357: parent->dv_xname));
! 1358: if (up->portno != 0)
! 1359: DPRINTF((" port %d", up->portno));
! 1360: DPRINTF((" (addr %d) disconnected\n", dev->address));
! 1361: config_detach(dev->subdevs[i], DETACH_FORCE);
! 1362: dev->subdevs[i] = 0;
! 1363: }
! 1364: }
! 1365:
! 1366: usbd_add_dev_event(USB_EVENT_DEVICE_DETACH, dev);
! 1367: dev->bus->devices[dev->address] = NULL;
! 1368: up->device = NULL;
! 1369: usb_free_device(dev);
! 1370: }
CVSweb