From 08964a35b2e643e96232a8de0dbdccd6e06adbe2 Mon Sep 17 00:00:00 2001 From: patacongo Date: Wed, 25 Jan 2012 19:27:20 +0000 Subject: [PATCH] Progress toward composite CDC/ACM+MSC USB device git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@4332 7fd9a85b-ad96-42d3-883c-3090e2eb8679 --- nuttx/drivers/usbdev/cdcacm.c | 179 ++++-- nuttx/drivers/usbdev/cdcacm.h | 44 +- nuttx/drivers/usbdev/cdcacm_descriptors.c | 8 +- nuttx/drivers/usbdev/composite.c | 623 +++++++++++++++++-- nuttx/drivers/usbdev/composite.h | 134 +++- nuttx/drivers/usbdev/composite_descriptors.c | 117 +--- nuttx/drivers/usbdev/msc.c | 74 ++- nuttx/drivers/usbdev/msc.h | 50 +- nuttx/drivers/usbdev/msc_descriptors.c | 6 +- nuttx/drivers/usbdev/msc_scsi.c | 18 +- nuttx/include/nuttx/usb/cdc_serial.h | 44 ++ nuttx/include/nuttx/usb/usbdev.h | 51 +- nuttx/include/nuttx/usb/usbdev_trace.h | 19 + 13 files changed, 1086 insertions(+), 281 deletions(-) diff --git a/nuttx/drivers/usbdev/cdcacm.c b/nuttx/drivers/usbdev/cdcacm.c index 9c6c366252..c203d54155 100644 --- a/nuttx/drivers/usbdev/cdcacm.c +++ b/nuttx/drivers/usbdev/cdcacm.c @@ -99,7 +99,7 @@ struct cdcser_dev_s FAR struct usbdev_ep_s *epintin; /* Interrupt IN endpoint structure */ FAR struct usbdev_ep_s *epbulkin; /* Bulk IN endpoint structure */ FAR struct usbdev_ep_s *epbulkout; /* Bulk OUT endpoint structure */ - FAR struct usbdev_req_s *ctrlreq; /* Control request */ + FAR struct usbdev_req_s *ctrlreq; /* Allocoated control request */ struct sq_queue_s reqlist; /* List of write request containers */ /* Pre-allocated write request containers. The write requests will @@ -158,10 +158,8 @@ static void cdcser_resetconfig(FAR struct cdcser_dev_s *priv); static int cdcser_epconfigure(FAR struct usbdev_ep_s *ep, enum cdcser_epdesc_e epid, uint16_t mxpacket, bool last); #endif -#ifndef CONFIG_CDCSER_COMPOSITE static int cdcser_setconfig(FAR struct cdcser_dev_s *priv, uint8_t config); -#endif /* Completion event handlers ***********************************************/ @@ -591,7 +589,6 @@ static int cdcser_epconfigure(FAR struct usbdev_ep_s *ep, * ****************************************************************************/ -#ifndef CONFIG_CDCSER_COMPOSITE static int cdcser_setconfig(FAR struct cdcser_dev_s *priv, uint8_t config) { FAR struct usbdev_req_s *req; @@ -725,7 +722,6 @@ errout: cdcser_resetconfig(priv); return ret; } -#endif /**************************************************************************** * Name: cdcser_ep0incomplete @@ -798,7 +794,7 @@ static void cdcser_rdcomplete(FAR struct usbdev_ep_s *ep, /* Requeue the read request */ #ifdef CONFIG_CDCSER_BULKREQLEN - req->len = max(CONFIG_CDCSER_BULKREQLEN, ep->maxpacket); + req->len = MAX(CONFIG_CDCSER_BULKREQLEN, ep->maxpacket); #else req->len = ep->maxpacket; #endif @@ -952,7 +948,7 @@ static int cdcser_bind(FAR struct usbdev_s *dev, FAR struct usbdevclass_driver_s /* Pre-allocate read requests */ #ifdef CONFIG_CDCSER_BULKREQLEN - reqlen = max(CONFIG_CDCSER_BULKREQLEN, priv->epbulkout->maxpacket); + reqlen = MAX(CONFIG_CDCSER_BULKREQLEN, priv->epbulkout->maxpacket); #else reqlen = priv->epbulkout->maxpacket; #endif @@ -974,7 +970,7 @@ static int cdcser_bind(FAR struct usbdev_s *dev, FAR struct usbdevclass_driver_s /* Pre-allocate write request containers and put in a free list */ #ifdef CONFIG_CDCSER_BULKREQLEN - reqlen = max(CONFIG_CDCSER_BULKREQLEN, priv->epbulkin->maxpacket); + reqlen = MAX(CONFIG_CDCSER_BULKREQLEN, priv->epbulkin->maxpacket); #else reqlen = priv->epbulkin->maxpacket; #endif @@ -998,15 +994,19 @@ static int cdcser_bind(FAR struct usbdev_s *dev, FAR struct usbdevclass_driver_s irqrestore(flags); } - /* Report if we are selfpowered */ + /* Report if we are selfpowered (unless we are part of a composite device) */ +#ifndef CONFIG_CDCSER_COMPOSITE #ifdef CONFIG_USBDEV_SELFPOWERED DEV_SETSELFPOWERED(dev); #endif - /* And pull-up the data line for the soft connect function */ + /* And pull-up the data line for the soft connect function (unless we are + * part of a composite device) + */ DEV_CONNECT(dev); +#endif return OK; errout: @@ -1194,14 +1194,6 @@ static int cdcser_setup(FAR struct usbdev_s *dev, const struct usb_ctrlreq_s *ct case USB_REQ_TYPE_STANDARD: { - /* If the serial device is used in as part of a composite device, - * then standard descriptors are handled by logic in the composite - * device logic. - */ - -#ifdef CONFIG_CDCSER_COMPOSITE - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDSTDREQ), ctrl->req); -#else switch (ctrl->req) { case USB_REQ_GETDESCRIPTOR: @@ -1212,14 +1204,26 @@ static int cdcser_setup(FAR struct usbdev_s *dev, const struct usb_ctrlreq_s *ct switch (ctrl->value[1]) { + /* If the serial device is used in as part of a composite device, + * then the device descriptor is provided by logic in the composite + * device implementation. + */ + +#ifndef CONFIG_CDCSER_COMPOSITE case USB_DESC_TYPE_DEVICE: { ret = USB_SIZEOF_DEVDESC; memcpy(ctrlreq->buf, cdcser_getdevdesc(), ret); } break; +#endif -#ifdef CONFIG_USBDEV_DUALSPEED + /* If the serial 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_CDCSER_COMPOSITE) && defined(CONFIG_USBDEV_DUALSPEED) case USB_DESC_TYPE_DEVICEQUALIFIER: { ret = USB_SIZEOF_QUALDESC; @@ -1228,8 +1232,14 @@ static int cdcser_setup(FAR struct usbdev_s *dev, const struct usb_ctrlreq_s *ct break; case USB_DESC_TYPE_OTHERSPEEDCONFIG: -#endif /* CONFIG_USBDEV_DUALSPEED */ +#endif + /* If the serial 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_CDCSER_COMPOSITE case USB_DESC_TYPE_CONFIG: { #ifdef CONFIG_USBDEV_DUALSPEED @@ -1239,7 +1249,14 @@ static int cdcser_setup(FAR struct usbdev_s *dev, const struct usb_ctrlreq_s *ct #endif } break; +#endif + /* If the serial 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_CDCSER_COMPOSITE case USB_DESC_TYPE_STRING: { /* index == language code. */ @@ -1247,6 +1264,7 @@ static int cdcser_setup(FAR struct usbdev_s *dev, const struct usb_ctrlreq_s *ct ret = cdcser_mkstrdesc(ctrl->value[0], (struct usb_strdesc_s *)ctrlreq->buf); } break; +#endif default: { @@ -1266,6 +1284,12 @@ static int cdcser_setup(FAR struct usbdev_s *dev, const struct usb_ctrlreq_s *ct } break; + /* If the serial 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_CDCSER_COMPOSITE case USB_REQ_GETCONFIGURATION: { if (ctrl->type == USB_DIR_IN) @@ -1275,14 +1299,15 @@ static int cdcser_setup(FAR struct usbdev_s *dev, const struct usb_ctrlreq_s *ct } } break; +#endif case USB_REQ_SETINTERFACE: { - if (ctrl->type == USB_REQ_RECIPIENT_INTERFACE) + if (ctrl->type == USB_REQ_RECIPIENT_INTERFACE && + priv->config == CDCSER_CONFIGID) { - if (priv->config == CDCSER_CONFIGID && - index == CDCSER_INTERFACEID && - value == CDCSER_ALTINTERFACEID) + if ((index == CDCSER_NOTIFID && value == CDCSER_NOTALTIFID) || + (index == CDCSER_DATAIFID && value == CDCSER_DATAALTIFID)) { cdcser_resetconfig(priv); cdcser_setconfig(priv, priv->config); @@ -1297,14 +1322,15 @@ static int cdcser_setup(FAR struct usbdev_s *dev, const struct usb_ctrlreq_s *ct if (ctrl->type == (USB_DIR_IN|USB_REQ_RECIPIENT_INTERFACE) && priv->config == CDCSER_CONFIGIDNONE) { - if (index != CDCSER_INTERFACEID) - { - ret = -EDOM; + if ((index == CDCSER_NOTIFID && value == CDCSER_NOTALTIFID) || + (index == CDCSER_DATAIFID && value == CDCSER_DATAALTIFID)) + { + *(uint8_t*) ctrlreq->buf = value; + ret = 1; } else - { - *(uint8_t*) ctrlreq->buf = CDCSER_ALTINTERFACEID; - ret = 1; + { + ret = -EDOM; } } } @@ -1314,7 +1340,6 @@ static int cdcser_setup(FAR struct usbdev_s *dev, const struct usb_ctrlreq_s *ct usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDSTDREQ), ctrl->req); break; } -#endif } break; @@ -1328,7 +1353,8 @@ static int cdcser_setup(FAR struct usbdev_s *dev, const struct usb_ctrlreq_s *ct case ACM_GET_LINE_CODING: { - if (ctrl->type == (USB_DIR_IN|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE)) + if (ctrl->type == (USB_DIR_IN|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE) && + index == CDCSER_NOTIFID) { /* Return the current line status from the private data structure */ @@ -1348,11 +1374,12 @@ static int cdcser_setup(FAR struct usbdev_s *dev, const struct usb_ctrlreq_s *ct case ACM_SET_LINE_CODING: { - if (ctrl->type == (USB_DIR_OUT|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE)) + if (ctrl->type == (USB_DIR_OUT|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE) && + len == SIZEOF_CDC_LINECODING && index == CDCSER_NOTIFID) { /* Save the new line coding in the private data structure */ - memcpy(&priv->linecoding, ctrlreq->buf, min(len, 7)); + memcpy(&priv->linecoding, ctrlreq->buf, MIN(len, 7)); ret = 0; /* If there is a registered callback to receive line status info, then @@ -1377,7 +1404,8 @@ static int cdcser_setup(FAR struct usbdev_s *dev, const struct usb_ctrlreq_s *ct case ACM_SET_CTRL_LINE_STATE: { - if (ctrl->type == (USB_DIR_OUT|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE)) + if (ctrl->type == (USB_DIR_OUT|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE) && + index == CDCSER_NOTIFID) { /* Save the control line state in the private data structure. Only bits * 0 and 1 have meaning. @@ -1406,7 +1434,8 @@ static int cdcser_setup(FAR struct usbdev_s *dev, const struct usb_ctrlreq_s *ct case ACM_SEND_BREAK: { - if (ctrl->type == (USB_DIR_OUT|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE)) + if (ctrl->type == (USB_DIR_OUT|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE) && + index == CDCSER_NOTIFID) { /* If there is a registered callback to handle the SendBreak request, * then callout now. @@ -1436,7 +1465,7 @@ static int cdcser_setup(FAR struct usbdev_s *dev, const struct usb_ctrlreq_s *ct if (ret >= 0) { - ctrlreq->len = min(len, ret); + ctrlreq->len = MIN(len, ret); ctrlreq->flags = USBDEV_REQFLAGS_NULLPKT; ret = EP_SUBMIT(dev->ep0, ctrlreq); if (ret < 0) @@ -1498,10 +1527,12 @@ static void cdcser_disconnect(FAR struct usbdev_s *dev) irqrestore(flags); /* Perform the soft connect function so that we will we can be - * re-enumerated. + * re-enumerated (unless we are part of a composite device) */ - DEV_CONNECT(dev); +#ifndef CONFIG_CDCSER_COMPOSITE + DEV_CONNECT(dev); +#endif } /**************************************************************************** @@ -1893,21 +1924,27 @@ static bool cdcuart_txempty(FAR struct uart_dev_s *dev) ****************************************************************************/ /**************************************************************************** - * Name: cdcser_initialize + * Name: cdcser_classobject * * Description: - * Register USB serial port (and USB serial console if so configured). + * Register USB serial port (and USB serial console if so configured) and + * return the class object. * * Input Parameter: - * Device minor number. E.g., minor 0 would correspond to /dev/ttyUSB0. + * minor - Device minor number. E.g., minor 0 would correspond to + * /dev/ttyUSB0. + * classdev - The location to return the CDC serial class' device + * instance. * * Returned Value: - * Zero (OK) means that the driver was successfully registered. On any - * failure, a negated errno value is retured. + * A pointer to the allocated class object (NULL on failure). * ****************************************************************************/ -int cdcser_initialize(int minor) +#ifndef CONFIG_CDCSER_COMPOSITE +static +#endif +int cdcser_classobject(int minor, FAR struct usbdevclass_driver_s **classdev) { FAR struct cdcser_alloc_s *alloc; FAR struct cdcser_dev_s *priv; @@ -1963,15 +2000,6 @@ int cdcser_initialize(int minor) drvr->drvr.ops = &g_driverops; drvr->dev = priv; - /* Register the USB serial class driver */ - - ret = usbdev_register(&drvr->drvr); - if (ret) - { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_DEVREGISTER), (uint16_t)-ret); - goto errout_with_alloc; - } - /* Register the USB serial console */ #ifdef CONFIG_CDCSER_CONSOLE @@ -1993,11 +2021,50 @@ int cdcser_initialize(int minor) usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UARTREGISTER), (uint16_t)-ret); goto errout_with_class; } + + *classdev = &drvr->drvr; return OK; errout_with_class: - usbdev_unregister(&drvr->drvr); -errout_with_alloc: kfree(alloc); return ret; } + +/**************************************************************************** + * Name: cdcser_initialize + * + * Description: + * Register USB serial port (and USB serial console if so configured). + * + * Input Parameter: + * Device minor number. E.g., minor 0 would correspond to /dev/ttyUSB0. + * + * Returned Value: + * Zero (OK) means that the driver was successfully registered. On any + * failure, a negated errno value is retured. + * + ****************************************************************************/ + +#ifndef CONFIG_CDCSER_COMPOSITE +int cdcser_initialize(int minor) +{ + FAR struct usbdevclass_driver_s *drvr; + FAR struct cdcser_dev_s *priv; + int ret; + + /* Get an instance of the serial driver class object */ + + ret = cdcser_classobject(minor, &drvr); + if (ret == OK) + { + /* Register the USB serial class driver */ + + ret = usbdev_register(drvr); + if (ret < 0) + { + usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_DEVREGISTER), (uint16_t)-ret); + } + } + return ret; +} +#endif diff --git a/nuttx/drivers/usbdev/cdcacm.h b/nuttx/drivers/usbdev/cdcacm.h index ca7352da83..c434b0f078 100644 --- a/nuttx/drivers/usbdev/cdcacm.h +++ b/nuttx/drivers/usbdev/cdcacm.h @@ -72,13 +72,39 @@ # endif #endif +/* Interface IDs. If the serial driver is built as a component of a composite + * device, then the interface IDs may need to be offset. + */ + +#ifndef CONFIG_CDCSER_COMPOSITE +# undef CONFIG_CDCSER_IFNOBASE +# define CONFIG_CDCSER_IFNOBASE 0 +#endif + +#ifndef CONFIG_CDCSER_IFNOBASE +# define CONFIG_CDCSER_IFNOBASE 0 +#endif + /* Descriptors **************************************************************/ /* These settings are not modifiable via the NuttX configuration */ #define CDC_VERSIONNO 0x0110 /* CDC version number 1.10 (BCD) */ #define CDCSER_CONFIGIDNONE (0) /* Config ID means to return to address mode */ -#define CDCSER_INTERFACEID (0) -#define CDCSER_ALTINTERFACEID (0) + +/* Interface IDs: + * + * CDCSER_NINTERFACES Two interfaces + * CDCSER_NOTIFID ID of the notifier interface + * CDCSER_NOTALTIFID No alternate for the notifier interface + * CDCSER_DATAIFID ID of the data interface + * CDCSER_DATAALTIFID No alternate for the data interface + */ + +#define CDCSER_NINTERFACES (2) /* Number of interfaces in the configuration */ +#define CDCSER_NOTIFID (CONFIG_CDCSER_IFNOBASE+0) +#define CDCSER_NOTALTIFID CDCSER_NOTIFID +#define CDCSER_DATAIFID (CONFIG_CDCSER_IFNOBASE+1) +#define CDCSER_DATAALTIFID CDCSER_DATAIFID /* Configuration descriptor values */ @@ -95,10 +121,6 @@ #define CDCSER_VERSIONNO (0x0101) /* Device version number 1.1 (BCD) */ #define CDCSER_NCONFIGS (1) /* Number of configurations supported */ -/* Configuration descriptor values */ - -#define CDCSER_NINTERFACES (2) /* Number of interfaces in the configuration */ - /* String language */ #define CDCSER_STR_LANGUAGE (0x0409) /* en-us */ @@ -177,14 +199,14 @@ #define CDCSER_EPINBULK_ATTR (USB_EP_ATTR_XFER_BULK) /* Misc Macros **************************************************************/ -/* min/max macros */ +/* MIN/MAX macros */ -#ifndef min -# define min(a,b) ((a)<(b)?(a):(b)) +#ifndef MIN +# define MIN(a,b) ((a)<(b)?(a):(b)) #endif -#ifndef max -# define max(a,b) ((a)>(b)?(a):(b)) +#ifndef MAX +# define MAX(a,b) ((a)>(b)?(a):(b)) #endif /* Trace values *************************************************************/ diff --git a/nuttx/drivers/usbdev/cdcacm_descriptors.c b/nuttx/drivers/usbdev/cdcacm_descriptors.c index b8affe3cc6..168801ac0d 100644 --- a/nuttx/drivers/usbdev/cdcacm_descriptors.c +++ b/nuttx/drivers/usbdev/cdcacm_descriptors.c @@ -145,8 +145,8 @@ static const struct usb_ifdesc_s g_notifdesc = { USB_SIZEOF_IFDESC, /* len */ USB_DESC_TYPE_INTERFACE, /* type */ - 0, /* ifno */ - 0, /* alt */ + CDCSER_NOTIFID, /* ifno */ + CDCSER_NOTALTIFID, /* alt */ 1, /* neps */ USB_CLASS_CDC, /* class */ CDC_SUBCLASS_ACM, /* subclass */ @@ -213,8 +213,8 @@ static const struct usb_ifdesc_s g_dataifdesc = { USB_SIZEOF_IFDESC, /* len */ USB_DESC_TYPE_INTERFACE, /* type */ - 1, /* ifno */ - 0, /* alt */ + CDCSER_DATAIFID, /* ifno */ + CDCSER_DATAALTIFID, /* alt */ 2, /* neps */ USB_CLASS_CDC_DATA, /* class */ CDC_DATA_SUBCLASS_NONE, /* subclass */ diff --git a/nuttx/drivers/usbdev/composite.c b/nuttx/drivers/usbdev/composite.c index 4c95823557..75f0fbed14 100644 --- a/nuttx/drivers/usbdev/composite.c +++ b/nuttx/drivers/usbdev/composite.c @@ -41,9 +41,14 @@ #include #include +#include #include #include +#include +#include +#include +#include #include #include "composite.h" @@ -58,17 +63,309 @@ * Private Types ****************************************************************************/ +/* This structure describes the internal state of the driver */ + +struct composite_dev_s +{ + FAR struct usbdev_s *usbdev; /* usbdev driver pointer */ + uint8_t config; /* Configuration number */ + FAR struct usbdev_req_s *ctrlreq; /* Allocated control request */ + struct usbdevclass_driver_s *dev1; /* Device 1 class object */ + struct usbdevclass_driver_s *dev2; /* Device 2 class object */ +}; + +/* The internal version of the class driver */ + +struct composite_driver_s +{ + struct usbdevclass_driver_s drvr; + FAR struct composite_dev_s *dev; +}; + +/* This is what is allocated */ + +struct composite_alloc_s +{ + struct composite_dev_s dev; + struct composite_driver_s drvr; +}; + /**************************************************************************** * Private Function Prototypes ****************************************************************************/ +/* USB helps ****************************************************************/ + +static void composite_ep0incomplete(FAR struct usbdev_ep_s *ep, + FAR struct usbdev_req_s *req); +static int composite_classsetup(FAR struct composite_dev_s *priv, + FAR struct usbdev_s *dev, + FAR const struct usb_ctrlreq_s *ctrl); +static struct usbdev_req_s *composite_allocreq(FAR struct usbdev_ep_s *ep, + uint16_t len); +static void composite_freereq(FAR struct usbdev_ep_s *ep, + FAR struct usbdev_req_s *req); + +/* USB class device ********************************************************/ + +static int composite_bind(FAR struct usbdev_s *dev, + FAR struct usbdevclass_driver_s *driver); +static void composite_unbind(FAR struct usbdev_s *dev); +static int composite_setup(FAR struct usbdev_s *dev, + FAR const struct usb_ctrlreq_s *ctrl); +static void composite_disconnect(FAR struct usbdev_s *dev); +static void composite_suspend(FAR struct usbdev_s *dev); +static void composite_resume(FAR struct usbdev_s *dev); /**************************************************************************** * Private Data ****************************************************************************/ +/* USB class device *********************************************************/ + +static const struct usbdevclass_driverops_s g_driverops = +{ + composite_bind, /* bind */ + composite_unbind, /* unbind */ + composite_setup, /* setup */ + composite_disconnect, /* disconnect */ + composite_suspend, /* suspend */ + composite_resume, /* resume */ +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +const char g_compvendorstr[] = CONFIG_COMPOSITE_VENDORSTR; +const char g_compproductstr[] = CONFIG_COMPOSITE_PRODUCTSTR; +const char g_compserialstr[] = CONFIG_COMPOSITE_SERIALSTR; /**************************************************************************** * Private Functions ****************************************************************************/ +/**************************************************************************** + * Helpers + ****************************************************************************/ + +/**************************************************************************** + * Name: composite_ep0incomplete + * + * Description: + * Handle completion of EP0 control operations + * + ****************************************************************************/ + +static void composite_ep0incomplete(FAR struct usbdev_ep_s *ep, + FAR struct usbdev_req_s *req) +{ + if (req->result || req->xfrd != req->len) + { + usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_REQRESULT), (uint16_t)-req->result); + } +} + +/**************************************************************************** + * Name: composite_classsetup + * + * Description: + * Forward a setup command to the appropriate component device + * + ****************************************************************************/ + +static int composite_classsetup(FAR struct composite_dev_s *priv, + FAR struct usbdev_s *dev, + FAR const struct usb_ctrlreq_s *ctrl) +{ + uint16_t index; + uint8_t interface; + int ret = -EOPNOTSUPP; + + index = GETUINT16(ctrl->index); + interface = (uint8_t)(index & 0xff); + + if (interface >= DEV1_FIRSTINTERFACE && interface <= (DEV1_FIRSTINTERFACE + DEV1_NINTERFACES)) + { + ret = CLASS_SETUP(priv->dev1, dev, ctrl); + } + else if (interface >= DEV2_FIRSTINTERFACE && interface <= (DEV2_FIRSTINTERFACE + DEV2_NINTERFACES)) + { + ret = CLASS_SETUP(priv->dev1, dev, ctrl); + } + + return ret; +} + +/**************************************************************************** + * Name: composite_allocreq + * + * Description: + * Allocate a request instance along with its buffer + * + ****************************************************************************/ + +static struct usbdev_req_s *composite_allocreq(FAR struct usbdev_ep_s *ep, + uint16_t len) +{ + FAR struct usbdev_req_s *req; + + req = EP_ALLOCREQ(ep); + if (req != NULL) + { + req->len = len; + req->buf = EP_ALLOCBUFFER(ep, len); + if (!req->buf) + { + EP_FREEREQ(ep, req); + req = NULL; + } + } + return req; +} + +/**************************************************************************** + * Name: composite_freereq + * + * Description: + * Free a request instance along with its buffer + * + ****************************************************************************/ + +static void composite_freereq(FAR struct usbdev_ep_s *ep, + FAR struct usbdev_req_s *req) +{ + if (ep != NULL && req != NULL) + { + if (req->buf != NULL) + { + EP_FREEBUFFER(ep, req->buf); + } + EP_FREEREQ(ep, req); + } +} + +/**************************************************************************** + * USB Class Driver Methods + ****************************************************************************/ + +/**************************************************************************** + * Name: composite_bind + * + * Description: + * Invoked when the driver is bound to a USB device driver + * + ****************************************************************************/ + +static int composite_bind(FAR struct usbdev_s *dev, FAR struct usbdevclass_driver_s *driver) +{ + FAR struct composite_dev_s *priv = ((struct composite_driver_s*)driver)->dev; + int ret; + + usbtrace(TRACE_CLASSBIND, 0); + + /* Bind the structures */ + + priv->usbdev = dev; + dev->ep0->priv = priv; + + /* Preallocate 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(dev); + return ret; +} + +/**************************************************************************** + * Name: composite_unbind + * + * Description: + * Invoked when the driver is unbound from a USB device driver + * + ****************************************************************************/ + +static void composite_unbind(FAR struct usbdev_s *dev) +{ + FAR struct composite_dev_s *priv; + irqstate_t flags; + + usbtrace(TRACE_CLASSUNBIND, 0); + +#ifdef CONFIG_DEBUG + if (!dev || !dev->ep0) + { + usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_INVALIDARG), 0); + return; + } +#endif + + /* Extract reference to private data */ + + priv = (FAR struct composite_dev_s *)dev->ep0->priv; + +#ifdef CONFIG_DEBUG + if (!priv) + { + usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_EP0NOTBOUND), 0); + return; + } +#endif + + /* Make sure that we are not already unbound */ + + if (priv != NULL) + { + /* Unbind the constituent class drivers */ + + flags = irqsave(); + CLASS_UNBIND(priv->dev1, dev); + CLASS_UNBIND(priv->dev2, dev); + + /* Free the pre-allocated control request */ + + priv->config = COMPOSITE_CONFIGIDNONE; + if (priv->ctrlreq != NULL) + { + composite_freereq(dev->ep0, priv->ctrlreq); + priv->ctrlreq = NULL; + } + irqrestore(flags); + } +} /**************************************************************************** * Name: composite_setup @@ -79,7 +376,6 @@ * ****************************************************************************/ - #if 0 static int composite_setup(FAR struct usbdev_s *dev, FAR const struct usb_ctrlreq_s *ctrl) { @@ -88,35 +384,36 @@ static int composite_setup(FAR struct usbdev_s *dev, uint16_t value; uint16_t index; uint16_t len; + bool dispatched = false; int ret = -EOPNOTSUPP; #ifdef CONFIG_DEBUG if (!dev || !dev->ep0 || !ctrl) { - usbtrace(TRACE_CLSERROR(USBSTRG_TRACEERR_SETUPINVALIDARGS), 0); + usbtrace(TRACE_CLSERROR(COMPOSITE_TRACEERR_SETUPINVALIDARGS), 0); return -EIO; } #endif - /* Extract reference to private data */ + /* Extract a reference to private data */ usbtrace(TRACE_CLASSSETUP, ctrl->req); priv = (FAR struct composite_dev_s *)dev->ep0->priv; #ifdef CONFIG_DEBUG - if (!priv || !priv->ctrlreq) + if (!priv) { - usbtrace(TRACE_CLSERROR(USBSTRG_TRACEERR_EP0NOTBOUND2), 0); + usbtrace(TRACE_CLSERROR(COMPOSITE_TRACEERR_EP0NOTBOUND2), 0); return -ENODEV; } #endif - ctrlreq = priv->ctrlreq; + 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); + 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); @@ -153,7 +450,7 @@ static int composite_setup(FAR struct usbdev_s *dev, break; case USB_DESC_TYPE_OTHERSPEEDCONFIG: -#endif /* CONFIG_USBDEV_DUALSPEED */ +#endif case USB_DESC_TYPE_CONFIG: { @@ -175,7 +472,7 @@ static int composite_setup(FAR struct usbdev_s *dev, default: { - usbtrace(TRACE_CLSERROR(USBSTRG_TRACEERR_GETUNKNOWNDESC), value); + usbtrace(TRACE_CLSERROR(COMPOSITE_TRACEERR_GETUNKNOWNDESC), value); } break; } @@ -186,17 +483,19 @@ static int composite_setup(FAR struct usbdev_s *dev, { if (ctrl->type == 0) { - /* Signal the worker thread to instantiate the new configuration */ + /* Save the configuration and inform the constituent classes */ - priv->theventset |= USBSTRG_EVENT_CFGCHANGE; - priv->thvalue = value; - pthread_cond_signal(&priv->cond); + ret = CLASS_SETUP(priv->dev1, dev, ctrl); + dispatched = true; - /* Return here... the response will be provided later by the - * worker thread. - */ - - return OK; + if (ret >= 0) + { + ret = CLASS_SETUP(priv->dev1, dev, ctrl); + if (ret >= 0) + { + priv->config = value; + } + } } } break; @@ -213,23 +512,10 @@ static int composite_setup(FAR struct usbdev_s *dev, case USB_REQ_SETINTERFACE: { - if (ctrl->type == USB_REQ_RECIPIENT_INTERFACE) + if (ctrl->type == USB_REQ_RECIPIENT_INTERFACE && + priv->config == COMPOSITE_CONFIGID) { - if (priv->config == USBSTRG_CONFIGID && - index == USBSTRG_INTERFACEID && - value == USBSTRG_ALTINTERFACEID) - { - /* Signal to instantiate the interface change */ - - priv->theventset |= USBSTRG_EVENT_IFCHANGE; - pthread_cond_signal(&priv->cond); - - /* Return here... the response will be provided later by the - * worker thread. - */ - - return OK; - } + dispatched = (composite_classsetup(priv, dev, ctrl) >= 0); } } break; @@ -237,56 +523,265 @@ static int composite_setup(FAR struct usbdev_s *dev, case USB_REQ_GETINTERFACE: { if (ctrl->type == (USB_DIR_IN|USB_REQ_RECIPIENT_INTERFACE) && - priv->config == USBSTRG_CONFIGIDNONE) + priv->config == COMPOSITE_CONFIGIDNONE) { - if (index != USBSTRG_INTERFACEID) - { - ret = -EDOM; - } - else - { - ctrlreq->buf[0] = USBSTRG_ALTINTERFACEID; - ret = 1; - } + dispatched = (composite_classsetup(priv, dev, ctrl) >= 0); } } break; default: - usbtrace(TRACE_CLSERROR(USBSTRG_TRACEERR_UNSUPPORTEDSTDREQ), ctrl->req); + usbtrace(TRACE_CLSERROR(COMPOSITE_TRACEERR_UNSUPPORTEDSTDREQ), ctrl->req); break; } - - /* 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) - { - ctrlreq->len = min(len, ret); - ctrlreq->flags = USBDEV_REQFLAGS_NULLPKT; - ret = EP_SUBMIT(dev->ep0, ctrlreq); - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBSTRG_TRACEERR_EPRESPQ), (uint16_t)-ret); - ctrlreq->result = OK; - composite_ep0incomplete(dev->ep0, ctrlreq); - } } else { + uint8_t recipient; + /********************************************************************** * Non-Standard Class Requests **********************************************************************/ -#warning "Missing Logic" + + /* 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) + { + dispatched = (composite_classsetup(priv, dev, ctrl) >= 0); + } } + + /* 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) + { + ctrlreq->len = MIN(len, ret); + ctrlreq->flags = USBDEV_REQFLAGS_NULLPKT; + ret = EP_SUBMIT(dev->ep0, ctrlreq); + if (ret < 0) + { + usbtrace(TRACE_CLSERROR(COMPOSITE_TRACEERR_EPRESPQ), (uint16_t)-ret); + ctrlreq->result = OK; + composite_ep0incomplete(dev->ep0, ctrlreq); + } + } return ret; } + +/**************************************************************************** + * Name: composite_disconnect + * + * Description: + * Invoked after all transfers have been stopped, when the host is + * disconnected. This function is probably called from the context of an + * interrupt handler. + * + ****************************************************************************/ + +static void composite_disconnect(FAR struct usbdev_s *dev) +{ + FAR struct composite_dev_s *priv; + irqstate_t flags; + + usbtrace(TRACE_CLASSDISCONNECT, 0); + +#ifdef CONFIG_DEBUG + if (!dev || !dev->ep0) + { + usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_INVALIDARG), 0); + return; + } #endif + /* Extract reference to private data */ + + priv = (FAR struct composite_dev_s *)dev->ep0->priv; + +#ifdef CONFIG_DEBUG + if (!priv) + { + usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_EP0NOTBOUND), 0); + return; + } +#endif + + /* Reset the configuration and inform the constituent class drivers of + * the disconnection. + */ + + flags = irqsave(); + priv->config = COMPOSITE_CONFIGIDNONE; + CLASS_DISCONNECT(priv->dev1, dev); + CLASS_DISCONNECT(priv->dev2, dev); + irqrestore(flags); + + /* Perform the soft connect function so that we will we can be + * re-enumerated. + */ + + DEV_CONNECT(dev); +} + +/**************************************************************************** + * Name: composite_suspend + * + * Description: + * Invoked on a USB suspend event. + * + ****************************************************************************/ + +static void composite_suspend(FAR struct usbdev_s *dev) +{ + FAR struct composite_dev_s *priv; + irqstate_t flags; + + usbtrace(TRACE_CLASSSUSPEND, 0); + +#ifdef CONFIG_DEBUG + if (!dev || !dev->ep0 || !dev->ep0->priv) + { + usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_INVALIDARG), 0); + return; + } +#endif + + /* Extract reference to private data */ + + priv = (FAR struct composite_dev_s *)dev->ep0->priv; + + /* Forward the suspend event to the constituent devices */ + + flags = irqsave(); + CLASS_SUSPEND(priv->dev1, priv->usbdev); + CLASS_SUSPEND(priv->dev2, priv->usbdev); + irqrestore(flags); +} + +/**************************************************************************** + * Name: composite_resume + * + * Description: + * Invoked on a USB resume event. + * + ****************************************************************************/ + +static void composite_resume(FAR struct usbdev_s *dev) +{ + FAR struct composite_dev_s *priv = NULL; + irqstate_t flags; + + if (!dev || !dev->ep0 || !dev->ep0->priv) + +#ifdef CONFIG_DEBUG + if (!dev || !dev->ep0) + { + usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_INVALIDARG), 0); + return; + } +#endif + + /* Extract reference to private data */ + + priv = (FAR struct composite_dev_s *)dev->ep0->priv; + + /* Forward the resume event to the constituent devices */ + + flags = irqsave(); + CLASS_RESUME(priv->dev1, priv->usbdev); + CLASS_RESUME(priv->dev2, priv->usbdev); + irqrestore(flags); +} + /**************************************************************************** * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: composite_initialize + * + * Description: + * Register USB composite port (and USB composite console if so configured). + * + * Input Parameter: + * Device minor number. E.g., minor 0 would correspond to /dev/ttyUSB0. + * + * Returned Value: + * Zero (OK) means that the driver was successfully registered. On any + * failure, a negated errno value is retured. + * + ****************************************************************************/ + +int composite_initialize(int minor) +{ + 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*)kmalloc(sizeof(struct composite_alloc_s)); + if (!alloc) + { + usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_ALLOCDEVSTRUCT), 0); + return -ENOMEM; + } + + /* 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 OK; + +errout_with_alloc: + kfree(alloc); + return ret; +} #endif /* CONFIG_USBDEV_COMPOSITE */ diff --git a/nuttx/drivers/usbdev/composite.h b/nuttx/drivers/usbdev/composite.h index ed3b48eacc..14cbd9db82 100644 --- a/nuttx/drivers/usbdev/composite.h +++ b/nuttx/drivers/usbdev/composite.h @@ -50,6 +50,15 @@ #ifdef CONFIG_USBDEV_COMPOSITE +#ifdef CONFIG_CDCSER_COMPOSITE +# include +# include "cdcacm.h" +#endif + +#ifdef CONFIG_USBSTRG_COMPOSITE +# include "msc.h" +#endif + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -74,16 +83,16 @@ #ifndef CONFIG_COMPOSITE_COMPOSITE # ifndef CONFIG_COMPOSITE_VENDORID # warning "CONFIG_COMPOSITE_VENDORID not defined" -# define CONFIG_COMPOSITE_VENDORID 0x584e +# define CONFIG_COMPOSITE_VENDORID 0x03eb # endif # ifndef CONFIG_COMPOSITE_PRODUCTID # warning "CONFIG_COMPOSITE_PRODUCTID not defined" -# define CONFIG_COMPOSITE_PRODUCTID 0x5342 +# define CONFIG_COMPOSITE_PRODUCTID 0x2022 # endif # ifndef CONFIG_COMPOSITE_VERSIONNO -# define CONFIG_COMPOSITE_VERSIONNO (0x0399) +# define CONFIG_COMPOSITE_VERSIONNO (0x0101) # endif # ifndef CONFIG_COMPOSITE_VENDORSTR @@ -103,7 +112,112 @@ #undef CONFIG_COMPOSITE_CONFIGSTR #define CONFIG_COMPOSITE_CONFIGSTR "Composite" +/* Constituent devices ******************************************************/ + +#undef DEV1_IS_CDCSERIAL +#undef DEV1_IS_USBSTRG + +#undef DEV2_IS_CDCSERIAL +#undef DEV2_IS_USBSTRG + +/* Pick the first device in the composite. At present, this may only be + * the CDC serial device or the mass storage device. + */ + +#if defined(CONFIG_CDCSER_COMPOSITE) +# define DEV1_IS_CDCSERIAL 1 +# define DEV1_MKCFGDESC cdcser_mkcfgdesc +# define DEV1_CLASSOBJECT board_cdcclassobject +# define DEV1_NCONFIGS CDCSER_NCONFIGS +# define DEV1_CONFIGID CDCSER_CONFIGID +# define DEV1_FIRSTINTERFACE CONFIG_CDCSER_IFNOBASE +# define DEV1_NINTERFACES CDCSER_NINTERFACES +# define DEV1_FIRSTSTRID CONFIG_CDCSER_STRBASE +# define DEV1_NSTRIDS (CDCSER_LASTSTRID-CONFIG_CDCSER_STRBASE) +# define DEV1_CFGDESCSIZE SIZEOF_CDCSER_CFGDESC +#elif defined(CONFIG_CDCSER_COMPOSITE) +# define DEV1_IS_USBSTRG 1 +# define DEV1_MKCFGDESC usbstrg_mkcfgdesc +# define DEV1_CLASSOBJECT board_mscclassobject +# define DEV1_NCONFIGS USBSTRG_NCONFIGS +# define DEV1_CONFIGID USBSTRG_CONFIGID +# define DEV1_FIRSTINTERFACE CONFIG_USBSTRG_IFNOBASE +# define DEV1_NINTERFACES USBSTRG_NINTERFACES +# define DEV1_FIRSTSTRID CONFIG_USBSTRG_IFNOBASE +# define DEV1_NSTRIDS (USBSTRG_LASTSTRID-CONFIG_USBSTRG_STRBASE) +# define DEV1_CFGDESCSIZE SIZEOF_USBSTRG_CFGDESC +#else +# error "No members of the composite defined" +#endif + +/* Pick the second device in the composite. At present, this may only be + * the CDC serial device or the mass storage device. + */ + +#if defined(CONFIG_CDCSER_COMPOSITE) && !defined(DEV1_IS_CDCSERIAL) +# define DEV2_IS_CDCSERIAL 1 +# define DEV2_MKCFGDESC cdcser_mkcfgdesc +# define DEV2_CLASSOBJECT board_cdcclassobject +# define DEV2_NCONFIGS CDCSER_NCONFIGS +# define DEV2_CONFIGID CDCSER_CONFIGID +# define DEV2_FIRSTINTERFACE CONFIG_CDCSER_IFNOBASE +# define DEV2_NINTERFACES CDCSER_NINTERFACES +# define DEV2_FIRSTSTRID CONFIG_CDCSER_STRBASE +# define DEV2_NSTRIDS (CDCSER_LASTSTRID-CONFIG_CDCSER_STRBASE) +# define DEV2_CFGDESCSIZE SIZEOF_CDCSER_CFGDESC +#elif defined(CONFIG_CDCSER_COMPOSITE) && !defined(DEV1_IS_USBSTRG) +# define DEV2_IS_USBSTRG 1 +# define DEV2_MKCFGDESC usbstrg_mkcfgdesc +# define DEV2_CLASSOBJECT board_mscclassobject +# define DEV2_NCONFIGS USBSTRG_NCONFIGS +# define DEV2_CONFIGID USBSTRG_CONFIGID +# define DEV2_FIRSTINTERFACE CONFIG_USBSTRG_IFNOBASE +# define DEV2_NINTERFACES USBSTRG_NINTERFACES +# define DEV2_FIRSTSTRID CONFIG_CDCSER_STRBASE +# define DEV2_NSTRIDS (USBSTRG_LASTSTRID-CONFIG_USBSTRG_STRBASE) +# define DEV2_CFGDESCSIZE SIZEOF_USBSTRG_CFGDESC +#else +# error "Insufficient members of the composite defined" +#endif + +/* Verify interface configuration */ + +#if DEV1_FIRSTINTERFACE != 0 +# warning "The first interface number should be zero" +#endif + +#if (DEV1_FIRSTINTERFACE + DEV2_NINTERFACES) != DEV2_FIRSTINTERFACE +# warning "Interface numbers are not contiguous" +#endif + +/* Total size of the configuration descriptor: */ + +#define COMPOSITE_CFGDESCSIZE (USB_SIZEOF_CFGDESC + DEV1_CFGDESCSIZE + DEV2_CFGDESCSIZE) + +/* The total number of interfaces */ + +#define COMPOSITE_NINTERFACES (DEV1_NINTERFACES + DEV2_NINTERFACES) + +/* Composite configuration ID value */ + +#if DEV1_NCONFIGS != 1 || DEV1_CONFIGID != 1 +# error "DEV1: Only a single configuration is supported" +#endif + +#if DEV2_NCONFIGS != 1 || DEV2_CONFIGID != 1 +# error "DEV2: Only a single configuration is supported" +#endif + /* Descriptors **************************************************************/ +/* These settings are not modifiable via the NuttX configuration */ + +#define COMPOSITE_CONFIGIDNONE (0) /* Config ID = 0 means to return to address mode */ +#define COMPOSITE_NCONFIGS (1) /* The number of configurations supported */ +#define COMPOSITE_CONFIGID (1) /* The only supported configuration ID */ + +/* String language */ + +#define COMPOSITE_STR_LANGUAGE (0x0409) /* en-us */ /* Descriptor strings */ @@ -112,6 +226,16 @@ #define COMPOSITE_SERIALSTRID (3) #define COMPOSITE_CONFIGSTRID (4) +/* Everpresent MIN/MAX macros ***********************************************/ + +#ifndef MIN +# define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef MAX +# define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + /**************************************************************************** * Public Types ****************************************************************************/ @@ -120,6 +244,10 @@ * Public Data ****************************************************************************/ +extern const char g_compvendorstr[]; +extern const char g_compproductstr[]; +extern const char g_compserialstr[]; + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ diff --git a/nuttx/drivers/usbdev/composite_descriptors.c b/nuttx/drivers/usbdev/composite_descriptors.c index 5feed8e218..e49631b5b2 100644 --- a/nuttx/drivers/usbdev/composite_descriptors.c +++ b/nuttx/drivers/usbdev/composite_descriptors.c @@ -44,105 +44,19 @@ #include #include #include +#include #include #include #include "composite.h" -#ifdef CONFIG_CDCSER_COMPOSITE -# include "cdcacm.h" -#endif - -#ifdef CONFIG_USBSTRG_COMPOSITE -# include "msc.h" -#endif - #ifdef CONFIG_USBDEV_COMPOSITE /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -#undef DEV1_IS_CDCSERIAL -#undef DEV1_IS_USBSTRG - -#undef DEV2_IS_CDCSERIAL -#undef DEV2_IS_USBSTRG - -/* Pick the first device in the composite. At present, this may only be - * the CDC serial device or the mass storage device. - */ - -#if defined(CONFIG_CDCSER_COMPOSITE) -# define DEV1_IS_CDCSERIAL 1 -# define DEV1_MKCFGDESC cdcser_mkcfgdesc -# define DEV1_NCONFIGS CDCSER_NCONFIGS -# define DEV1_CONFIGID CDCSER_CONFIGID -# define DEV1_NINTERFACES CDCSER_NINTERFACES -# define DEV1_FIRSTSTRID CONFIG_CDCSER_STRBASE -# define DEV1_NSTRIDS (CDCSER_LASTSTRID-CONFIG_CDCSER_STRBASE) -# define DEV1_CFGDESCSIZE SIZEOF_CDCSER_CFGDESC -#elif defined(CONFIG_CDCSER_COMPOSITE) -# define DEV1_IS_USBSTRG 1 -# define DEV1_MKCFGDESC composite_mkcfgdesc -# define DEV1_NCONFIGS USBSTRG_NCONFIGS -# define DEV1_CONFIGID USBSTRG_CONFIGID -# define DEV1_NINTERFACES USBSTRG_NINTERFACES -# define DEV1_FIRSTSTRID CONFIG_CDCSER_STRBASE -# define DEV1_NSTRIDS (USBSTRG_LASTSTRID-CONFIG_USBSTRG_STRBASE) -# define DEV1_CFGDESCSIZE SIZEOF_USBSTRG_CFGDESC -#else -# error "No members of the composite defined" -#endif - -/* Pick the second device in the composite. At present, this may only be - * the CDC serial device or the mass storage device. - */ - -#if defined(CONFIG_CDCSER_COMPOSITE) && !defined(DEV1_IS_CDCSERIAL) -# define DEV2_IS_CDCSERIAL 1 -# define DEV2_MKCFGDESC cdcser_mkcfgdesc -# define DEV2_NCONFIGS CDCSER_NCONFIGS -# define DEV2_CONFIGID CDCSER_CONFIGID -# define DEV2_NINTERFACES CDCSER_NINTERFACES -# define DEV2_FIRSTSTRID CONFIG_CDCSER_STRBASE -# define DEV2_NSTRIDS (CDCSER_LASTSTRID-CONFIG_CDCSER_STRBASE) -# define DEV2_CFGDESCSIZE SIZEOF_CDCSER_CFGDESC -#elif defined(CONFIG_CDCSER_COMPOSITE) && !defined(DEV1_IS_USBSTRG) -# define DEV2_IS_USBSTRG 1 -# define DEV2_MKCFGDESC composite_mkcfgdesc -# define DEV2_NCONFIGS USBSTRG_NCONFIGS -# define DEV2_CONFIGID USBSTRG_CONFIGID -# define DEV2_NINTERFACES USBSTRG_NINTERFACES -# define DEV2_FIRSTSTRID CONFIG_CDCSER_STRBASE -# define DEV2_NSTRIDS (USBSTRG_LASTSTRID-CONFIG_USBSTRG_STRBASE) -# define DEV2_CFGDESCSIZE SIZEOF_USBSTRG_CFGDESC -#else -# error "Insufficient members of the composite defined" -#endif - -/* Total size of the configuration descriptor: */ - -#define COMPOSITE_CFGDESCSIZE (USB_SIZEOF_CFGDESC + DEV1_CFGDESCSIZE + DEV2_CFGDESCSIZE) - -/* The total number of interfaces */ - -#define COMPOSITE_NINTERFACES (DEV1_NINTERFACES + DEV2_NINTERFACES) - -/* Composite configuration ID value */ - -#if DEV1_NCONFIGS != 1 || DEV1_CONFIGID != 1 -# error "DEV1: Only a single configuration is supported" -#endif - -#if DEV2_NCONFIGS != 1 || DEV2_CONFIGID != 1 -# error "DEV2: Only a single configuration is supported" -#endif - -#define COMPOSITE_NCONFIGS 1 -#define COMPOSITE_CONFIGID 1 - /**************************************************************************** * Private Types ****************************************************************************/ @@ -258,25 +172,25 @@ int composite_mkstrdesc(uint8_t id, struct usb_strdesc_s *strdesc) strdesc->len = 4; strdesc->type = USB_DESC_TYPE_STRING; - strdesc->data[0] = LSBYTE(USBSTRG_STR_LANGUAGE); - strdesc->data[1] = MSBYTE(USBSTRG_STR_LANGUAGE); + strdesc->data[0] = LSBYTE(COMPOSITE_STR_LANGUAGE); + strdesc->data[1] = MSBYTE(COMPOSITE_STR_LANGUAGE); return 4; } case COMPOSITE_MANUFACTURERSTRID: - str = g_vendorstr; + str = g_compvendorstr; break; case COMPOSITE_PRODUCTSTRID: - str = g_productstr; + str = g_compproductstr; break; case COMPOSITE_SERIALSTRID: - str = g_serialstr; + str = g_compserialstr; break; case COMPOSITE_CONFIGSTRID: - str = CONFIG_USBSTRG_CONFIGSTR; + str = CONFIG_COMPOSITE_CONFIGSTR; break; default: @@ -307,12 +221,10 @@ int composite_mkstrdesc(uint8_t id, struct usb_strdesc_s *strdesc) * ****************************************************************************/ -#ifndef CONFIG_USBSTRG_COMPOSITE FAR const struct usb_devdesc_s *composite_getdevdesc(void) { return &g_devdesc; } -#endif /**************************************************************************** * Name: composite_mkcfgdesc @@ -329,21 +241,28 @@ int16_t composite_mkcfgdesc(uint8_t *buf) #endif { FAR struct usb_cfgdesc_s *cfgdesc = (struct usb_cfgdesc_s*)buf; + int16_t len; /* Configuration descriptor -- Copy the canned configuration descriptor. */ memcpy(cfgdesc, &g_cfgdesc, USB_SIZEOF_CFGDESC); + len = USB_SIZEOF_CFGDESC; buf += USB_SIZEOF_CFGDESC; /* Copy DEV1/DEV2 configuration descriptors */ #ifdef CONFIG_USBDEV_DUALSPEED - buf += DEV1_MKCFGDESC(buf, speed, type); - buf += DEV2_MKCFGDESC(buf, speed, type); + len = DEV1_MKCFGDESC(buf, speed, type); + buf += len; + len = DEV2_MKCFGDESC(buf, speed, type); + buf += len; #else - buf += DEV1_MKCFGDESC(buf); - buf += DEV2_MKCFGDESC(buf); + len = DEV1_MKCFGDESC(buf); + buf += len; + len = DEV2_MKCFGDESC(buf); + buf += len; #endif + DEBUGASSERT(len == COMPOSITE_CFGDESCSIZE); return COMPOSITE_CFGDESCSIZE; } diff --git a/nuttx/drivers/usbdev/msc.c b/nuttx/drivers/usbdev/msc.c index a29153b645..63d6a1f5bb 100644 --- a/nuttx/drivers/usbdev/msc.c +++ b/nuttx/drivers/usbdev/msc.c @@ -335,15 +335,19 @@ static int usbstrg_bind(FAR struct usbdev_s *dev, FAR struct usbdevclass_driver_ irqrestore(flags); } - /* Report if we are selfpowered */ + /* Report if we are selfpowered (unless we are part of a composite device) */ +#ifndef CONFIG_USBSTRG_COMPOSITE #ifdef CONFIG_USBDEV_SELFPOWERED DEV_SETSELFPOWERED(dev); #endif - /* And pull-up the data line for the soft connect function */ + /* And pull-up the data line for the soft connect function (unless we are + * part of a composite device) + */ DEV_CONNECT(dev); +#endif return OK; errout: @@ -520,14 +524,6 @@ static int usbstrg_setup(FAR struct usbdev_s *dev, * Standard Requests **********************************************************************/ - /* If the mass storage device is used in as part of a composite device, - * then the configuration descriptor is is handled by logic in the - * composite device logic. - */ - -#ifdef CONFIG_USBSTRG_COMPOSITE - usbtrace(TRACE_CLSERROR(USBSTRG_TRACEERR_UNSUPPORTEDSTDREQ), ctrl->req); -#else switch (ctrl->req) { case USB_REQ_GETDESCRIPTOR: @@ -538,14 +534,26 @@ static int usbstrg_setup(FAR struct usbdev_s *dev, 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_USBSTRG_COMPOSITE case USB_DESC_TYPE_DEVICE: { ret = USB_SIZEOF_DEVDESC; memcpy(ctrlreq->buf, usbstrg_getdevdesc(), ret); } break; +#endif -#ifdef CONFIG_USBDEV_DUALSPEED + /* 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_USBSTRG_COMPOSITE) && defined(CONFIG_USBDEV_DUALSPEED) case USB_DESC_TYPE_DEVICEQUALIFIER: { ret = USB_SIZEOF_QUALDESC; @@ -554,8 +562,14 @@ static int usbstrg_setup(FAR struct usbdev_s *dev, break; case USB_DESC_TYPE_OTHERSPEEDCONFIG: -#endif /* CONFIG_USBDEV_DUALSPEED */ +#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_USBSTRG_COMPOSITE case USB_DESC_TYPE_CONFIG: { #ifdef CONFIG_USBDEV_DUALSPEED @@ -565,7 +579,14 @@ static int usbstrg_setup(FAR struct usbdev_s *dev, #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_USBSTRG_COMPOSITE case USB_DESC_TYPE_STRING: { /* index == language code. */ @@ -573,6 +594,7 @@ static int usbstrg_setup(FAR struct usbdev_s *dev, ret = usbstrg_mkstrdesc(ctrl->value[0], (struct usb_strdesc_s *)ctrlreq->buf); } break; +#endif default: { @@ -602,6 +624,12 @@ static int usbstrg_setup(FAR struct usbdev_s *dev, } 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_USBSTRG_COMPOSITE case USB_REQ_GETCONFIGURATION: { if (ctrl->type == USB_DIR_IN) @@ -611,6 +639,7 @@ static int usbstrg_setup(FAR struct usbdev_s *dev, } } break; +#endif case USB_REQ_SETINTERFACE: { @@ -657,7 +686,6 @@ static int usbstrg_setup(FAR struct usbdev_s *dev, usbtrace(TRACE_CLSERROR(USBSTRG_TRACEERR_UNSUPPORTEDSTDREQ), ctrl->req); break; } -#endif } else { @@ -681,7 +709,7 @@ static int usbstrg_setup(FAR struct usbdev_s *dev, { /* Only one interface is supported */ - if (index != USBSTRG_CONFIGID) + if (index != USBSTRG_INTERFACEID) { usbtrace(TRACE_CLSERROR(USBSTRG_TRACEERR_MSRESETNDX), index); ret = -EDOM; @@ -705,7 +733,7 @@ static int usbstrg_setup(FAR struct usbdev_s *dev, case USBSTRG_REQ_GETMAXLUN: /* Return number LUNs supported */ { - if (ctrl->type == USBSTRG_TYPE_SETUPIN && value == 0) + if (ctrl->type == USBSTRG_TYPE_SETUPIN && value == 0 && len == 1) { /* Only one interface is supported */ @@ -735,7 +763,7 @@ static int usbstrg_setup(FAR struct usbdev_s *dev, if (ret >= 0) { - ctrlreq->len = min(len, ret); + ctrlreq->len = MIN(len, ret); ctrlreq->flags = USBDEV_REQFLAGS_NULLPKT; ret = EP_SUBMIT(dev->ep0, ctrlreq); if (ret < 0) @@ -800,10 +828,12 @@ static void usbstrg_disconnect(FAR struct usbdev_s *dev) irqrestore(flags); /* Perform the soft connect function so that we will we can be - * re-enumerated. + * re-enumerated (unless we are part of a composite device) */ - DEV_CONNECT(dev); +#ifndef CONFIG_USBSTRG_COMPOSITE + DEV_CONNECT(dev); +#endif } /**************************************************************************** @@ -1548,14 +1578,16 @@ int usbstrg_exportluns(FAR void *handle) goto errout_with_mutex; } - /* Register the USB storage class driver */ + /* Register the USB storage class driver (unless we are part of a composite device) */ +#ifndef CONFIG_CDCSER_COMPOSITE ret = usbdev_register(&drvr->drvr); if (ret != OK) { usbtrace(TRACE_CLSERROR(USBSTRG_TRACEERR_DEVREGISTER), (uint16_t)-ret); goto errout_with_mutex; } +#endif /* Signal to start the thread */ @@ -1632,9 +1664,11 @@ void usbstrg_uninitialize(FAR void *handle) } priv->thread = 0; - /* Unregister the driver */ + /* Unregister the driver (unless we are a part of a composite device */ +#ifndef CONFIG_CDCSER_COMPOSITE usbdev_unregister(&alloc->drvr.drvr); +#endif /* Uninitialize and release the LUNs */ diff --git a/nuttx/drivers/usbdev/msc.h b/nuttx/drivers/usbdev/msc.h index f73d1af9cc..1c23f50fdd 100644 --- a/nuttx/drivers/usbdev/msc.h +++ b/nuttx/drivers/usbdev/msc.h @@ -71,6 +71,19 @@ # define CONFIG_USBSTRG_STRBASE (4) #endif +/* Interface IDs. If the mass storage driver is built as a component of a + * composite device, then the interface IDs may need to be offset. + */ + +#ifndef CONFIG_USBSTRG_COMPOSITE +# undef CONFIG_USBSTRG_IFNOBASE +# define CONFIG_USBSTRG_IFNOBASE 0 +#endif + +#ifndef CONFIG_USBSTRG_IFNOBASE +# define CONFIG_USBSTRG_IFNOBASE 0 +#endif + /* Number of requests in the write queue */ #ifndef CONFIG_USBSTRG_NWRREQS @@ -296,8 +309,9 @@ /* Configuration Descriptor */ #define USBSTRG_NINTERFACES (1) /* Number of interfaces in the configuration */ -#define USBSTRG_INTERFACEID (0) -#define USBSTRG_ALTINTERFACEID (0) +#define USBSTRG_INTERFACEID (CONFIG_USBSTRG_IFNOBASE+0) +#define USBSTRG_ALTINTERFACEID USBSTRG_INTERFACEID + #define USBSTRG_CONFIGIDNONE (0) /* Config ID means to return to address mode */ #define USBSTRG_CONFIGID (1) /* The only supported configuration ID */ @@ -375,14 +389,14 @@ #define USBSTRG_DRVR_WRITE(l,b,s,n) ((l)->inode->u.i_bops->write((l)->inode,b,s,n)) #define USBSTRG_DRVR_GEOMETRY(l,g) ((l)->inode->u.i_bops->geometry((l)->inode,g)) -/* Everpresent min/max macros ***********************************************/ +/* Everpresent MIN/MAX macros ***********************************************/ -#ifndef min -# define min(a,b) ((a) < (b) ? (a) : (b)) +#ifndef MIN +# define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif -#ifndef max -# define max(a,b) ((a) > (b) ? (a) : (b)) +#ifndef MAX +# define MAX(a,b) ((a) > (b) ? (a) : (b)) #endif /**************************************************************************** @@ -503,10 +517,26 @@ extern "C" /* String *******************************************************************/ -EXTERN const char g_vendorstr[]; -EXTERN const char g_productstr[]; -EXTERN const char g_serialstr[]; +/* Mass storage class vendor/product/serial number strings */ +#ifndef CONFIG_USBSTRG_COMPOSITE +EXTERN const char g_mscvendorstr[]; +EXTERN const char g_mscproductstr[]; +EXTERN const char g_mscserialstr[]; + +/* If we are using a composite device, then vendor/product/serial number strings + * are provided by the composite device logic. + */ + +#else +EXTERN const char g_compvendorstr[]; +EXTERN const char g_compproductstr[]; +EXTERN const char g_compserialstr[]; + +#define g_mscvendorstr g_compvendorstr +#define g_mscproductstr g_compproductstr +#define g_mscserialstr g_compserialstr +#endif /************************************************************************************ * Public Function Prototypes ************************************************************************************/ diff --git a/nuttx/drivers/usbdev/msc_descriptors.c b/nuttx/drivers/usbdev/msc_descriptors.c index 7cb77d8a19..8d9e8a8393 100644 --- a/nuttx/drivers/usbdev/msc_descriptors.c +++ b/nuttx/drivers/usbdev/msc_descriptors.c @@ -213,9 +213,9 @@ static const struct usb_epdesc_s g_hsepbulkindesc = /* Strings ******************************************************************/ #ifndef CONFIG_USBSTRG_COMPOSITE -const char g_vendorstr[] = CONFIG_USBSTRG_VENDORSTR; -const char g_productstr[] = CONFIG_USBSTRG_PRODUCTSTR; -const char g_serialstr[] = CONFIG_USBSTRG_SERIALSTR; +const char g_msccendorstr[] = CONFIG_USBSTRG_VENDORSTR; +const char g_mscproductstr[] = CONFIG_USBSTRG_PRODUCTSTR; +const char g_mscserialstr[] = CONFIG_USBSTRG_SERIALSTR; #endif /**************************************************************************** diff --git a/nuttx/drivers/usbdev/msc_scsi.c b/nuttx/drivers/usbdev/msc_scsi.c index d5b0162e06..6302b1a700 100644 --- a/nuttx/drivers/usbdev/msc_scsi.c +++ b/nuttx/drivers/usbdev/msc_scsi.c @@ -606,17 +606,17 @@ static inline int usbstrg_cmdinquiry(FAR struct usbstrg_dev_s *priv, memset(response->vendorid, ' ', 8+16+4); - len = strlen(g_vendorstr); + len = strlen(g_mscvendorstr); DEBUGASSERT(len <= 8); - memcpy(response->vendorid, g_vendorstr, len); + memcpy(response->vendorid, g_mscvendorstr, len); - len = strlen(g_productstr); + len = strlen(g_mscproductstr); DEBUGASSERT(len <= 16); - memcpy(response->productid, g_productstr, len); + memcpy(response->productid, g_mscproductstr, len); - len = strlen(g_serialstr); + len = strlen(g_mscserialstr); DEBUGASSERT(len <= 4); - memcpy(response->productid, g_serialstr, len); + memcpy(response->productid, g_mscserialstr, len); } } @@ -1545,7 +1545,7 @@ static int usbstrg_idlestate(FAR struct usbstrg_dev_s *priv) /* Handle the CBW */ usbstrg_dumpdata("SCSCI CBW", (uint8_t*)cbw, USBSTRG_CBW_SIZEOF - USBSTRG_MAXCDBLEN); - usbstrg_dumpdata(" CDB", cbw->cdb, min(cbw->cdblen, USBSTRG_MAXCDBLEN)); + usbstrg_dumpdata(" CDB", cbw->cdb, MIN(cbw->cdblen, USBSTRG_MAXCDBLEN)); /* Check for properly formatted CBW? */ @@ -2045,7 +2045,7 @@ static int usbstrg_cmdreadstate(FAR struct usbstrg_dev_s *priv) src = &priv->iobuffer[lun->sectorsize - priv->nsectbytes]; dest = &req->buf[priv->nreqbytes]; - nbytes = min(CONFIG_USBSTRG_BULKINREQLEN - priv->nreqbytes, priv->nsectbytes); + nbytes = MIN(CONFIG_USBSTRG_BULKINREQLEN - priv->nreqbytes, priv->nsectbytes); /* Copy the data from the sector buffer to the USB request and update counts */ @@ -2178,7 +2178,7 @@ static int usbstrg_cmdwritestate(FAR struct usbstrg_dev_s *priv) src = &req->buf[xfrd - priv->nreqbytes]; dest = &priv->iobuffer[priv->nsectbytes]; - nbytes = min(lun->sectorsize - priv->nsectbytes, priv->nreqbytes); + nbytes = MIN(lun->sectorsize - priv->nsectbytes, priv->nreqbytes); /* Copy the data from the sector buffer to the USB request and update counts */ diff --git a/nuttx/include/nuttx/usb/cdc_serial.h b/nuttx/include/nuttx/usb/cdc_serial.h index 8a975666a3..33ad03bb73 100644 --- a/nuttx/include/nuttx/usb/cdc_serial.h +++ b/nuttx/include/nuttx/usb/cdc_serial.h @@ -290,6 +290,50 @@ typedef FAR void (*cdcser_callback_t)(enum cdcser_event_e event); * Public Function Prototypes ****************************************************************************/ +/**************************************************************************** + * Name: board_cdcclassobject + * + * Description: + * If the CDC serial class driver is part of composite device, then + * board-specific logic must provide board_cdcclassobject(). In the simplest + * case, board_cdcclassobject() is simply a wrapper around cdcser_classobject() + * that provides the correct device minor number. + * + * Input Parameters: + * classdev - The location to return the CDC serial class' device + * instance. + * + * Returned Value: + * 0 on success; a negated errno on failure + * + ****************************************************************************/ + +#if defined(CONFIG_USBDEV_COMPOSITE) && defined(CONFIG_CDCSER_COMPOSITE) +EXTERN int board_cdcclassobject(FAR struct usbdevclass_driver_s **classdev); +#endif + +/**************************************************************************** + * Name: cdcser_classobject + * + * Description: + * Register USB serial port (and USB serial console if so configured) and + * return the class object. + * + * Input Parameter: + * minor - Device minor number. E.g., minor 0 would correspond to + * /dev/ttyUSB0. + * classdev - The location to return the CDC serial class' device + * instance. + * + * Returned Value: + * A pointer to the allocated class object (NULL on failure). + * + ****************************************************************************/ + +#if defined(CONFIG_USBDEV_COMPOSITE) && defined(CONFIG_CDCSER_COMPOSITE) +int cdcser_classobject(int minor, FAR struct usbdevclass_driver_s **classdev); +#endif + /**************************************************************************** * Name: cdcser_initialize * diff --git a/nuttx/include/nuttx/usb/usbdev.h b/nuttx/include/nuttx/usb/usbdev.h index bd9a66db82..8c4b3ff263 100644 --- a/nuttx/include/nuttx/usb/usbdev.h +++ b/nuttx/include/nuttx/usb/usbdev.h @@ -167,11 +167,13 @@ /* Invoked on USB suspend. */ -#define CLASS_SUSPEND(drvr,dev) (drvr)->ops->suspend ? (drvr)->ops->suspend(dev) : (void) +#define CLASS_SUSPEND(drvr,dev) \ + do { if ((drvr)->ops->suspend) (drvr)->ops->suspend(dev); } while (0) /* Invoked on USB resume */ -#define CLASS_RESUME(drvr,dev) (drvr)->ops->resume ? (drvr)->ops->resume(dev) : (void) +#define CLASS_RESUME(drvr,dev) \ + do { if ((drvr)->ops->resume) (drvr)->ops->resume(dev); } while (0) /* Device speeds */ @@ -353,6 +355,33 @@ EXTERN int usbdev_unregister(FAR struct usbdevclass_driver_s *driver); EXTERN int usbdev_serialinitialize(int minor); +/**************************************************************************** + * Name: board_mscclassobject + * + * Description: + * If the mass storage class driver is part of composite device, then + * its instantiation and configuration is a multi-step, board-specific, + * process (See comments for usbstrg_configure below). In this case, + * board-specific logic must provide board_mscclassobject(). + * + * board_mscclassobject() is called from the composite driver. It must + * encapsulate the instantiation and configuration of the mass storage + * class and the return the mass storage device's class driver instance + * to the composite dirver. + * + * Input Parameters: + * classdev - The location to return the mass storage class' device + * instance. + * + * Returned Value: + * 0 on success; a negated errno on failure + * + ****************************************************************************/ + +#if defined(CONFIG_USBDEV_COMPOSITE) && defined(CONFIG_USBSTRG_COMPOSITE) +EXTERN int board_mscclassobject(FAR struct usbdevclass_driver_s **classdev); +#endif + /**************************************************************************** * Name: usbstrg_configure * @@ -434,6 +463,24 @@ EXTERN int usbstrg_unbindlun(FAR void *handle, unsigned int lunno); EXTERN int usbstrg_exportluns(FAR void *handle); +/**************************************************************************** + * Name: cdcser_classobject + * + * Description: + * . + * + * Input Parameters: + * handle - The handle returned by a previous call to usbstrg_configure(). + * + * Returned Value: + * 0 on success; a negated errno on failure + * + ****************************************************************************/ + +#if defined(CONFIG_USBDEV_COMPOSITE) && defined(CONFIG_USBSTRG_COMPOSITE) +EXTERN int usbstrg_classobject(FAR void *handle, FAR struct usbdevclass_driver_s **classdev); +#endif + /**************************************************************************** * Name: usbstrg_uninitialize * diff --git a/nuttx/include/nuttx/usb/usbdev_trace.h b/nuttx/include/nuttx/usb/usbdev_trace.h index 4ffd790572..ebf8831329 100644 --- a/nuttx/include/nuttx/usb/usbdev_trace.h +++ b/nuttx/include/nuttx/usb/usbdev_trace.h @@ -225,6 +225,25 @@ /* USB Storage driver class events ******************************************/ +#define USBCOMPOSITE_TRACEERR_REQRESULT 0x0001 +#define USBCOMPOSITE_TRACEERR_ALLOCCTRLREQ 0x0002 +#define USBCOMPOSITE_TRACEERR_INVALIDARG 0x0003 +#define USBCOMPOSITE_TRACEERR_EP0NOTBOUND 0x0004 +#define COMPOSITE_TRACEERR_SETUPINVALIDARGS 0x0005 +#define COMPOSITE_TRACEERR_EP0NOTBOUND2 0x0006 +#define COMPOSITE_TRACEERR_GETUNKNOWNDESC 0x0007 +#define COMPOSITE_TRACEERR_UNSUPPORTEDSTDREQ 0x0008 +#define COMPOSITE_TRACEERR_EPRESPQ 0x0009 +#define USBCOMPOSITE_TRACEERR_ALLOCDEVSTRUCT 0x000a +#define USBCOMPOSITE_TRACEERR_CLASSOBJECT 0x000b +#define USBCOMPOSITE_TRACEERR_DEVREGISTER 0x000c +#define USBCOMPOSITE_TRACEERR_INVALIDARG 0x000d +#define USBCOMPOSITE_TRACEERR_INVALIDARG 0x000f +#define USBCOMPOSITE_TRACEERR_INVALIDARG 0x0010 +#define USBCOMPOSITE_TRACEERR_INVALIDARG 0x0011 + +/* USB Storage driver class events ******************************************/ + /* State transitions */ #define USBSTRG_CLASSSTATE_IDLECMDPARSE 0x0001