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 }
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 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); } }