void usbmsc_deferredresponse(FAR struct usbmsc_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(USBMSC_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(USBMSC_TRACEERR_DEFERREDRESPSUBMIT), (uint16_t)-ret); #if 0 /* Not necessary */ ctrlreq->result = OK; usbmsc_ep0incomplete(dev->ep0, ctrlreq); #endif } } else { /* On a failure, the USB driver will stall. */ usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_DEFERREDRESPSTALLED), 0); EP_STALL(dev->ep0); } }
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; }