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);
    }
}
Beispiel #2
0
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;
}