static void usbmsc_disconnect(FAR struct usbdevclass_driver_s *driver,
                              FAR struct usbdev_s *dev)
{
  struct usbmsc_dev_s *priv;
  irqstate_t flags;

  usbtrace(TRACE_CLASSDISCONNECT, 0);

#ifdef CONFIG_DEBUG
  if (!driver || !dev || !dev->ep0)
    {
      usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_DISCONNECTINVALIDARGS), 0);
      return;
     }
#endif

  /* Extract reference to private data */

  priv = ((FAR struct usbmsc_driver_s *)driver)->dev;

#ifdef CONFIG_DEBUG
  if (!priv)
    {
      usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EP0NOTBOUND3), 0);
      return;
    }
#endif

  /* Reset the configuration */

  flags = irqsave();
  usbmsc_resetconfig(priv);

  /* Signal the worker thread */

  priv->theventset |= USBMSC_EVENT_DISCONNECT;
  pthread_cond_signal(&priv->cond);
  irqrestore(flags);

  /* Perform the soft connect function so that we will we can be
   * re-enumerated (unless we are part of a composite device)
   */

#ifndef CONFIG_USBMSC_COMPOSITE
  DEV_CONNECT(dev);
#endif
}
Пример #2
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;
}
Пример #3
0
static void usbmsc_unbind(FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_s *dev)
{
	FAR struct usbmsc_dev_s *priv;
	FAR struct usbmsc_req_s *reqcontainer;
	irqstate_t flags;
	int i;

	usbtrace(TRACE_CLASSUNBIND, 0);

#ifdef CONFIG_DEBUG
	if (!driver || !dev || !dev->ep0) {
		usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_UNBINDINVALIDARGS), 0);
		return;
	}
#endif

	/* Extract reference to private data */

	priv = ((FAR struct usbmsc_driver_s *)driver)->dev;

#ifdef CONFIG_DEBUG
	if (!priv) {
		usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EP0NOTBOUND1), 0);
		return;
	}
#endif

	/* The worker thread should have already been stopped by the
	 * driver un-initialize logic.
	 */

	DEBUGASSERT(priv->thstate == USBMSC_STATE_TERMINATED || priv->thstate == USBMSC_STATE_NOTSTARTED);

	/* Make sure that we are not already unbound */

	if (priv != NULL) {
		/* Make sure that the endpoints have been unconfigured.  If
		 * we were terminated gracefully, then the configuration should
		 * already have been reset.  If not, then calling usbmsc_resetconfig
		 * should cause the endpoints to immediately terminate all
		 * transfers and return the requests to us (with result == -ESHUTDOWN)
		 */

		usbmsc_resetconfig(priv);
		up_mdelay(50);

		/* Free the pre-allocated control request */

		if (priv->ctrlreq != NULL) {
			usbmsc_freereq(dev->ep0, priv->ctrlreq);
			priv->ctrlreq = NULL;
		}

		/* Free pre-allocated read requests (which should all have
		 * been returned to the free list at this time -- we don't check)
		 */

		for (i = 0; i < CONFIG_USBMSC_NRDREQS; i++) {
			reqcontainer = &priv->rdreqs[i];
			if (reqcontainer->req) {
				usbmsc_freereq(priv->epbulkout, reqcontainer->req);
				reqcontainer->req = NULL;
			}
		}

		/* Free the bulk OUT endpoint */

		if (priv->epbulkout) {
			DEV_FREEEP(dev, priv->epbulkout);
			priv->epbulkout = NULL;
		}

		/* Free write requests that are not in use (which should be all
		 * of them
		 */

		flags = irqsave();
		while (!sq_empty(&priv->wrreqlist)) {
			reqcontainer = (struct usbmsc_req_s *)sq_remfirst(&priv->wrreqlist);
			if (reqcontainer->req != NULL) {
				usbmsc_freereq(priv->epbulkin, reqcontainer->req);
			}
		}

		/* Free the bulk IN endpoint */

		if (priv->epbulkin) {
			DEV_FREEEP(dev, priv->epbulkin);
			priv->epbulkin = NULL;
		}

		irqrestore(flags);
	}
}