int svc_to_usb(struct apbridge_dev_s *priv, void *payload, size_t len) { int ret; struct usbdev_ep_s *ep; struct usbdev_req_s *req; struct apbridge_req_s *reqcontainer; if (len > APBRIDGE_EPINTIN_MXPACKET) return -EINVAL; ep = priv->epintin; reqcontainer = &priv->intreq; req = reqcontainer->req; req->len = len; req->priv = reqcontainer; memcpy(req->buf, payload, len); /* Then submit the request to the endpoint */ ret = EP_SUBMIT(ep, req); if (ret != OK) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_SUBMITFAIL), (uint16_t) - ret); return ret; } return 0; }
int composite_ep0submit(FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_s *dev, FAR struct usbdev_req_s *ctrlreq) { /* This function is not really necessary in the current design. However, * keeping this will provide us a little flexibility in the future if * it becomes necessary to manage the completion callbacks. */ return EP_SUBMIT(dev->ep0, ctrlreq); }
static void usbclass_rdcomplete(struct usbdev_ep_s *ep, struct usbdev_req_s *req) { struct apbridge_dev_s *priv; struct apbridge_usb_driver *drv; irqstate_t flags; int ret; /* Sanity check */ #ifdef CONFIG_DEBUG if (!ep || !ep->priv || !req) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); return; } #endif /* Extract references to private data */ priv = (struct apbridge_dev_s *)ep->priv; drv = priv->driver; /* Process the received data unless this is some unusual condition */ switch (req->result) { case 0: /* Normal completion */ usbtrace(TRACE_CLASSRDCOMPLETE, 0); drv->usb_to_unipro(priv, req->buf, req->xfrd); break; case -ESHUTDOWN: /* Disconnection */ usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSHUTDOWN), 0); return; default: /* Some other error occurred */ usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDUNEXPECTED), (uint16_t) - req->result); break; }; ret = EP_SUBMIT(priv->epbulkout, req); if (ret != OK) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSUBMIT), (uint16_t) - ret); } }
void usbstrg_deferredresponse(FAR struct usbstrg_dev_s *priv, bool failed) { FAR struct usbdev_s *dev; FAR struct usbdev_req_s *ctrlreq; int ret; #ifdef CONFIG_DEBUG if (!priv || !priv->usbdev || !priv->ctrlreq) { usbtrace(TRACE_CLSERROR(USBSTRG_TRACEERR_DEFERREDRESPINVALIDARGS), 0); return; } #endif dev = priv->usbdev; ctrlreq = priv->ctrlreq; /* If no error occurs, respond to the deferred setup command with a null * packet. */ if (!failed) { ctrlreq->len = 0; ctrlreq->flags = USBDEV_REQFLAGS_NULLPKT; ret = EP_SUBMIT(dev->ep0, ctrlreq); if (ret < 0) { usbtrace(TRACE_CLSERROR(USBSTRG_TRACEERR_DEFERREDRESPSUBMIT), (uint16_t)-ret); #if 0 /* Not necessary */ ctrlreq->result = OK; usbstrg_ep0incomplete(dev->ep0, ctrlreq); #endif } } else { /* On a failure, the USB driver will stall. */ usbtrace(TRACE_DEVERROR(USBSTRG_TRACEERR_DEFERREDRESPSTALLED), 0); EP_STALL(dev->ep0); } }
static int composite_setup(FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_s *dev, FAR const struct usb_ctrlreq_s *ctrl, FAR uint8_t *dataout, size_t outlen) { FAR struct composite_dev_s *priv; FAR struct usbdev_req_s *ctrlreq; uint16_t value; uint16_t index; uint16_t len; bool dispatched = false; int ret = -EOPNOTSUPP; #ifdef CONFIG_DEBUG_FEATURES if (!driver || !dev || !dev->ep0 || !ctrl) { usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_SETUPINVALIDARGS), 0); return -EIO; } #endif /* Extract a reference to private data */ usbtrace(TRACE_CLASSSETUP, ctrl->req); priv = ((FAR struct composite_driver_s *)driver)->dev; #ifdef CONFIG_DEBUG_FEATURES if (!priv) { usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_EP0NOTBOUND2), 0); return -ENODEV; } #endif ctrlreq = priv->ctrlreq; /* Extract the little-endian 16-bit values to host order */ value = GETUINT16(ctrl->value); index = GETUINT16(ctrl->index); len = GETUINT16(ctrl->len); uinfo("type=%02x req=%02x value=%04x index=%04x len=%04x\n", ctrl->type, ctrl->req, value, index, len); UNUSED(index); if ((ctrl->type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD) { /********************************************************************** * Standard Requests **********************************************************************/ switch (ctrl->req) { case USB_REQ_GETDESCRIPTOR: { /* The value field specifies the descriptor type in the MS byte and the * descriptor index in the LS byte (order is little endian) */ switch (ctrl->value[1]) { case USB_DESC_TYPE_DEVICE: { ret = USB_SIZEOF_DEVDESC; memcpy(ctrlreq->buf, composite_getdevdesc(), ret); } break; #ifdef CONFIG_USBDEV_DUALSPEED case USB_DESC_TYPE_DEVICEQUALIFIER: { ret = USB_SIZEOF_QUALDESC; memcpy(ctrlreq->buf, composite_getqualdesc(), ret); } break; case USB_DESC_TYPE_OTHERSPEEDCONFIG: #endif case USB_DESC_TYPE_CONFIG: { #ifdef CONFIG_USBDEV_DUALSPEED ret = composite_mkcfgdesc(ctrlreq->buf, dev->speed, ctrl->value[1]); #else ret = composite_mkcfgdesc(ctrlreq->buf); #endif } break; case USB_DESC_TYPE_STRING: { /* value == string index. Zero is the language ID. */ uint8_t strid = ctrl->value[0]; FAR struct usb_strdesc_s *buf = (FAR struct usb_strdesc_s *)ctrlreq->buf; if (strid <= COMPOSITE_NSTRIDS) { ret = composite_mkstrdesc(strid, buf); } #if DEV1_NSTRIDS > 0 else if (strid <= DEV1_STRIDBASE + DEV1_NSTRIDS) { ret = DEV1_MKSTRDESC(strid, buf); } #endif #if DEV2_NSTRIDS > 0 else if (strid <= DEV2_STRIDBASE + DEV2_NSTRIDS) { ret = DEV2_MKSTRDESC(strid, buf); } #endif } break; default: { usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_GETUNKNOWNDESC), value); } break; } } break; case USB_REQ_SETCONFIGURATION: { if (ctrl->type == 0) { /* Save the configuration and inform the constituent classes */ ret = CLASS_SETUP(priv->dev1, dev, ctrl, dataout, outlen); dispatched = true; if (ret >= 0) { ret = CLASS_SETUP(priv->dev2, dev, ctrl, dataout, outlen); if (ret >= 0) { priv->config = value; } } } } break; case USB_REQ_GETCONFIGURATION: { if (ctrl->type == USB_DIR_IN) { ctrlreq->buf[0] = priv->config; ret = 1; } } break; case USB_REQ_SETINTERFACE: { if (ctrl->type == USB_REQ_RECIPIENT_INTERFACE && priv->config == COMPOSITE_CONFIGID) { ret = composite_classsetup(priv, dev, ctrl, dataout, outlen); dispatched = true; } } break; case USB_REQ_GETINTERFACE: { if (ctrl->type == (USB_DIR_IN | USB_REQ_RECIPIENT_INTERFACE) && priv->config == COMPOSITE_CONFIGIDNONE) { ret = composite_classsetup(priv, dev, ctrl, dataout, outlen); dispatched = true; } } break; default: usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_UNSUPPORTEDSTDREQ), ctrl->req); break; } } else { uint8_t recipient; /********************************************************************** * Non-Standard Class Requests **********************************************************************/ /* Class implementations should handle there own interface and endpoint * requests. */ recipient = ctrl->type & USB_REQ_RECIPIENT_MASK; if (recipient == USB_REQ_RECIPIENT_INTERFACE || recipient == USB_REQ_RECIPIENT_ENDPOINT) { ret = composite_classsetup(priv, dev, ctrl, dataout, outlen); dispatched = true; } } /* Respond to the setup command if (1) data was returned, and (2) the request was * NOT successfully dispatched to the component class driver. On an error return * value (ret < 0), the USB driver will stall EP0. */ if (ret >= 0 && !dispatched) { /* Setup the request */ ctrlreq->len = MIN(len, ret); ctrlreq->flags = USBDEV_REQFLAGS_NULLPKT; /* And submit the request to the USB controller driver */ ret = EP_SUBMIT(dev->ep0, ctrlreq); if (ret < 0) { usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_EPRESPQ), (uint16_t)-ret); ctrlreq->result = OK; composite_ep0incomplete(dev->ep0, ctrlreq); } } return ret; }
int usbmsc_setconfig(FAR struct usbmsc_dev_s *priv, uint8_t config) { FAR struct usbmsc_req_s *privreq; FAR struct usbdev_req_s *req; #ifdef CONFIG_USBDEV_DUALSPEED FAR const struct usb_epdesc_s *epdesc; bool hispeed = (priv->usbdev->speed == USB_SPEED_HIGH); #endif int i; int ret = 0; #ifdef CONFIG_DEBUG if (priv == NULL) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_SETCONFIGINVALIDARGS), 0); return -EIO; } #endif if (config == priv->config) { /* Already configured -- Do nothing */ usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_ALREADYCONFIGURED), 0); return OK; } /* Discard the previous configuration data */ usbmsc_resetconfig(priv); /* Was this a request to simply discard the current configuration? */ if (config == USBMSC_CONFIGIDNONE) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_CONFIGNONE), 0); return OK; } /* We only accept one configuration */ if (config != USBMSC_CONFIGID) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_CONFIGIDBAD), 0); return -EINVAL; } /* Configure the IN bulk endpoint */ #ifdef CONFIG_USBDEV_DUALSPEED epdesc = USBMSC_EPBULKINDESC(hispeed); ret = EP_CONFIGURE(priv->epbulkin, epdesc, false); #else ret = EP_CONFIGURE(priv->epbulkin, usbmsc_getepdesc(USBMSC_EPFSBULKIN), false); #endif if (ret < 0) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EPBULKINCONFIGFAIL), 0); goto errout; } priv->epbulkin->priv = priv; /* Configure the OUT bulk endpoint */ #ifdef CONFIG_USBDEV_DUALSPEED epdesc = USBMSC_EPBULKOUTDESC(hispeed); ret = EP_CONFIGURE(priv->epbulkout, epdesc, true); #else ret = EP_CONFIGURE(priv->epbulkout, usbmsc_getepdesc(USBMSC_EPFSBULKOUT), true); #endif if (ret < 0) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EPBULKOUTCONFIGFAIL), 0); goto errout; } priv->epbulkout->priv = priv; /* Queue read requests in the bulk OUT endpoint */ for (i = 0; i < CONFIG_USBMSC_NRDREQS; i++) { privreq = &priv->rdreqs[i]; req = privreq->req; req->len = CONFIG_USBMSC_BULKOUTREQLEN; req->priv = privreq; req->callback = usbmsc_rdcomplete; ret = EP_SUBMIT(priv->epbulkout, req); if (ret < 0) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_RDSUBMIT), (uint16_t)-ret); goto errout; } } priv->config = config; return OK; errout: usbmsc_resetconfig(priv); return ret; }
static int usbmsc_setup(FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_s *dev, FAR const struct usb_ctrlreq_s *ctrl, FAR uint8_t *dataout, size_t outlen) { FAR struct usbmsc_dev_s *priv; FAR struct usbdev_req_s *ctrlreq; uint16_t value; uint16_t index; uint16_t len; int ret = -EOPNOTSUPP; #ifdef CONFIG_DEBUG if (!driver || !dev || !dev->ep0 || !ctrl) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_SETUPINVALIDARGS), 0); return -EIO; } #endif /* Extract reference to private data */ usbtrace(TRACE_CLASSSETUP, ctrl->req); priv = ((FAR struct usbmsc_driver_s *)driver)->dev; #ifdef CONFIG_DEBUG if (!priv || !priv->ctrlreq) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EP0NOTBOUND2), 0); return -ENODEV; } #endif ctrlreq = priv->ctrlreq; /* Extract the little-endian 16-bit values to host order */ value = GETUINT16(ctrl->value); index = GETUINT16(ctrl->index); len = GETUINT16(ctrl->len); uvdbg("type=%02x req=%02x value=%04x index=%04x len=%04x\n", ctrl->type, ctrl->req, value, index, len); if ((ctrl->type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD) { /********************************************************************** * Standard Requests **********************************************************************/ switch (ctrl->req) { case USB_REQ_GETDESCRIPTOR: { /* The value field specifies the descriptor type in the MS byte and the * descriptor index in the LS byte (order is little endian) */ switch (ctrl->value[1]) { /* If the mass storage device is used in as part of a composite * device, then the device descriptor is is provided by logic * in the composite device implementation. */ #ifndef CONFIG_USBMSC_COMPOSITE case USB_DESC_TYPE_DEVICE: { ret = USB_SIZEOF_DEVDESC; memcpy(ctrlreq->buf, usbmsc_getdevdesc(), ret); } break; #endif /* If the mass storage device is used in as part of a composite device, * then the device qualifier descriptor is provided by logic in the * composite device implementation. */ #if !defined(CONFIG_USBMSC_COMPOSITE) && defined(CONFIG_USBDEV_DUALSPEED) case USB_DESC_TYPE_DEVICEQUALIFIER: { ret = USB_SIZEOF_QUALDESC; memcpy(ctrlreq->buf, usbmsc_getqualdesc(), ret); } break; case USB_DESC_TYPE_OTHERSPEEDCONFIG: #endif /* If the mass storage device is used in as part of a composite device, * then the configuration descriptor is provided by logic in the * composite device implementation. */ #ifndef CONFIG_USBMSC_COMPOSITE case USB_DESC_TYPE_CONFIG: { #ifdef CONFIG_USBDEV_DUALSPEED ret = usbmsc_mkcfgdesc(ctrlreq->buf, dev->speed, ctrl->value[1]); #else ret = usbmsc_mkcfgdesc(ctrlreq->buf); #endif } break; #endif /* If the mass storage device is used in as part of a composite device, * then the language string descriptor is provided by logic in the * composite device implementation. */ #ifndef CONFIG_USBMSC_COMPOSITE case USB_DESC_TYPE_STRING: { /* index == language code. */ ret = usbmsc_mkstrdesc(ctrl->value[0], (struct usb_strdesc_s *)ctrlreq->buf); } break; #endif default: { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_GETUNKNOWNDESC), value); } break; } } break; case USB_REQ_SETCONFIGURATION: { if (ctrl->type == 0) { /* Signal the worker thread to instantiate the new configuration */ priv->theventset |= USBMSC_EVENT_CFGCHANGE; priv->thvalue = value; usbmsc_scsi_signal(priv); /* Return here... the response will be provided later by the * worker thread. */ return OK; } } break; /* If the mass storage device is used in as part of a composite device, * then the overall composite class configuration is managed by logic * in the composite device implementation. */ #ifndef CONFIG_USBMSC_COMPOSITE case USB_REQ_GETCONFIGURATION: { if (ctrl->type == USB_DIR_IN) { ctrlreq->buf[0] = priv->config; ret = 1; } } break; #endif case USB_REQ_SETINTERFACE: { if (ctrl->type == USB_REQ_RECIPIENT_INTERFACE) { if (priv->config == USBMSC_CONFIGID && index == USBMSC_INTERFACEID && value == USBMSC_ALTINTERFACEID) { /* Signal to instantiate the interface change */ priv->theventset |= USBMSC_EVENT_IFCHANGE; usbmsc_scsi_signal(priv); /* Return here... the response will be provided later by the * worker thread. */ return OK; } } } break; case USB_REQ_GETINTERFACE: { if (ctrl->type == (USB_DIR_IN | USB_REQ_RECIPIENT_INTERFACE) && priv->config == USBMSC_CONFIGIDNONE) { if (index != USBMSC_INTERFACEID) { ret = -EDOM; } else { ctrlreq->buf[0] = USBMSC_ALTINTERFACEID; ret = 1; } } } break; default: usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_UNSUPPORTEDSTDREQ), ctrl->req); break; } } else if ((ctrl->type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_CLASS) { /********************************************************************** * Bulk-Only Mass Storage Class Requests **********************************************************************/ /* Verify that we are configured */ if (!priv->config) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_NOTCONFIGURED), 0); return ret; } switch (ctrl->req) { case USBMSC_REQ_MSRESET: { /* Reset mass storage device and interface */ if (ctrl->type == USBMSC_TYPE_SETUPOUT && value == 0 && len == 0) { /* Only one interface is supported */ if (index != USBMSC_INTERFACEID) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_MSRESETNDX), index); ret = -EDOM; } else { /* Signal to stop the current operation and reinitialize state */ priv->theventset |= USBMSC_EVENT_RESET; usbmsc_scsi_signal(priv); /* Return here... the response will be provided later by the * worker thread. */ return OK; } } } break; case USBMSC_REQ_GETMAXLUN: { /* Return number LUNs supported */ if (ctrl->type == USBMSC_TYPE_SETUPIN && value == 0 && len == 1) { /* Only one interface is supported */ if (index != USBMSC_INTERFACEID) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_GETMAXLUNNDX), index); ret = -EDOM; } else { ctrlreq->buf[0] = priv->nluns - 1; ret = 1; } } } break; default: usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_BADREQUEST), ctrl->req); break; } } else { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_UNSUPPORTEDTYPE), ctrl->type); } /* Respond to the setup command if data was returned. On an error return * value (ret < 0), the USB driver will stall EP0. */ if (ret >= 0) { /* Configure the response */ ctrlreq->len = MIN(len, ret); ctrlreq->flags = USBDEV_REQFLAGS_NULLPKT; /* Send the response -- either directly to the USB controller or * indirectly in the case where this class is a member of a composite * device. */ #ifndef CONFIG_USBMSC_COMPOSITE ret = EP_SUBMIT(dev->ep0, ctrlreq); #else ret = composite_ep0submit(driver, dev, ctrlreq); #endif if (ret < 0) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EPRESPQ), (uint16_t)-ret); #if 0 /* Not necessary */ ctrlreq->result = OK; usbmsc_ep0incomplete(dev->ep0, ctrlreq); #endif } } return ret; }
void usbmsc_rdcomplete(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req) { FAR struct usbmsc_dev_s *priv; FAR struct usbmsc_req_s *privreq; irqstate_t flags; int ret; /* Sanity check */ #ifdef CONFIG_DEBUG if (!ep || !ep->priv || !req || !req->priv) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_RDCOMPLETEINVALIDARGS), 0); return; } #endif /* Extract references to private data */ priv = (FAR struct usbmsc_dev_s *)ep->priv; privreq = (FAR struct usbmsc_req_s *)req->priv; /* Process the received data unless this is some unusual condition */ switch (req->result) { case 0: { /* Normal completion */ usbtrace(TRACE_CLASSRDCOMPLETE, req->xfrd); /* Add the filled read request from the rdreqlist */ flags = irqsave(); sq_addlast((FAR sq_entry_t *)privreq, &priv->rdreqlist); irqrestore(flags); /* Signal the worker thread that there is received data to be processed */ priv->theventset |= USBMSC_EVENT_RDCOMPLETE; usbmsc_scsi_signal(priv); } break; case -ESHUTDOWN: { /* Disconnection */ usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_RDSHUTDOWN), 0); /* Drop the read request... it will be cleaned up later */ } break; default: { /* Some other error occurred */ usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_RDUNEXPECTED), (uint16_t)-req->result); /* Return the read request to the bulk out endpoint for re-filling */ req = privreq->req; req->priv = privreq; req->callback = usbmsc_rdcomplete; ret = EP_SUBMIT(priv->epbulkout, req); if (ret != OK) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_RDCOMPLETERDSUBMIT), (uint16_t)-ret); } } break; } }
static int usbclass_setconfig(struct apbridge_dev_s *priv, uint8_t config) { struct usbdev_req_s *req; struct usb_epdesc_s epdesc; uint16_t mxpacket; // int i; int ret = 0; #if CONFIG_DEBUG if (priv == NULL) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); return -EIO; } #endif if (config == priv->config) { /* Already configured -- Do nothing */ usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_ALREADYCONFIGURED), 0); return 0; } /* Discard the previous configuration data */ usbclass_resetconfig(priv); /* Was this a request to simply discard the current configuration? */ if (config == APBRIDGE_CONFIGIDNONE) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_CONFIGNONE), 0); return 0; } /* We only accept one configuration */ if (config != APBRIDGE_CONFIGID) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_CONFIGIDBAD), 0); return -EINVAL; } /* Configure the IN interrupt endpoint */ if (priv->usbdev->speed == USB_SPEED_HIGH) { mxpacket = APBRIDGE_EPINTIN_MXPACKET; } else { mxpacket = 64; } usbclass_mkepdesc(&g_epintindesc, mxpacket, &epdesc); ret = EP_CONFIGURE(priv->epintin, &epdesc, false); if (ret < 0) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPINTINCONFIGFAIL), 0); goto errout; } priv->epintin->priv = priv; /* Configure the IN bulk endpoint */ if (priv->usbdev->speed == USB_SPEED_HIGH) { mxpacket = APBRIDGE_BULK_MXPACKET; } else { mxpacket = 64; } usbclass_mkepdesc(&g_epbulkindesc, mxpacket, &epdesc); ret = EP_CONFIGURE(priv->epbulkin, &epdesc, false); if (ret < 0) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPBULKINCONFIGFAIL), 0); goto errout; } priv->epbulkin->priv = priv; /* Configure the OUT bulk endpoint */ usbclass_mkepdesc(&g_epbulkoutdesc, mxpacket, &epdesc); ret = EP_CONFIGURE(priv->epbulkout, &epdesc, true); if (ret < 0) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPBULKOUTCONFIGFAIL), 0); goto errout; } priv->epbulkout->priv = priv; /* Queue read requests in the bulk OUT endpoint */ req = priv->rdreq.req; req->callback = usbclass_rdcomplete; ret = EP_SUBMIT(priv->epbulkout, priv->rdreq.req); if (ret != OK) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSUBMIT), (uint16_t) - ret); goto errout; } /* We are successfully configured */ priv->config = config; return OK; errout: usbclass_resetconfig(priv); return ret; }
static int usbclass_setup(struct usbdevclass_driver_s *driver, struct usbdev_s *dev, const struct usb_ctrlreq_s *ctrl, uint8_t * dataout, size_t outlen) { struct apbridge_dev_s *priv; struct usbdev_req_s *ctrlreq; uint16_t value; uint16_t index; uint16_t len; int ret = -EOPNOTSUPP; #ifdef CONFIG_DEBUG if (!driver || !dev || !dev->ep0 || !ctrl) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); return -EIO; } #endif /* Extract reference to private data */ usbtrace(TRACE_CLASSSETUP, ctrl->req); priv = ((struct apbridge_driver_s *)driver)->dev; #ifdef CONFIG_DEBUG if (!priv || !priv->ctrlreq) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EP0NOTBOUND), 0); return -ENODEV; } #endif ctrlreq = priv->ctrlreq; ctrlreq->priv = (void *)USB_REQ; /* Extract the little-endian 16-bit values to host order */ value = GETUINT16(ctrl->value); index = GETUINT16(ctrl->index); len = GETUINT16(ctrl->len); uvdbg("type=%02x req=%02x value=%04x index=%04x len=%04x\n", ctrl->type, ctrl->req, value, index, len); switch (ctrl->type & USB_REQ_TYPE_MASK) { /*********************************************************************** * Standard Requests ***********************************************************************/ case USB_REQ_TYPE_STANDARD: { switch (ctrl->req) { case USB_REQ_GETDESCRIPTOR: { /* The value field specifies the descriptor type in the MS byte and the * descriptor index in the LS byte (order is little endian) */ switch (ctrl->value[1]) { case USB_DESC_TYPE_DEVICE: { ret = USB_SIZEOF_DEVDESC; memcpy(ctrlreq->buf, &g_devdesc, ret); } break; case USB_DESC_TYPE_DEVICEQUALIFIER: { ret = USB_SIZEOF_QUALDESC; memcpy(ctrlreq->buf, &g_qualdesc, ret); } break; case USB_DESC_TYPE_OTHERSPEEDCONFIG: case USB_DESC_TYPE_CONFIG: { ret = usbclass_mkcfgdesc(ctrlreq->buf, dev->speed, ctrl->req); } break; case USB_DESC_TYPE_STRING: { /* index == language code. */ ret = usbclass_mkstrdesc(ctrl->value[0], (struct usb_strdesc_s *) ctrlreq->buf); } break; default: { usbtrace(TRACE_CLSERROR (USBSER_TRACEERR_GETUNKNOWNDESC), value); } break; } } break; case USB_REQ_SETCONFIGURATION: { if (ctrl->type == 0) { ret = usbclass_setconfig(priv, value); } } break; case USB_REQ_GETCONFIGURATION: { if (ctrl->type == USB_DIR_IN) { *(uint8_t *) ctrlreq->buf = priv->config; ret = 1; } } break; case USB_REQ_SETINTERFACE: { if (ctrl->type == USB_REQ_RECIPIENT_INTERFACE) { if (priv->config == APBRIDGE_CONFIGID && index == APBRIDGE_INTERFACEID && value == APBRIDGE_ALTINTERFACEID) { usbclass_resetconfig(priv); usbclass_setconfig(priv, priv->config); ret = 0; } } } break; case USB_REQ_GETINTERFACE: { if (ctrl->type == (USB_DIR_IN | USB_REQ_RECIPIENT_INTERFACE) && priv->config == APBRIDGE_CONFIGIDNONE) { if (index != APBRIDGE_INTERFACEID) { ret = -EDOM; } else { *(uint8_t *) ctrlreq->buf = APBRIDGE_ALTINTERFACEID; ret = 1; } } } break; default: usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDSTDREQ), ctrl->req); break; } } break; /* Put here vendor request */ case USB_REQ_TYPE_VENDOR: { if ((ctrl->type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_INTERFACE) { if (ctrl->req == APBRIDGE_RWREQUEST_SVC) { if ((ctrl->type & USB_DIR_IN) != 0) { *(uint32_t *) ctrlreq->buf = 0xdeadbeef; ret = 4; } else { ctrlreq->priv = (void *)GREYBUS_SVC_REQ; ret = len; } } else if (ctrl->req == APBRIDGE_RWREQUEST_LOG) { if ((ctrl->type & USB_DIR_IN) == 0) { } else { #if defined(CONFIG_APB_USB_LOG) ctrlreq->priv = (void *)GREYBUS_LOG; ret = usb_get_log(ctrlreq->buf, len); #else ret = 0; #endif } } else { usbtrace(TRACE_CLSERROR (USBSER_TRACEERR_UNSUPPORTEDCLASSREQ), ctrl->type); } } } break; default: usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDTYPE), ctrl->type); break; } /* Respond to the setup command if data was returned. On an error return * value (ret < 0), the USB driver will stall. */ if (ret >= 0) { ctrlreq->len = min(len, ret); ctrlreq->flags = USBDEV_REQFLAGS_NULLPKT; ret = EP_SUBMIT(dev->ep0, ctrlreq); if (ret < 0) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPRESPQ), (uint16_t) - ret); ctrlreq->result = OK; usbclass_ep0incomplete(dev->ep0, ctrlreq); } } return ret; }