static inline int usbhost_talloc(FAR struct usbhost_state_s *priv) { FAR struct usbhost_hubport_s *hport; DEBUGASSERT(priv != NULL && priv->usbclass.hport != NULL && priv->tbuffer == NULL); hport = priv->usbclass.hport; return DRVR_ALLOC(hport->drvr, &priv->tbuffer, &priv->tbuflen); }
int usbhost_enumerate(FAR struct usbhost_hubport_s *hport, FAR struct usbhost_class_s **devclass) { FAR struct usb_ctrlreq_s *ctrlreq = NULL; struct usbhost_id_s id; size_t maxlen; unsigned int cfglen; uint8_t maxpacketsize; uint8_t descsize; uint8_t funcaddr = 0; FAR uint8_t *buffer = NULL; int ret; DEBUGASSERT(hport != NULL && hport->drvr != NULL); /* Allocate descriptor buffers for use in this function. We will need two: * One for the request and one for the data buffer. */ ret = DRVR_ALLOC(hport->drvr, (FAR uint8_t **)&ctrlreq, &maxlen); if (ret < 0) { udbg("DRVR_ALLOC failed: %d\n", ret); return ret; } ret = DRVR_ALLOC(hport->drvr, &buffer, &maxlen); if (ret < 0) { udbg("DRVR_ALLOC failed: %d\n", ret); goto errout; } /* Pick an appropriate packet size for this device * * USB 2.0, Paragraph 5.5.3 "Control Transfer Packet Size Constraints" * * "An endpoint for control transfers specifies the maximum data * payload size that the endpoint can accept from or transmit to * the bus. The allowable maximum control transfer data payload * sizes for full-speed devices is 8, 16, 32, or 64 bytes; for * high-speed devices, it is 64 bytes and for low-speed devices, * it is 8 bytes. This maximum applies to the data payloads of the * Data packets following a Setup..." */ if (hport->speed == USB_SPEED_HIGH) { /* For high-speed, we must use 64 bytes */ maxpacketsize = 64; descsize = USB_SIZEOF_DEVDESC; } else { /* Eight will work for both low- and full-speed */ maxpacketsize = 8; descsize = 8; } /* Configure EP0 with the initial maximum packet size */ DRVR_EP0CONFIGURE(hport->drvr, hport->ep0, 0, hport->speed, maxpacketsize); /* Read first bytes of the device descriptor */ ctrlreq->type = USB_REQ_DIR_IN | USB_REQ_RECIPIENT_DEVICE; ctrlreq->req = USB_REQ_GETDESCRIPTOR; usbhost_putle16(ctrlreq->value, (USB_DESC_TYPE_DEVICE << 8)); usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->len, descsize); ret = DRVR_CTRLIN(hport->drvr, hport->ep0, ctrlreq, buffer); if (ret < 0) { udbg("ERROR: Failed to get device descriptor, length=%d: %d\n", descsize, ret); goto errout; } /* Extract the correct max packetsize from the device descriptor */ maxpacketsize = ((struct usb_devdesc_s *)buffer)->mxpacketsize; uvdbg("maxpacksetsize: %d\n", maxpacketsize); /* And reconfigure EP0 with the correct maximum packet size */ DRVR_EP0CONFIGURE(hport->drvr, hport->ep0, 0, hport->speed, maxpacketsize); /* Now read the full device descriptor (if we have not already done so) */ if (descsize < USB_SIZEOF_DEVDESC) { ctrlreq->type = USB_REQ_DIR_IN | USB_REQ_RECIPIENT_DEVICE; ctrlreq->req = USB_REQ_GETDESCRIPTOR; usbhost_putle16(ctrlreq->value, (USB_DESC_TYPE_DEVICE << 8)); usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->len, USB_SIZEOF_DEVDESC); ret = DRVR_CTRLIN(hport->drvr, hport->ep0, ctrlreq, buffer); if (ret < 0) { udbg("ERROR: Failed to get device descriptor, length=%d: %d\n", USB_SIZEOF_DEVDESC, ret); goto errout; } } /* Get class identification information from the device descriptor. Most * devices set this to USB_CLASS_PER_INTERFACE (zero) and provide the * identification information in the interface descriptor(s). That allows * a device to support multiple, different classes. */ (void)usbhost_devdesc((struct usb_devdesc_s *)buffer, &id); /* Assign a function address to the device connected to this port */ funcaddr = usbhost_devaddr_create(hport); if (funcaddr < 0) { udbg("ERROR: usbhost_devaddr_create failed: %d\n", ret); goto errout; } /* Set the USB device address */ ctrlreq->type = USB_REQ_DIR_OUT | USB_REQ_RECIPIENT_DEVICE; ctrlreq->req = USB_REQ_SETADDRESS; usbhost_putle16(ctrlreq->value, (uint16_t)funcaddr); usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->len, 0); ret = DRVR_CTRLOUT(hport->drvr, hport->ep0, ctrlreq, NULL); if (ret < 0) { udbg("ERROR: Failed to set address: %d\n"); goto errout; } usleep(2*1000); /* Assign the function address to the port */ DEBUGASSERT(hport->funcaddr == 0 && funcaddr != 0); hport->funcaddr = funcaddr; /* And reconfigure EP0 with the correct address */ DRVR_EP0CONFIGURE(hport->drvr, hport->ep0, hport->funcaddr, hport->speed, maxpacketsize); /* Get the configuration descriptor (only), index == 0. Should not be * hard-coded! More logic is needed in order to handle devices with * multiple configurations. */ ctrlreq->type = USB_REQ_DIR_IN | USB_REQ_RECIPIENT_DEVICE; ctrlreq->req = USB_REQ_GETDESCRIPTOR; usbhost_putle16(ctrlreq->value, (USB_DESC_TYPE_CONFIG << 8)); usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->len, USB_SIZEOF_CFGDESC); ret = DRVR_CTRLIN(hport->drvr, hport->ep0, ctrlreq, buffer); if (ret < 0) { udbg("ERROR: Failed to get configuration descriptor, length=%d: %d\n", USB_SIZEOF_CFGDESC, ret); goto errout; } /* Extract the full size of the configuration data */ cfglen = (unsigned int)usbhost_getle16(((struct usb_cfgdesc_s *)buffer)->totallen); uvdbg("sizeof config data: %d\n", cfglen); /* Get all of the configuration descriptor data, index == 0 (Should not be * hard-coded!) */ ctrlreq->type = USB_REQ_DIR_IN | USB_REQ_RECIPIENT_DEVICE; ctrlreq->req = USB_REQ_GETDESCRIPTOR; usbhost_putle16(ctrlreq->value, (USB_DESC_TYPE_CONFIG << 8)); usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->len, cfglen); ret = DRVR_CTRLIN(hport->drvr, hport->ep0, ctrlreq, buffer); if (ret < 0) { udbg("ERROR: Failed to get configuration descriptor, length=%d: %d\n", cfglen, ret); goto errout; } /* Select device configuration 1 (Should not be hard-coded!) */ ctrlreq->type = USB_REQ_DIR_OUT | USB_REQ_RECIPIENT_DEVICE; ctrlreq->req = USB_REQ_SETCONFIGURATION; usbhost_putle16(ctrlreq->value, 1); usbhost_putle16(ctrlreq->index, 0); usbhost_putle16(ctrlreq->len, 0); ret = DRVR_CTRLOUT(hport->drvr, hport->ep0, ctrlreq, NULL); if (ret < 0) { udbg("ERROR: Failed to set configuration: %d\n", ret); goto errout; } /* Was the class identification information provided in the device * descriptor? Or do we need to find it in the interface descriptor(s)? */ if (id.base == USB_CLASS_PER_INTERFACE) { /* Get the class identification information for this device from the * interface descriptor(s). Hmmm.. More logic is need to handle the * case of multiple interface descriptors. */ ret = usbhost_configdesc(buffer, cfglen, &id); if (ret < 0) { udbg("ERROR: usbhost_configdesc failed: %d\n", ret); goto errout; } } /* Some devices may require some delay before initialization */ usleep(100*1000); /* Parse the configuration descriptor and bind to the class instance for the * device. This needs to be the last thing done because the class driver * will begin configuring the device. */ ret = usbhost_classbind(hport, buffer, cfglen, &id, devclass); if (ret < 0) { udbg("ERROR: usbhost_classbind failed %d\n", ret); } errout: if (ret < 0) { /* Release the device function address on any failure */ usbhost_devaddr_destroy(hport, funcaddr); hport->funcaddr = 0; } /* Release temporary buffers in any event */ if (buffer != NULL) { DRVR_FREE(hport->drvr, buffer); } if (ctrlreq) { DRVR_FREE(hport->drvr, (FAR uint8_t *)ctrlreq); } return ret; }
static FAR struct usbhost_class_s * usbhost_create(FAR struct usbhost_hubport_s *hport, FAR const struct usbhost_id_s *id) { FAR struct usbhost_hubclass_s *alloc; FAR struct usbhost_class_s *hubclass; FAR struct usbhost_hubpriv_s *priv; size_t maxlen; int port; int ret; /* Allocate a USB host class instance */ alloc = kmm_zalloc(sizeof(struct usbhost_hubclass_s)); if (alloc == NULL) { return NULL; } /* Initialize the public class structure */ hubclass = &alloc->hubclass; hubclass->hport = hport; hubclass->connect = usbhost_connect; hubclass->disconnected = usbhost_disconnected; /* Initialize the private class structure */ priv = &alloc->hubpriv; /* Allocate memory for control requests */ ret = DRVR_ALLOC(hport->drvr, (FAR uint8_t **)&priv->ctrlreq, &maxlen); if (ret < 0) { udbg("ERROR: DRVR_ALLOC failed: %d\n", ret); goto errout_with_hub; } /* Allocate buffer for status change (INT) endpoint. */ ret = DRVR_IOALLOC(hport->drvr, &priv->buffer, INTIN_BUFSIZE); if (ret < 0) { udbg("ERROR: DRVR_IOALLOC failed: %d\n", ret); goto errout_with_ctrlreq; } /* Initialize semaphores (this works okay in the interrupt context) */ sem_init(&priv->exclsem, 0, 1); /* Initialize per-port data */ for (port = 0; port < USBHUB_MAX_PORTS; port++) { FAR struct usbhost_hubport_s *child; /* Initialize the hub port descriptor */ child = &priv->hport[port]; memset(child, 0, sizeof(struct usbhost_hubport_s)); child->drvr = hport->drvr; child->parent = hport; child->port = port; child->speed = USB_SPEED_FULL; } return hubclass; errout_with_ctrlreq: kmm_free(priv->ctrlreq); errout_with_hub: kmm_free(priv); return NULL; }