FAR void *composite_initialize(void) { FAR struct composite_alloc_s *alloc; FAR struct composite_dev_s *priv; FAR struct composite_driver_s *drvr; int ret; /* Allocate the structures needed */ alloc = (FAR struct composite_alloc_s *)kmm_malloc(sizeof(struct composite_alloc_s)); if (!alloc) { usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_ALLOCDEVSTRUCT), 0); return NULL; } /* Convenience pointers into the allocated blob */ priv = &alloc->dev; drvr = &alloc->drvr; /* Initialize the USB composite driver structure */ memset(priv, 0, sizeof(struct composite_dev_s)); /* Get the constitueat class driver objects */ ret = DEV1_CLASSOBJECT(&priv->dev1); if (ret < 0) { usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_CLASSOBJECT), (uint16_t)-ret); goto errout_with_alloc; } ret = DEV2_CLASSOBJECT(&priv->dev2); if (ret < 0) { usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_CLASSOBJECT), (uint16_t)-ret); goto errout_with_alloc; } /* Initialize the USB class driver structure */ #ifdef CONFIG_USBDEV_DUALSPEED drvr->drvr.speed = USB_SPEED_HIGH; #else drvr->drvr.speed = USB_SPEED_FULL; #endif drvr->drvr.ops = &g_driverops; drvr->dev = priv; /* Register the USB composite class driver */ ret = usbdev_register(&drvr->drvr); if (ret) { usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_DEVREGISTER), (uint16_t)-ret); goto errout_with_alloc; } return (FAR void *)alloc; errout_with_alloc: kmm_free(alloc); return NULL; }
int stm32_usbpullup(FAR struct usbdev_s *dev, bool enable) { usbtrace(TRACE_DEVPULLUP, (uint16_t)enable); stm32_gpiowrite(GPIO_USB_PULLUP, !enable); return OK; }
static int composite_bind(FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_s *dev) { FAR struct composite_dev_s *priv = ((FAR struct composite_driver_s *)driver)->dev; int ret; usbtrace(TRACE_CLASSBIND, 0); /* Bind the structures */ priv->usbdev = dev; /* Save the reference to our private data structure in EP0 so that it * can be recovered in ep0 completion events. */ dev->ep0->priv = priv; /* Preallocate one control request */ priv->ctrlreq = composite_allocreq(dev->ep0, COMPOSITE_CFGDESCSIZE); if (priv->ctrlreq == NULL) { usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_ALLOCCTRLREQ), 0); ret = -ENOMEM; goto errout; } /* Initialize the pre-allocated control request */ priv->ctrlreq->callback = composite_ep0incomplete; /* Then bind each of the constituent class drivers */ ret = CLASS_BIND(priv->dev1, dev); if (ret < 0) { goto errout; } ret = CLASS_BIND(priv->dev2, dev); if (ret < 0) { goto errout; } /* Report if we are selfpowered */ #ifdef CONFIG_USBDEV_SELFPOWERED DEV_SETSELFPOWERED(dev); #endif /* And pull-up the data line for the soft connect function */ DEV_CONNECT(dev); return OK; errout: composite_unbind(driver, dev); return ret; }
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 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 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); uvdbg("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; }
int kinetis_usbpullup(FAR struct usbdev_s *dev, bool enable) { usbtrace(TRACE_DEVPULLUP, (uint16_t)enable); # warning "Missing logic" return OK; }
static int usbclass_bind(struct usbdevclass_driver_s *driver, struct usbdev_s *dev) { struct apbridge_dev_s *priv = ((struct apbridge_driver_s *)driver)->dev; struct apbridge_req_s *reqcontainer; int ret; usbtrace(TRACE_CLASSBIND, 0); /* Bind the structures */ priv->usbdev = dev; /* Save the reference to our private data structure in EP0 so that it * can be recovered in ep0 completion events (Unless we are part of * a composite device and, in that case, the composite device owns * EP0). */ dev->ep0->priv = priv; /* Preallocate control request */ priv->ctrlreq = usbclass_allocreq(dev->ep0, APBRIDGE_MXDESCLEN); if (priv->ctrlreq == NULL) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_ALLOCCTRLREQ), 0); ret = -ENOMEM; goto errout; } priv->ctrlreq->callback = usbclass_ep0incomplete; /* Pre-allocate all endpoints... the endpoints will not be functional * until the SET CONFIGURATION request is processed in usbclass_setconfig. * This is done here because there may be calls to kmm_malloc and the SET * CONFIGURATION processing probably occurrs within interrupt handling * logic where kmm_malloc calls will fail. */ /* Pre-allocate the IN interrupt endpoint */ priv->epintin = DEV_ALLOCEP(dev, APBRIDGE_EPINTIN_ADDR, true, USB_EP_ATTR_XFER_INT); if (!priv->epintin) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPINTINALLOCFAIL), 0); ret = -ENODEV; goto errout; } priv->epintin->priv = priv; /* Pre-allocate the IN bulk endpoint */ priv->epbulkin = DEV_ALLOCEP(dev, APBRIDGE_EPINBULK_ADDR, true, USB_EP_ATTR_XFER_BULK); if (!priv->epbulkin) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPBULKINALLOCFAIL), 0); ret = -ENODEV; goto errout; } priv->epbulkin->priv = priv; /* Pre-allocate the OUT bulk endpoint */ priv->epbulkout = DEV_ALLOCEP(dev, APBRIDGE_EPOUTBULK_ADDR, false, USB_EP_ATTR_XFER_BULK); if (!priv->epbulkout) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPBULKOUTALLOCFAIL), 0); ret = -ENODEV; goto errout; } priv->epbulkout->priv = priv; reqcontainer = &priv->intreq; reqcontainer->req = usbclass_allocreq(priv->epintin, APBRIDGE_EPINTIN_MXPACKET); reqcontainer->req->priv = reqcontainer; reqcontainer->req->callback = usbclass_intcomplete; reqcontainer = &priv->rdreq; reqcontainer->req = usbclass_allocreq(priv->epbulkout, APBRIDGE_BULK_MXPACKET); reqcontainer->req->priv = reqcontainer; reqcontainer->req->callback = usbclass_rdcomplete; reqcontainer = &priv->wrreq; reqcontainer->req = usbclass_allocreq(priv->epbulkin, APBRIDGE_BULK_MXPACKET); reqcontainer->req->priv = reqcontainer; reqcontainer->req->callback = usbclass_wrcomplete; /* Report if we are selfpowered */ #ifdef CONFIG_USBDEV_SELFPOWERED DEV_SETSELFPOWERED(dev); #endif /* And pull-up the data line for the soft connect function */ DEV_CONNECT(dev); return OK; errout: /* * One endpoint allocation fail. * Release the endpoints which were allocated. */ usbclass_unbind(driver, dev); return ret; }
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; }
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; }
static void usbclass_unbind(struct usbdevclass_driver_s *driver, struct usbdev_s *dev) { struct apbridge_dev_s *priv; usbtrace(TRACE_CLASSUNBIND, 0); #ifdef CONFIG_DEBUG if (!driver || !dev || !dev->ep0) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0); return; } #endif /* Extract reference to private data */ priv = ((struct apbridge_driver_s *)driver)->dev; #ifdef CONFIG_DEBUG if (!priv) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EP0NOTBOUND), 0); return; } #endif /* 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 usbclass_resetconfig * should cause the endpoints to immediately terminate all * transfers and return the requests to us (with result == -ESHUTDOWN) */ usbclass_resetconfig(priv); up_mdelay(50); /* Free the interrupt IN endpoint */ if (priv->epintin) { DEV_FREEEP(dev, priv->epintin); priv->epintin = NULL; } /* Free the bulk IN endpoint */ if (priv->epbulkin) { DEV_FREEEP(dev, priv->epbulkin); priv->epbulkin = NULL; } /* Free the pre-allocated control request */ if (priv->ctrlreq != NULL) { usbclass_freereq(dev->ep0, priv->ctrlreq); priv->ctrlreq = NULL; } /* Free the bulk OUT endpoint */ if (priv->epbulkout) { DEV_FREEEP(dev, priv->epbulkout); priv->epbulkout = NULL; } } }