Annotation of sys/dev/usb/usbf_subr.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: usbf_subr.c,v 1.10 2007/07/27 09:16:09 mbalmer Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
! 5: *
! 6: * Permission to use, copy, modify, and distribute this software for any
! 7: * purpose with or without fee is hereby granted, provided that the above
! 8: * copyright notice and this permission notice appear in all copies.
! 9: *
! 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 17: */
! 18:
! 19: /*
! 20: * USB function driver interface subroutines
! 21: */
! 22:
! 23: #include <sys/param.h>
! 24: #include <sys/malloc.h>
! 25: #include <sys/systm.h>
! 26: #include <sys/timeout.h>
! 27:
! 28: #include <machine/bus.h>
! 29:
! 30: #include <dev/usb/usb.h>
! 31: #include <dev/usb/usbdi.h>
! 32: #include <dev/usb/usbdivar.h>
! 33: #include <dev/usb/usb_mem.h>
! 34: #include <dev/usb/usbf.h>
! 35: #include <dev/usb/usbfvar.h>
! 36:
! 37: #ifndef USBF_DEBUG
! 38: #define DPRINTF(l, x) do {} while (0)
! 39: #else
! 40: extern int usbfdebug;
! 41: #define DPRINTF(l, x) if ((l) <= usbfdebug) printf x; else {}
! 42: #endif
! 43:
! 44: void *usbf_realloc(void **, size_t *, size_t);
! 45: size_t usbf_get_string(usbf_device_handle, u_int8_t, char *, size_t);
! 46: usbf_status usbf_open_pipe_ival(usbf_interface_handle, u_int8_t,
! 47: usbf_pipe_handle *, int);
! 48: usbf_status usbf_setup_pipe(usbf_device_handle, usbf_interface_handle,
! 49: struct usbf_endpoint *, int,
! 50: usbf_pipe_handle *);
! 51: void usbf_start_next(usbf_pipe_handle);
! 52: void usbf_set_endpoint_halt(usbf_endpoint_handle);
! 53: void usbf_clear_endpoint_halt(usbf_endpoint_handle);
! 54:
! 55: static const char * const usbf_error_strs[] = USBF_ERROR_STRS;
! 56:
! 57: const char *
! 58: usbf_errstr(usbf_status err)
! 59: {
! 60: static char buffer[5];
! 61:
! 62: if (err < USBF_ERROR_MAX)
! 63: return usbf_error_strs[err];
! 64:
! 65: snprintf(buffer, sizeof buffer, "%d", err);
! 66: return buffer;
! 67: }
! 68:
! 69: void *
! 70: usbf_realloc(void **pp, size_t *sizep, size_t newsize)
! 71: {
! 72: void *p;
! 73: size_t oldsize;
! 74:
! 75: if (newsize == 0) {
! 76: if (*sizep > 0)
! 77: free(*pp, M_USB);
! 78: *pp = NULL;
! 79: *sizep = 0;
! 80: return NULL;
! 81: }
! 82:
! 83: p = malloc(newsize, M_USB, M_NOWAIT);
! 84: if (p == NULL)
! 85: return NULL;
! 86:
! 87: oldsize = MIN(*sizep, newsize);
! 88: if (oldsize > 0)
! 89: bcopy(*pp, p, oldsize);
! 90: *pp = p;
! 91: *sizep = newsize;
! 92: return p;
! 93: }
! 94:
! 95: /*
! 96: * Attach a function driver.
! 97: */
! 98: static usbf_status
! 99: usbf_probe_and_attach(struct device *parent, usbf_device_handle dev, int port)
! 100: {
! 101: struct usbf_attach_arg uaa;
! 102: struct device *dv;
! 103:
! 104: KASSERT(dev->function == NULL);
! 105:
! 106: bzero(&uaa, sizeof uaa);
! 107: uaa.device = dev;
! 108:
! 109: /*
! 110: * The softc structure of a USB function driver must begin with a
! 111: * "struct usbf_function" member (instead of USBBASEDEV), which must
! 112: * be initialized in the function driver's attach routine. Also, it
! 113: * should use usbf_devinfo_setup() to set the device identification.
! 114: */
! 115: dv = config_found_sm(parent, &uaa, NULL, NULL);
! 116: if (dv != NULL) {
! 117: dev->function = (struct usbf_function *)dv;
! 118: return USBF_NORMAL_COMPLETION;
! 119: }
! 120:
! 121: /*
! 122: * We failed to attach a function driver for this device, but the
! 123: * device can still function as a generic USB device without any
! 124: * interfaces.
! 125: */
! 126: return USBF_NORMAL_COMPLETION;
! 127: }
! 128:
! 129: static void
! 130: usbf_remove_device(usbf_device_handle dev, struct usbf_port *up)
! 131: {
! 132: KASSERT(dev != NULL && dev == up->device);
! 133:
! 134: if (dev->function != NULL)
! 135: config_detach((struct device *)dev->function, DETACH_FORCE);
! 136: if (dev->default_pipe != NULL)
! 137: usbf_close_pipe(dev->default_pipe);
! 138: up->device = NULL;
! 139: free(dev, M_USB);
! 140: }
! 141:
! 142: usbf_status
! 143: usbf_new_device(struct device *parent, usbf_bus_handle bus, int depth,
! 144: int speed, int port, struct usbf_port *up)
! 145: {
! 146: struct usbf_device *dev;
! 147: usb_device_descriptor_t *ud;
! 148: usbf_status err;
! 149:
! 150: #ifdef DIAGNOSTIC
! 151: KASSERT(up->device == NULL);
! 152: #endif
! 153:
! 154: dev = malloc(sizeof(*dev), M_USB, M_NOWAIT);
! 155: if (dev == NULL)
! 156: return USBF_NOMEM;
! 157:
! 158: bzero(dev, sizeof *dev);
! 159: dev->bus = bus;
! 160: dev->string_id = USBF_STRING_ID_MIN;
! 161: SIMPLEQ_INIT(&dev->configs);
! 162:
! 163: /* Initialize device status. */
! 164: USETW(dev->status.wStatus, UDS_SELF_POWERED);
! 165:
! 166: /*
! 167: * Initialize device descriptor. The function driver for this
! 168: * device (attached below) must complete the device descriptor.
! 169: */
! 170: ud = &dev->ddesc;
! 171: ud->bLength = USB_DEVICE_DESCRIPTOR_SIZE;
! 172: ud->bDescriptorType = UDESC_DEVICE;
! 173: ud->bMaxPacketSize = bus->ep0_maxp;
! 174: if (bus->usbrev >= USBREV_2_0)
! 175: USETW(ud->bcdUSB, UD_USB_2_0);
! 176: else
! 177: USETW(ud->bcdUSB, 0x0101);
! 178:
! 179: /* Set up the default endpoint handle and descriptor. */
! 180: dev->def_ep.edesc = &dev->def_ep_desc;
! 181: dev->def_ep_desc.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE;
! 182: dev->def_ep_desc.bDescriptorType = UDESC_ENDPOINT;
! 183: dev->def_ep_desc.bEndpointAddress = USB_CONTROL_ENDPOINT;
! 184: dev->def_ep_desc.bmAttributes = UE_CONTROL;
! 185: USETW(dev->def_ep_desc.wMaxPacketSize, ud->bMaxPacketSize);
! 186: dev->def_ep_desc.bInterval = 0;
! 187:
! 188: /* Establish the default pipe. */
! 189: err = usbf_setup_pipe(dev, NULL, &dev->def_ep, 0,
! 190: &dev->default_pipe);
! 191: if (err) {
! 192: free(dev, M_USB);
! 193: return err;
! 194: }
! 195:
! 196: /* Preallocate xfers for default pipe. */
! 197: dev->default_xfer = usbf_alloc_xfer(dev);
! 198: dev->data_xfer = usbf_alloc_xfer(dev);
! 199: if (dev->default_xfer == NULL || dev->data_xfer == NULL) {
! 200: if (dev->default_xfer != NULL)
! 201: usbf_free_xfer(dev->default_xfer);
! 202: usbf_close_pipe(dev->default_pipe);
! 203: free(dev, M_USB);
! 204: return USBF_NOMEM;
! 205: }
! 206:
! 207: /* Insert device request xfer. */
! 208: usbf_setup_default_xfer(dev->default_xfer, dev->default_pipe,
! 209: NULL, &dev->def_req, 0, 0, usbf_do_request);
! 210: err = usbf_transfer(dev->default_xfer);
! 211: if (err && err != USBF_IN_PROGRESS) {
! 212: usbf_free_xfer(dev->default_xfer);
! 213: usbf_free_xfer(dev->data_xfer);
! 214: usbf_close_pipe(dev->default_pipe);
! 215: free(dev, M_USB);
! 216: return err;
! 217: }
! 218:
! 219: /* Associate the upstream port with the device. */
! 220: bzero(up, sizeof *up);
! 221: up->portno = port;
! 222: up->device = dev;
! 223:
! 224: /* Attach function driver. */
! 225: err = usbf_probe_and_attach(parent, dev, port);
! 226: if (err)
! 227: usbf_remove_device(dev, up);
! 228: return err;
! 229: }
! 230:
! 231: /*
! 232: * Should be called by the function driver in its attach routine to change
! 233: * the default device identification according to the particular function.
! 234: */
! 235: void
! 236: usbf_devinfo_setup(usbf_device_handle dev, u_int8_t devclass,
! 237: u_int8_t subclass, u_int8_t proto, u_int16_t vendor, u_int16_t product,
! 238: u_int16_t device, const char *manf, const char *prod, const char *ser)
! 239: {
! 240: usb_device_descriptor_t *dd;
! 241:
! 242: dd = usbf_device_descriptor(dev);
! 243: dd->bDeviceClass = devclass;
! 244: dd->bDeviceSubClass = subclass;
! 245: dd->bDeviceProtocol = proto;
! 246: if (vendor != 0)
! 247: USETW(dd->idVendor, vendor);
! 248: if (product != 0)
! 249: USETW(dd->idProduct, product);
! 250: if (device != 0)
! 251: USETW(dd->bcdDevice, device);
! 252: if (manf != NULL)
! 253: dd->iManufacturer = usbf_add_string(dev, manf);
! 254: if (prod != NULL)
! 255: dd->iProduct = usbf_add_string(dev, prod);
! 256: if (ser != NULL)
! 257: dd->iSerialNumber = usbf_add_string(dev, ser);
! 258: }
! 259:
! 260: char *
! 261: usbf_devinfo_alloc(usbf_device_handle dev)
! 262: {
! 263: char manf[40];
! 264: char prod[40];
! 265: usb_device_descriptor_t *dd;
! 266: size_t len;
! 267: char *devinfo;
! 268:
! 269: dd = usbf_device_descriptor(dev);
! 270: usbf_get_string(dev, dd->iManufacturer, manf, sizeof manf);
! 271: usbf_get_string(dev, dd->iProduct, prod, sizeof prod);
! 272:
! 273: len = strlen(manf) + strlen(prod) + 32;
! 274: devinfo = malloc(len, M_USB, M_NOWAIT);
! 275: if (devinfo == NULL)
! 276: return NULL;
! 277:
! 278: snprintf(devinfo, len, "%s %s, rev %d.%02d/%d.%02d", manf, prod,
! 279: (UGETW(dd->bcdUSB)>>8) & 0xff, UGETW(dd->bcdUSB) & 0xff,
! 280: (UGETW(dd->bcdDevice)>>8) & 0xff, UGETW(dd->bcdDevice) & 0xff);
! 281: return devinfo;
! 282: }
! 283:
! 284: void
! 285: usbf_devinfo_free(char *devinfo)
! 286: {
! 287: if (devinfo != NULL)
! 288: free(devinfo, M_USB);
! 289: }
! 290:
! 291: /*
! 292: * Add a string descriptor to a logical device and return the string's id.
! 293: *
! 294: * If there is not enough memory available for the new string descriptor, or
! 295: * if there is no unused string id left, return the id of the empty string
! 296: * instead of failing.
! 297: */
! 298: u_int8_t
! 299: usbf_add_string(usbf_device_handle dev, const char *string)
! 300: {
! 301: usb_string_descriptor_t *sd;
! 302: size_t oldsize;
! 303: size_t newsize;
! 304: size_t len, i;
! 305: u_int8_t id;
! 306:
! 307: if (string == NULL || *string == '\0' ||
! 308: dev->string_id == USBF_STRING_ID_MAX)
! 309: return USBF_EMPTY_STRING_ID;
! 310:
! 311: if ((len = strlen(string)) >= USB_MAX_STRING_LEN)
! 312: len = USB_MAX_STRING_LEN - 1;
! 313:
! 314: oldsize = dev->sdesc_size;
! 315: newsize = oldsize + 2 + 2 * len;
! 316:
! 317: sd = usbf_realloc((void **)&dev->sdesc, &dev->sdesc_size,
! 318: newsize);
! 319: if (sd == NULL)
! 320: return USBF_EMPTY_STRING_ID;
! 321:
! 322: sd = (usb_string_descriptor_t *)((char *)sd + oldsize);
! 323: sd->bLength = newsize - oldsize;
! 324: sd->bDescriptorType = UDESC_STRING;
! 325: for (i = 0; string[i] != '\0' && i < len; i++)
! 326: USETW(sd->bString[i], string[i]);
! 327:
! 328: id = dev->string_id++;
! 329: return id;
! 330: }
! 331:
! 332: usb_string_descriptor_t *
! 333: usbf_string_descriptor(usbf_device_handle dev, u_int8_t id)
! 334: {
! 335: static usb_string_descriptor_t sd0;
! 336: static usb_string_descriptor_t sd1;
! 337: usb_string_descriptor_t *sd;
! 338:
! 339: /* handle the special string ids */
! 340: switch (id) {
! 341: case USB_LANGUAGE_TABLE:
! 342: sd0.bLength = 4;
! 343: sd0.bDescriptorType = UDESC_STRING;
! 344: USETW(sd0.bString[0], 0x0409 /* en_US */);
! 345: return &sd0;
! 346:
! 347: case USBF_EMPTY_STRING_ID:
! 348: sd1.bLength = 2;
! 349: sd1.bDescriptorType = UDESC_STRING;
! 350: return &sd0;
! 351: }
! 352:
! 353: /* check if the string id is valid */
! 354: if (id > dev->string_id)
! 355: return NULL;
! 356:
! 357: /* seek and return the descriptor of a non-empty string */
! 358: id -= USBF_STRING_ID_MIN;
! 359: sd = dev->sdesc;
! 360: while (id-- > 0)
! 361: sd = (usb_string_descriptor_t *)((char *)sd + sd->bLength);
! 362: return sd;
! 363: }
! 364:
! 365: size_t
! 366: usbf_get_string(usbf_device_handle dev, u_int8_t id, char *s, size_t size)
! 367: {
! 368: usb_string_descriptor_t *sd = NULL;
! 369: size_t i, len;
! 370:
! 371: if (id != USB_LANGUAGE_TABLE)
! 372: sd = usbf_string_descriptor(dev, id);
! 373:
! 374: if (sd == NULL) {
! 375: if (size > 0)
! 376: *s = '\0';
! 377: return 0;
! 378: }
! 379:
! 380: len = (sd->bLength - 2) / 2;
! 381: if (size < 1)
! 382: return len;
! 383:
! 384: for (i = 0; i < (size - 1) && i < len; i++)
! 385: s[i] = UGETW(sd->bString[i]) & 0xff;
! 386: s[i] = '\0';
! 387: return len;
! 388: }
! 389:
! 390: /*
! 391: * Add a new device configuration to an existing USB logical device.
! 392: * The new configuration initially has zero interfaces.
! 393: */
! 394: usbf_status
! 395: usbf_add_config(usbf_device_handle dev, usbf_config_handle *ucp)
! 396: {
! 397: struct usbf_config *uc;
! 398: usb_config_descriptor_t *cd;
! 399:
! 400: uc = malloc(sizeof *uc, M_USB, M_NOWAIT);
! 401: if (uc == NULL)
! 402: return USBF_NOMEM;
! 403:
! 404: cd = malloc(sizeof *cd, M_USB, M_NOWAIT);
! 405: if (cd == NULL) {
! 406: free(uc, M_USB);
! 407: return USBF_NOMEM;
! 408: }
! 409:
! 410: bzero(uc, sizeof *uc);
! 411: uc->uc_device = dev;
! 412: uc->uc_cdesc = cd;
! 413: uc->uc_cdesc_size = sizeof *cd;
! 414: SIMPLEQ_INIT(&uc->iface_head);
! 415:
! 416: bzero(cd, sizeof *cd);
! 417: cd->bLength = USB_CONFIG_DESCRIPTOR_SIZE;
! 418: cd->bDescriptorType = UDESC_CONFIG;
! 419: USETW(cd->wTotalLength, USB_CONFIG_DESCRIPTOR_SIZE);
! 420: cd->bConfigurationValue = USB_UNCONFIG_NO + 1 +
! 421: dev->ddesc.bNumConfigurations;
! 422: cd->iConfiguration = 0;
! 423: cd->bmAttributes = UC_BUS_POWERED | UC_SELF_POWERED;
! 424: #if 0
! 425: cd->bMaxPower = 100 / UC_POWER_FACTOR; /* 100 mA */
! 426: #else
! 427: cd->bMaxPower = 0; /* XXX 0 mA */
! 428: #endif
! 429:
! 430: SIMPLEQ_INSERT_TAIL(&dev->configs, uc, next);
! 431: dev->ddesc.bNumConfigurations++;
! 432:
! 433: if (ucp != NULL)
! 434: *ucp = uc;
! 435: return USBF_NORMAL_COMPLETION;
! 436: }
! 437:
! 438: /*
! 439: * Allocate memory for a new descriptor at the end of the existing
! 440: * device configuration descriptor.
! 441: */
! 442: usbf_status
! 443: usbf_add_config_desc(usbf_config_handle uc, usb_descriptor_t *d,
! 444: usb_descriptor_t **dp)
! 445: {
! 446: usb_config_descriptor_t *cd;
! 447: size_t oldsize;
! 448: size_t newsize;
! 449:
! 450: oldsize = uc->uc_cdesc_size;
! 451: newsize = oldsize + d->bLength;
! 452: if (d->bLength < sizeof(usb_descriptor_t) || newsize > 65535)
! 453: return USBF_INVAL;
! 454:
! 455: cd = usbf_realloc((void **)&uc->uc_cdesc, &uc->uc_cdesc_size,
! 456: newsize);
! 457: if (cd == NULL)
! 458: return USBF_NOMEM;
! 459:
! 460: bcopy(d, (char *)cd + oldsize, d->bLength);
! 461: USETW(cd->wTotalLength, newsize);
! 462: if (dp != NULL)
! 463: *dp = (usb_descriptor_t *)((char *)cd + oldsize);
! 464: return USBF_NORMAL_COMPLETION;
! 465: }
! 466:
! 467: usbf_status
! 468: usbf_add_interface(usbf_config_handle uc, u_int8_t bInterfaceClass,
! 469: u_int8_t bInterfaceSubClass, u_int8_t bInterfaceProtocol,
! 470: const char *string, usbf_interface_handle *uip)
! 471: {
! 472: struct usbf_interface *ui;
! 473: usb_interface_descriptor_t *id;
! 474:
! 475: if (uc->uc_closed)
! 476: return USBF_INVAL;
! 477:
! 478: ui = malloc(sizeof *ui, M_USB, M_NOWAIT);
! 479: if (ui == NULL)
! 480: return USBF_NOMEM;
! 481:
! 482: id = malloc(sizeof *id, M_USB, M_NOWAIT);
! 483: if (id == NULL) {
! 484: free(ui, M_USB);
! 485: return USBF_NOMEM;
! 486: }
! 487:
! 488: bzero(ui, sizeof *ui);
! 489: ui->config = uc;
! 490: ui->idesc = id;
! 491: LIST_INIT(&ui->pipes);
! 492: SIMPLEQ_INIT(&ui->endpoint_head);
! 493:
! 494: bzero(id, sizeof *id);
! 495: id->bLength = USB_INTERFACE_DESCRIPTOR_SIZE;
! 496: id->bDescriptorType = UDESC_INTERFACE;
! 497: id->bInterfaceNumber = uc->uc_cdesc->bNumInterface;
! 498: id->bInterfaceClass = bInterfaceClass;
! 499: id->bInterfaceSubClass = bInterfaceSubClass;
! 500: id->bInterfaceProtocol = bInterfaceProtocol;
! 501: id->iInterface = 0; /*usbf_add_string(uc->uc_device, string);*/ /* XXX */
! 502:
! 503: SIMPLEQ_INSERT_TAIL(&uc->iface_head, ui, next);
! 504: uc->uc_cdesc->bNumInterface++;
! 505:
! 506: *uip = ui;
! 507: return USBF_NORMAL_COMPLETION;
! 508: }
! 509:
! 510: usbf_status
! 511: usbf_add_endpoint(usbf_interface_handle ui, u_int8_t bEndpointAddress,
! 512: u_int8_t bmAttributes, u_int16_t wMaxPacketSize, u_int8_t bInterval,
! 513: usbf_endpoint_handle *uep)
! 514: {
! 515: struct usbf_endpoint *ue;
! 516: usb_endpoint_descriptor_t *ed;
! 517:
! 518: if (ui->config->uc_closed)
! 519: return USBF_INVAL;
! 520:
! 521: ue = malloc(sizeof *ue, M_USB, M_NOWAIT);
! 522: if (ue == NULL)
! 523: return USBF_NOMEM;
! 524:
! 525: ed = malloc(sizeof *ed, M_USB, M_NOWAIT);
! 526: if (ed == NULL) {
! 527: free(ue, M_USB);
! 528: return USBF_NOMEM;
! 529: }
! 530:
! 531: bzero(ue, sizeof *ue);
! 532: ue->iface = ui;
! 533: ue->edesc = ed;
! 534:
! 535: bzero(ed, sizeof *ed);
! 536: ed->bLength = USB_ENDPOINT_DESCRIPTOR_SIZE;
! 537: ed->bDescriptorType = UDESC_ENDPOINT;
! 538: ed->bEndpointAddress = bEndpointAddress;
! 539: ed->bmAttributes = bmAttributes;
! 540: USETW(ed->wMaxPacketSize, wMaxPacketSize);
! 541: ed->bInterval = bInterval;
! 542:
! 543: SIMPLEQ_INSERT_TAIL(&ui->endpoint_head, ue, next);
! 544: ui->idesc->bNumEndpoints++;
! 545:
! 546: *uep = ue;
! 547: return USBF_NORMAL_COMPLETION;
! 548: }
! 549:
! 550: /*
! 551: * Close the configuration, thereby combining all descriptors and creating
! 552: * the real USB configuration descriptor that can be sent to the USB host.
! 553: */
! 554: usbf_status
! 555: usbf_end_config(usbf_config_handle uc)
! 556: {
! 557: struct usbf_interface *ui;
! 558: struct usbf_endpoint *ue;
! 559: usb_descriptor_t *d;
! 560: usbf_status err = USBF_NORMAL_COMPLETION;
! 561:
! 562: if (uc->uc_closed)
! 563: return USBF_INVAL;
! 564:
! 565: SIMPLEQ_FOREACH(ui, &uc->iface_head, next) {
! 566: err = usbf_add_config_desc(uc,
! 567: (usb_descriptor_t *)ui->idesc, &d);
! 568: if (err)
! 569: break;
! 570:
! 571: free(ui->idesc, M_USB);
! 572: ui->idesc = (usb_interface_descriptor_t *)d;
! 573:
! 574: SIMPLEQ_FOREACH(ue, &ui->endpoint_head, next) {
! 575: err = usbf_add_config_desc(uc,
! 576: (usb_descriptor_t *)ue->edesc, &d);
! 577: if (err)
! 578: break;
! 579:
! 580: free(ue->edesc, M_USB);
! 581: ue->edesc = (usb_endpoint_descriptor_t *)d;
! 582: }
! 583: }
! 584:
! 585: uc->uc_closed = 1;
! 586: return err;
! 587: }
! 588:
! 589: usb_device_descriptor_t *
! 590: usbf_device_descriptor(usbf_device_handle dev)
! 591: {
! 592: return &dev->ddesc;
! 593: }
! 594:
! 595: usb_config_descriptor_t *
! 596: usbf_config_descriptor(usbf_device_handle dev, u_int8_t index)
! 597: {
! 598: struct usbf_config *uc;
! 599:
! 600: SIMPLEQ_FOREACH(uc, &dev->configs, next) {
! 601: if (index-- == 0)
! 602: return uc->uc_cdesc;
! 603: }
! 604: return NULL;
! 605: }
! 606:
! 607: int
! 608: usbf_interface_number(usbf_interface_handle iface)
! 609: {
! 610: return iface->idesc->bInterfaceNumber;
! 611: }
! 612:
! 613: u_int8_t
! 614: usbf_endpoint_address(usbf_endpoint_handle endpoint)
! 615: {
! 616: return endpoint->edesc->bEndpointAddress;
! 617: }
! 618:
! 619: u_int8_t
! 620: usbf_endpoint_attributes(usbf_endpoint_handle endpoint)
! 621: {
! 622: return endpoint->edesc->bmAttributes;
! 623: }
! 624:
! 625: usbf_status
! 626: usbf_open_pipe(usbf_interface_handle iface, u_int8_t address,
! 627: usbf_pipe_handle *pipe)
! 628: {
! 629: return usbf_open_pipe_ival(iface, address, pipe, 0);
! 630: }
! 631:
! 632: usbf_status
! 633: usbf_open_pipe_ival(usbf_interface_handle iface, u_int8_t address,
! 634: usbf_pipe_handle *pipe, int ival)
! 635: {
! 636: struct usbf_endpoint *ep;
! 637: usbf_pipe_handle p;
! 638: usbf_status err;
! 639:
! 640: ep = usbf_iface_endpoint(iface, address);
! 641: if (ep == NULL)
! 642: return USBF_BAD_ADDRESS;
! 643:
! 644: err = usbf_setup_pipe(iface->config->uc_device, iface, ep,
! 645: ival, &p);
! 646: if (err)
! 647: return err;
! 648: LIST_INSERT_HEAD(&iface->pipes, p, next);
! 649: *pipe = p;
! 650: return USBF_NORMAL_COMPLETION;
! 651: }
! 652:
! 653: usbf_status
! 654: usbf_setup_pipe(usbf_device_handle dev, usbf_interface_handle iface,
! 655: struct usbf_endpoint *ep, int ival, usbf_pipe_handle *pipe)
! 656: {
! 657: struct usbf_pipe *p;
! 658: usbf_status err;
! 659:
! 660: p = malloc(dev->bus->pipe_size, M_USB, M_NOWAIT);
! 661: if (p == NULL)
! 662: return USBF_NOMEM;
! 663:
! 664: p->device = dev;
! 665: p->iface = iface;
! 666: p->endpoint = ep;
! 667: ep->refcnt++;
! 668: p->running = 0;
! 669: p->refcnt = 1;
! 670: p->repeat = 0;
! 671: p->interval = ival;
! 672: p->methods = NULL; /* set by bus driver in open_pipe() */
! 673: SIMPLEQ_INIT(&p->queue);
! 674: err = dev->bus->methods->open_pipe(p);
! 675: if (err) {
! 676: free(p, M_USB);
! 677: return err;
! 678: }
! 679: *pipe = p;
! 680: return USBF_NORMAL_COMPLETION;
! 681: }
! 682:
! 683: /* Dequeue all pipe operations. */
! 684: void
! 685: usbf_abort_pipe(usbf_pipe_handle pipe)
! 686: {
! 687: usbf_xfer_handle xfer;
! 688: int s;
! 689:
! 690: s = splusb();
! 691: pipe->repeat = 0;
! 692: pipe->aborting = 1;
! 693:
! 694: while ((xfer = SIMPLEQ_FIRST(&pipe->queue)) != NULL) {
! 695: DPRINTF(0,("usbf_abort_pipe: pipe=%p, xfer=%p\n", pipe,
! 696: xfer));
! 697: /* Make the DC abort it (and invoke the callback). */
! 698: pipe->methods->abort(xfer);
! 699: }
! 700:
! 701: pipe->aborting = 0;
! 702: splx(s);
! 703: }
! 704:
! 705: /* Abort all pipe operations and close the pipe. */
! 706: void
! 707: usbf_close_pipe(usbf_pipe_handle pipe)
! 708: {
! 709: usbf_abort_pipe(pipe);
! 710: pipe->methods->close(pipe);
! 711: pipe->endpoint->refcnt--;
! 712: free(pipe, M_USB);
! 713: }
! 714:
! 715: void
! 716: usbf_stall_pipe(usbf_pipe_handle pipe)
! 717: {
! 718: DPRINTF(0,("usbf_stall_pipe not implemented\n"));
! 719: }
! 720:
! 721: usbf_endpoint_handle
! 722: usbf_iface_endpoint(usbf_interface_handle iface, u_int8_t address)
! 723: {
! 724: usbf_endpoint_handle ep;
! 725:
! 726: SIMPLEQ_FOREACH(ep, &iface->endpoint_head, next) {
! 727: if (ep->edesc->bEndpointAddress == address)
! 728: return ep;
! 729: }
! 730: return NULL;
! 731: }
! 732:
! 733: usbf_endpoint_handle
! 734: usbf_config_endpoint(usbf_config_handle cfg, u_int8_t address)
! 735: {
! 736: usbf_interface_handle iface;
! 737: usbf_endpoint_handle ep;
! 738:
! 739: SIMPLEQ_FOREACH(iface, &cfg->iface_head, next) {
! 740: SIMPLEQ_FOREACH(ep, &iface->endpoint_head, next) {
! 741: if (ep->edesc->bEndpointAddress == address)
! 742: return ep;
! 743: }
! 744: }
! 745: return NULL;
! 746: }
! 747:
! 748: void
! 749: usbf_set_endpoint_halt(usbf_endpoint_handle endpoint)
! 750: {
! 751: }
! 752:
! 753: void
! 754: usbf_clear_endpoint_halt(usbf_endpoint_handle endpoint)
! 755: {
! 756: }
! 757:
! 758: usbf_status
! 759: usbf_set_endpoint_feature(usbf_config_handle cfg, u_int8_t address,
! 760: u_int16_t value)
! 761: {
! 762: usbf_endpoint_handle ep;
! 763:
! 764: DPRINTF(0,("usbf_set_endpoint_feature: cfg=%p address=%#x"
! 765: " value=%#x\n", cfg, address, value));
! 766:
! 767: ep = usbf_config_endpoint(cfg, address);
! 768: if (ep == NULL)
! 769: return USBF_BAD_ADDRESS;
! 770:
! 771: switch (value) {
! 772: case UF_ENDPOINT_HALT:
! 773: usbf_set_endpoint_halt(ep);
! 774: return USBF_NORMAL_COMPLETION;
! 775: default:
! 776: /* unsupported feature, send STALL in data/status phase */
! 777: return USBF_STALLED;
! 778: }
! 779: }
! 780:
! 781: usbf_status
! 782: usbf_clear_endpoint_feature(usbf_config_handle cfg, u_int8_t address,
! 783: u_int16_t value)
! 784: {
! 785: usbf_endpoint_handle ep;
! 786:
! 787: DPRINTF(0,("usbf_clear_endpoint_feature: cfg=%p address=%#x"
! 788: " value=%#x\n", cfg, address, value));
! 789:
! 790: ep = usbf_config_endpoint(cfg, address);
! 791: if (ep == NULL)
! 792: return USBF_BAD_ADDRESS;
! 793:
! 794: switch (value) {
! 795: case UF_ENDPOINT_HALT:
! 796: usbf_clear_endpoint_halt(ep);
! 797: return USBF_NORMAL_COMPLETION;
! 798: default:
! 799: /* unsupported feature, send STALL in data/status phase */
! 800: return USBF_STALLED;
! 801: }
! 802: }
! 803:
! 804: usbf_xfer_handle
! 805: usbf_alloc_xfer(usbf_device_handle dev)
! 806: {
! 807: struct usbf_xfer *xfer;
! 808:
! 809: /* allocate zero-filled buffer */
! 810: xfer = dev->bus->methods->allocx(dev->bus);
! 811: if (xfer == NULL)
! 812: return NULL;
! 813: xfer->device = dev;
! 814: timeout_set(&xfer->timeout_handle, NULL, NULL);
! 815: DPRINTF(1,("usbf_alloc_xfer() = %p\n", xfer));
! 816: return xfer;
! 817: }
! 818:
! 819: void
! 820: usbf_free_xfer(usbf_xfer_handle xfer)
! 821: {
! 822: DPRINTF(1,("usbf_free_xfer: %p\n", xfer));
! 823: if (xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF))
! 824: usbf_free_buffer(xfer);
! 825: xfer->device->bus->methods->freex(xfer->device->bus, xfer);
! 826: }
! 827:
! 828: usbf_status
! 829: usbf_allocmem(usbf_bus_handle bus, size_t size, size_t align, usb_dma_t *p)
! 830: {
! 831: struct usbd_bus dbus;
! 832: usbd_status err;
! 833:
! 834: /* XXX bad idea, fix usb_mem.c instead! */
! 835: dbus.dmatag = bus->dmatag;
! 836: err = usb_allocmem(&dbus, size, align, p);
! 837: return err ? USBF_NOMEM : USBF_NORMAL_COMPLETION;
! 838: }
! 839:
! 840: void
! 841: usbf_freemem(usbf_bus_handle bus, usb_dma_t *p)
! 842: {
! 843: usb_freemem((usbd_bus_handle)NULL, p);
! 844: }
! 845:
! 846: void *
! 847: usbf_alloc_buffer(usbf_xfer_handle xfer, u_int32_t size)
! 848: {
! 849: struct usbf_bus *bus = xfer->device->bus;
! 850: usbf_status err;
! 851:
! 852: #ifdef DIAGNOSTIC
! 853: if (xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF))
! 854: printf("xfer %p already has a buffer\n", xfer);
! 855: #endif
! 856:
! 857: err = bus->methods->allocm(bus, &xfer->dmabuf, size);
! 858: if (err)
! 859: return NULL;
! 860:
! 861: xfer->rqflags |= URQ_DEV_DMABUF;
! 862: return KERNADDR(&xfer->dmabuf, 0);
! 863: }
! 864:
! 865: void
! 866: usbf_free_buffer(usbf_xfer_handle xfer)
! 867: {
! 868: #ifdef DIAGNOSTIC
! 869: if (!(xfer->rqflags & URQ_DEV_DMABUF)) {
! 870: printf("usbf_free_buffer: no buffer\n");
! 871: return;
! 872: }
! 873: #endif
! 874: xfer->rqflags &= ~URQ_DEV_DMABUF;
! 875: xfer->device->bus->methods->freem(xfer->device->bus, &xfer->dmabuf);
! 876: }
! 877:
! 878: #ifdef USBF_DEBUG
! 879: /*
! 880: * The dump format is similar to Linux' Gadget driver so that we can
! 881: * easily compare traces.
! 882: */
! 883: static void
! 884: usbf_dump_buffer(usbf_xfer_handle xfer)
! 885: {
! 886: struct device *dev = (struct device *)xfer->pipe->device->bus->usbfctl;
! 887: usbf_endpoint_handle ep = xfer->pipe->endpoint;
! 888: int index = usbf_endpoint_index(ep);
! 889: int dir = usbf_endpoint_dir(ep);
! 890: u_char *p = xfer->buffer;
! 891: u_int i;
! 892:
! 893: printf("%s: ep%d-%s, length=%u, %s", dev->dv_xname, index,
! 894: (xfer->rqflags & URQ_REQUEST) ? "setup" :
! 895: (index == 0 ? "in" : (dir == UE_DIR_IN ? "in" : "out")),
! 896: xfer->length, usbf_errstr(xfer->status));
! 897:
! 898: for (i = 0; i < xfer->length; i++) {
! 899: if ((i % 16) == 0)
! 900: printf("\n%4x:", i);
! 901: else if ((i % 8) == 0)
! 902: printf(" ");
! 903: printf(" %02x", p[i]);
! 904: }
! 905: printf("\n");
! 906: }
! 907: #endif
! 908:
! 909: void
! 910: usbf_setup_xfer(usbf_xfer_handle xfer, usbf_pipe_handle pipe,
! 911: usbf_private_handle priv, void *buffer, u_int32_t length,
! 912: u_int16_t flags, u_int32_t timeout, usbf_callback callback)
! 913: {
! 914: xfer->pipe = pipe;
! 915: xfer->priv = priv;
! 916: xfer->buffer = buffer;
! 917: xfer->length = length;
! 918: xfer->actlen = 0;
! 919: xfer->flags = flags;
! 920: xfer->timeout = timeout;
! 921: xfer->status = USBF_NOT_STARTED;
! 922: xfer->callback = callback;
! 923: xfer->rqflags &= ~URQ_REQUEST;
! 924: }
! 925:
! 926: void
! 927: usbf_setup_default_xfer(usbf_xfer_handle xfer, usbf_pipe_handle pipe,
! 928: usbf_private_handle priv, usb_device_request_t *req, u_int16_t flags,
! 929: u_int32_t timeout, usbf_callback callback)
! 930: {
! 931: xfer->pipe = pipe;
! 932: xfer->priv = priv;
! 933: xfer->buffer = req;
! 934: xfer->length = sizeof *req;
! 935: xfer->actlen = 0;
! 936: xfer->flags = flags;
! 937: xfer->timeout = timeout;
! 938: xfer->status = USBF_NOT_STARTED;
! 939: xfer->callback = callback;
! 940: xfer->rqflags |= URQ_REQUEST;
! 941: }
! 942:
! 943: void
! 944: usbf_get_xfer_status(usbf_xfer_handle xfer, usbf_private_handle *priv,
! 945: void **buffer, u_int32_t *actlen, usbf_status *status)
! 946: {
! 947: if (priv != NULL)
! 948: *priv = xfer->priv;
! 949: if (buffer != NULL)
! 950: *buffer = xfer->buffer;
! 951: if (actlen != NULL)
! 952: *actlen = xfer->actlen;
! 953: if (status != NULL)
! 954: *status = xfer->status;
! 955: }
! 956:
! 957: usbf_status
! 958: usbf_transfer(usbf_xfer_handle xfer)
! 959: {
! 960: usbf_pipe_handle pipe = xfer->pipe;
! 961: usbf_status err;
! 962:
! 963: err = pipe->methods->transfer(xfer);
! 964: if (err != USBF_IN_PROGRESS && err) {
! 965: if (xfer->rqflags & URQ_AUTO_DMABUF) {
! 966: usbf_free_buffer(xfer);
! 967: xfer->rqflags &= ~URQ_AUTO_DMABUF;
! 968: }
! 969: }
! 970: return err;
! 971: }
! 972:
! 973: usbf_status
! 974: usbf_insert_transfer(usbf_xfer_handle xfer)
! 975: {
! 976: usbf_pipe_handle pipe = xfer->pipe;
! 977: usbf_status err;
! 978: int s;
! 979:
! 980: DPRINTF(1,("usbf_insert_transfer: xfer=%p pipe=%p running=%d\n",
! 981: xfer, pipe, pipe->running));
! 982:
! 983: s = splusb();
! 984: SIMPLEQ_INSERT_TAIL(&pipe->queue, xfer, next);
! 985: if (pipe->running)
! 986: err = USBF_IN_PROGRESS;
! 987: else {
! 988: pipe->running = 1;
! 989: err = USBF_NORMAL_COMPLETION;
! 990: }
! 991: splx(s);
! 992: return err;
! 993: }
! 994:
! 995: void
! 996: usbf_start_next(usbf_pipe_handle pipe)
! 997: {
! 998: usbf_xfer_handle xfer;
! 999: usbf_status err;
! 1000:
! 1001: SPLUSBCHECK;
! 1002:
! 1003: /* Get next request in queue. */
! 1004: xfer = SIMPLEQ_FIRST(&pipe->queue);
! 1005: if (xfer == NULL)
! 1006: pipe->running = 0;
! 1007: else {
! 1008: err = pipe->methods->start(xfer);
! 1009: if (err != USBF_IN_PROGRESS) {
! 1010: printf("usbf_start_next: %s\n", usbf_errstr(err));
! 1011: pipe->running = 0;
! 1012: /* XXX do what? */
! 1013: }
! 1014: }
! 1015: }
! 1016:
! 1017: /* Called at splusb() */
! 1018: void
! 1019: usbf_transfer_complete(usbf_xfer_handle xfer)
! 1020: {
! 1021: usbf_pipe_handle pipe = xfer->pipe;
! 1022: int repeat = pipe->repeat;
! 1023:
! 1024: SPLUSBCHECK;
! 1025: DPRINTF(1,("usbf_transfer_complete: xfer=%p pipe=%p running=%d\n",
! 1026: xfer, pipe, pipe->running));
! 1027: #ifdef USBF_DEBUG
! 1028: if (usbfdebug > 0)
! 1029: usbf_dump_buffer(xfer);
! 1030: #endif
! 1031:
! 1032: if (!repeat) {
! 1033: /* Remove request from queue. */
! 1034: KASSERT(SIMPLEQ_FIRST(&pipe->queue) == xfer);
! 1035: SIMPLEQ_REMOVE_HEAD(&pipe->queue, next);
! 1036: }
! 1037:
! 1038: if (xfer->status == USBF_NORMAL_COMPLETION &&
! 1039: xfer->actlen < xfer->length &&
! 1040: !(xfer->flags & USBD_SHORT_XFER_OK)) {
! 1041: DPRINTF(0,("usbf_transfer_complete: short xfer=%p %u<%u\n",
! 1042: xfer, xfer->actlen, xfer->length));
! 1043: xfer->status = USBF_SHORT_XFER;
! 1044: }
! 1045:
! 1046: if (xfer->callback != NULL)
! 1047: xfer->callback(xfer, xfer->priv, xfer->status);
! 1048:
! 1049: pipe->methods->done(xfer);
! 1050:
! 1051: /* XXX wake up any processes waiting for the transfer to complete */
! 1052:
! 1053: if (!repeat) {
! 1054: if (xfer->status != USBF_NORMAL_COMPLETION &&
! 1055: pipe->iface != NULL) /* not control pipe */
! 1056: pipe->running = 0;
! 1057: else
! 1058: usbf_start_next(pipe);
! 1059: }
! 1060: }
! 1061:
! 1062: /*
! 1063: * Software interrupts
! 1064: */
! 1065:
! 1066: usbf_status
! 1067: usbf_softintr_establish(struct usbf_bus *bus)
! 1068: {
! 1069: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
! 1070: KASSERT(bus->soft == NULL);
! 1071: /* XXX we should have our own level */
! 1072: bus->soft = softintr_establish(IPL_SOFTNET,
! 1073: bus->methods->soft_intr, bus);
! 1074: if (bus->soft == NULL)
! 1075: return USBF_INVAL;
! 1076: #endif
! 1077: return USBF_NORMAL_COMPLETION;
! 1078: }
! 1079:
! 1080: void
! 1081: usbf_schedsoftintr(struct usbf_bus *bus)
! 1082: {
! 1083: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
! 1084: softintr_schedule(bus->soft);
! 1085: #else
! 1086: bus->methods->soft_intr(bus);
! 1087: #endif /* __HAVE_GENERIC_SOFT_INTERRUPTS */
! 1088: }
CVSweb