Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
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);
}
Ejemplo n.º 3
0
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);
    }
}
Ejemplo n.º 4
0
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);
    }
}
Ejemplo n.º 5
0
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;
}
Ejemplo n.º 6
0
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;
}
Ejemplo n.º 7
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;
}
Ejemplo n.º 8
0
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;
	}
}
Ejemplo n.º 9
0
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;
}
Ejemplo n.º 10
0
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;
}