diff --git a/configs/boardctl.c b/configs/boardctl.c index 208394e49f3..bbdd3ef7706 100644 --- a/configs/boardctl.c +++ b/configs/boardctl.c @@ -1,7 +1,7 @@ /**************************************************************************** * configs/boardctl.c * - * Copyright (C) 2015-2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2015-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -181,8 +181,84 @@ static inline int boardctl_usbdevctrl(FAR struct boardioc_usbdev_ctrl_s *ctrl) case BOARDIOC_USBDEV_CONNECT: /* Connect the Composite device */ { + /* Here we are composing the configuration of the usb composite device. + * + * The standard is to use one CDC/ACM and one USB mass storage device. + */ + + struct composite_devdesc_s dev[2]; + int ifnobase = 0; + int strbase = COMPOSITE_NSTRIDS; + DEBUGASSERT(ctrl->handle != NULL); - *ctrl->handle = composite_initialize(); + + /* Configure the CDC/ACM device */ + + /* Ask the cdcacm driver to fill in the constants we didn't + * know here. + */ + + cdcacm_get_composite_devdesc(&dev[0]); + + /* Overwrite and correct some values... */ + /* The callback functions for the CDC/ACM class */ + + dev[0].board_classobject = board_cdcclassobject; + dev[0].board_uninitialize = board_cdcuninitialize; + + /* Interfaces */ + + dev[0].usb_dev_desc.ifnobase = ifnobase; /* Offset to Interface-IDs */ + dev[0].minor = CONFIG_SYSTEM_COMPOSITE_TTYUSB; /* The minor interface number */ + + /* Strings */ + + dev[0].usb_dev_desc.strbase = strbase; /* Offset to String Numbers */ + + /* Endpoints */ + + dev[0].usb_dev_desc.epno[CDCACM_EP_INTIN_IDX] = 3; + dev[0].usb_dev_desc.epno[CDCACM_EP_BULKIN_IDX] = 4; + dev[0].usb_dev_desc.epno[CDCACM_EP_BULKOUT_IDX] = 5; + + /* Count up the base numbers */ + + ifnobase += dev[0].usb_dev_desc.ninterfaces; + strbase += dev[0].usb_dev_desc.nstrings; + + /* Configure the mass storage device device */ + /* Ask the usbmsc driver to fill in the constants we didn't + * know here. + */ + + usbmsc_get_composite_devdesc(&dev[1]); + + /* Overwrite and correct some values... */ + /* The callback functions for the USBMSC class */ + + dev[1].board_classobject = board_mscclassobject; + dev[1].board_uninitialize = board_mscuninitialize; + + /* Interfaces */ + + dev[1].usb_dev_desc.ifnobase = ifnobase; /* Offset to Interface-IDs */ + dev[1].minor = CONFIG_SYSTEM_COMPOSITE_DEVMINOR1; /* The minor interface number */ + + /* Strings */ + + dev[1].usb_dev_desc.strbase = strbase; /* Offset to String Numbers */ + + /* Endpoints */ + + dev[1].usb_dev_desc.epno[USBMSC_EP_BULKIN_IDX] = 1; + dev[1].usb_dev_desc.epno[USBMSC_EP_BULKOUT_IDX] = 2; + + /* Count up the base numbers */ + + ifnobase += dev[1].usb_dev_desc.ninterfaces; + strbase += dev[1].usb_dev_desc.nstrings; + + *ctrl->handle = composite_initialize(2, dev); if (*ctrl->handle == NULL) { ret = -EIO; diff --git a/drivers/usbdev/Kconfig b/drivers/usbdev/Kconfig index f68b2be67f3..a9cbda09a91 100644 --- a/drivers/usbdev/Kconfig +++ b/drivers/usbdev/Kconfig @@ -322,33 +322,10 @@ menuconfig CDCACM_COMPOSITE Configure the CDC serial driver as part of a composite driver (only if USBDEV_COMPOSITE is also defined) -if CDCACM_COMPOSITE +if !CDCACM_COMPOSITE -config CDCACM_IFNOBASE - int "Offset the CDC/ACM interface numbers" - default 0 - ---help--- - If the CDC driver is part of a composite device, then this may need to - be defined to offset the CDC/ACM interface numbers so that they are - unique and contiguous. When used with the Mass Storage driver, the - correct value for this offset is zero. - -config CDCACM_STRBASE - int "Offset the CDC/ACM string numbers" - default 4 - ---help--- - If the CDC driver is part of a composite device, then this may need to - be defined to offset the CDC/ACM string numbers so that they are - unique and contiguous. When used with the Mass Storage driver, the - correct value for this offset is four (this value actuallly only needs - to be defined if names are provided for the Notification interface, - config CDCACM_NOTIFSTR, or the data interface, CDCACM_DATAIFSTR). - - The default of four accounts for strings IDs 0-3 used by the composite - descriptors. Any additional CDC/ACM string descripts must then begin - with string index four. - -endif +# In a composite device the EP0 config comes from the composite device +# and the EP-Number is configured dynamically via composite_initialize config CDCACM_EP0MAXPACKET int "Endpoint 0 max packet size" @@ -363,6 +340,8 @@ config CDCACM_EPINTIN The logical 7-bit address of a hardware endpoint that supports interrupt IN operation. Default 1. +endif + config CDCACM_EPINTIN_FSSIZE int "Interupt IN full speed MAXPACKET size" default 64 @@ -377,6 +356,11 @@ config CDCACM_EPINTIN_HSSIZE Max package size for the interrupt IN endpoint if high speed mode. Default 64. +if !CDCACM_COMPOSITE + +# In a composite device the EP-Number is configured dynamically via +# composite_initialize + config CDCACM_EPBULKOUT int "Bulk OUT endpoint number" default 3 @@ -384,6 +368,8 @@ config CDCACM_EPBULKOUT The logical 7-bit address of a hardware endpoint that supports bulk OUT operation. Default: 3 +endif + config CDCACM_EPBULKOUT_FSSIZE int "Bulk OUT full speed MAXPACKET size" default 64 @@ -398,6 +384,11 @@ config CDCACM_EPBULKOUT_HSSIZE Max package size for the bulk OUT endpoint if high speed mode. Default 512. +if !CDCACM_COMPOSITE + +# In a composite device the EP-Number is configured dynamically via +# composite_initialize + config CDCACM_EPBULKIN int "Bulk IN endpoint number" default 2 @@ -405,6 +396,8 @@ config CDCACM_EPBULKIN The logical 7-bit address of a hardware endpoint that supports bulk IN operation. Default: 2 +endif + config CDCACM_EPBULKIN_FSSIZE int "Bulk IN full speed MAXPACKET size" default 64 @@ -468,6 +461,11 @@ config CDCACM_TXBUFSIZE will hold one request of size 768; a buffer size of 193 will hold two requests of size 96 bytes. +if !CDCACM_COMPOSITE + +# In a composite device the Vendor- and Product-ID is given by the composite +# device + config CDCACM_VENDORID hex "Vendor ID" default 0x0525 @@ -493,6 +491,7 @@ config CDCACM_PRODUCTSTR string "Product string" default "CDC/ACM Serial" +endif # !CDCACM_COMPOSITE endif # CDCACM menuconfig USBMSC @@ -530,38 +529,17 @@ config USBMSC_COMPOSITE Configure the mass storage driver as part of a composite driver (only if USBDEV_COMPOSITE is also defined) -config USBMSC_IFNOBASE - int "Offset the mass storage interface number" - default 2 - depends on USBMSC_COMPOSITE - ---help--- - If the CDC driver is part of a composite device, then this may need to - be defined to offset the mass storage interface number so that it is - unique and contiguous. When used with the CDC/ACM driver, the - correct value for this offset is two (because of the two CDC/ACM - interfaces that will precede it). - -config USBMSC_STRBASE - int "Offset the mass storage string numbers" - default 4 - depends on USBMSC_COMPOSITE - ---help--- - If the CDC driver is part of a composite device, then this may need to - be defined to offset the mass storage string numbers so that they are - unique and contiguous. When used with the CDC/ACM driver, the - correct value for this offset is four (or perhaps 5 or 6, depending - on if CDCACM_NOTIFSTR or CDCACM_DATAIFSTR are defined). - - String IDS 0-3 are used by the composite descriptors. This amount - may need to be incremented to account for string IDs used by other - members of the composite. - config USBMSC_EP0MAXPACKET int "Max packet size for endpoint 0" default 64 ---help--- Max packet size for endpoint 0 +if !USBMSC_COMPOSITE + +# In a composite device the EP-Number and STR-Number is configured +# dynamically via composite_initialize + config USBMSC_EPBULKOUT int "Bulk OUT endpoint number" default 2 @@ -576,6 +554,8 @@ config USBMSC_EPBULKIN The logical 7-bit address of a hardware endpoints that support bulk OUT and IN operations +endif + config USBMSC_NWRREQS int "The number of write requests that can be in flight" default 4 @@ -613,6 +593,11 @@ config USBMSC_BULKOUTREQLEN beyond the maximum size of one packet. Default: 512 or 64 bytes (depending upon if dual speed operation is supported or not). +if !USBMSC_COMPOSITE + +# In a composite device the Vendor- and Product-IDs are handled by the +# composite device + config USBMSC_VENDORID hex "Mass storage Vendor ID" default 0x584e @@ -638,6 +623,8 @@ config USBMSC_PRODUCTSTR string "Mass storage product string" default "Mass Storage" +endif # !USBMSC_COMPOSITE + config USBMSC_VERSIONNO hex "USB MSC Version Number" default "0x399" diff --git a/drivers/usbdev/cdcacm.c b/drivers/usbdev/cdcacm.c index 15f92dd9aea..c804dd6c5dd 100644 --- a/drivers/usbdev/cdcacm.c +++ b/drivers/usbdev/cdcacm.c @@ -1,7 +1,7 @@ /**************************************************************************** * drivers/usbdev/cdcacm.c * - * Copyright (C) 2011-2013, 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2011-2013, 2016-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -64,7 +64,7 @@ #include "cdcacm.h" -#ifdef CONFIG_USBMSC_COMPOSITE +#ifdef CONFIG_CDCACM_COMPOSITE # include # include "composite.h" #endif @@ -105,6 +105,8 @@ struct cdcacm_dev_s FAR struct usbdev_req_s *ctrlreq; /* Allocated control request */ struct sq_queue_s reqlist; /* List of write request containers */ + struct usbdev_description_s devdesc; + /* Pre-allocated write request containers. The write requests will * be linked in a free list (reqlist), and used to send requests to * EPBULKIN; Read requests will be queued in the EBULKOUT. @@ -157,10 +159,10 @@ static void cdcacm_freereq(FAR struct usbdev_ep_s *ep, /* Configuration ***********************************************************/ static void cdcacm_resetconfig(FAR struct cdcacm_dev_s *priv); -#ifdef CONFIG_USBDEV_DUALSPEED static int cdcacm_epconfigure(FAR struct usbdev_ep_s *ep, - enum cdcacm_epdesc_e epid, uint16_t mxpacket, bool last); -#endif + enum cdcacm_epdesc_e epid, bool last, + FAR struct usbdev_description_s *devdesc, + bool hispeed); static int cdcacm_setconfig(FAR struct cdcacm_dev_s *priv, uint8_t config); @@ -623,16 +625,15 @@ static void cdcacm_resetconfig(FAR struct cdcacm_dev_s *priv) * ****************************************************************************/ -#ifdef CONFIG_USBDEV_DUALSPEED static int cdcacm_epconfigure(FAR struct usbdev_ep_s *ep, - enum cdcacm_epdesc_e epid, uint16_t mxpacket, - bool last) + enum cdcacm_epdesc_e epid, bool last, + FAR struct usbdev_description_s *devdesc, + bool hispeed) { struct usb_epdesc_s epdesc; - cdcacm_mkepdesc(epid, mxpacket, &epdesc); + cdcacm_copy_epdesc(epid, &epdesc, devdesc, hispeed); return EP_CONFIGURE(ep, &epdesc, last); } -#endif /**************************************************************************** * Name: cdcacm_setconfig @@ -690,14 +691,14 @@ static int cdcacm_setconfig(FAR struct cdcacm_dev_s *priv, uint8_t config) #ifdef CONFIG_USBDEV_DUALSPEED if (priv->usbdev->speed == USB_SPEED_HIGH) { - ret = cdcacm_epconfigure(priv->epintin, CDCACM_EPINTIN, - CONFIG_CDCACM_EPINTIN_HSSIZE, false); + ret = cdcacm_epconfigure(priv->epintin, CDCACM_EPINTIN, false, + &priv->devdesc, true); } else #endif { - ret = EP_CONFIGURE(priv->epintin, - cdcacm_getepdesc(CDCACM_EPINTIN), false); + ret = cdcacm_epconfigure(priv->epintin, CDCACM_EPINTIN, false, + &priv->devdesc, false); } if (ret < 0) @@ -713,14 +714,14 @@ static int cdcacm_setconfig(FAR struct cdcacm_dev_s *priv, uint8_t config) #ifdef CONFIG_USBDEV_DUALSPEED if (priv->usbdev->speed == USB_SPEED_HIGH) { - ret = cdcacm_epconfigure(priv->epbulkin, CDCACM_EPBULKIN, - CONFIG_CDCACM_EPBULKIN_HSSIZE, false); + ret = cdcacm_epconfigure(priv->epbulkin, CDCACM_EPBULKIN, false, + &priv->devdesc, true); } else #endif { - ret = EP_CONFIGURE(priv->epbulkin, - cdcacm_getepdesc(CDCACM_EPBULKIN), false); + ret = cdcacm_epconfigure(priv->epbulkin, CDCACM_EPBULKIN, false, + &priv->devdesc, false); } if (ret < 0) @@ -736,14 +737,14 @@ static int cdcacm_setconfig(FAR struct cdcacm_dev_s *priv, uint8_t config) #ifdef CONFIG_USBDEV_DUALSPEED if (priv->usbdev->speed == USB_SPEED_HIGH) { - ret = cdcacm_epconfigure(priv->epbulkout, CDCACM_EPBULKOUT, - CONFIG_CDCACM_EPBULKOUT_HSSIZE, true); + ret = cdcacm_epconfigure(priv->epbulkout, CDCACM_EPBULKOUT, true, + &priv->devdesc, true); } else #endif { - ret = EP_CONFIGURE(priv->epbulkout, - cdcacm_getepdesc(CDCACM_EPBULKOUT), true); + ret = cdcacm_epconfigure(priv->epbulkout, CDCACM_EPBULKOUT, true, + &priv->devdesc, false); } if (ret < 0) @@ -967,7 +968,7 @@ static int cdcacm_bind(FAR struct usbdevclass_driver_s *driver, * EP0). */ -#ifndef CONFIG_USBMSC_COMPOSITE +#ifndef CONFIG_CDCACM_COMPOSITE dev->ep0->priv = priv; #endif @@ -992,7 +993,8 @@ static int cdcacm_bind(FAR struct usbdevclass_driver_s *driver, /* Pre-allocate the IN interrupt endpoint */ - priv->epintin = DEV_ALLOCEP(dev, CDCACM_EPINTIN_ADDR, true, USB_EP_ATTR_XFER_INT); + priv->epintin = DEV_ALLOCEP(dev, CDCACM_MKEPINTIN(&priv->devdesc), + true, USB_EP_ATTR_XFER_INT); if (!priv->epintin) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPINTINALLOCFAIL), 0); @@ -1004,7 +1006,8 @@ static int cdcacm_bind(FAR struct usbdevclass_driver_s *driver, /* Pre-allocate the IN bulk endpoint */ - priv->epbulkin = DEV_ALLOCEP(dev, CDCACM_EPINBULK_ADDR, true, USB_EP_ATTR_XFER_BULK); + priv->epbulkin = DEV_ALLOCEP(dev, CDCACM_MKEPBULKIN(&priv->devdesc), + true, USB_EP_ATTR_XFER_BULK); if (!priv->epbulkin) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPBULKINALLOCFAIL), 0); @@ -1016,7 +1019,8 @@ static int cdcacm_bind(FAR struct usbdevclass_driver_s *driver, /* Pre-allocate the OUT bulk endpoint */ - priv->epbulkout = DEV_ALLOCEP(dev, CDCACM_EPOUTBULK_ADDR, false, USB_EP_ATTR_XFER_BULK); + priv->epbulkout = DEV_ALLOCEP(dev, CDCACM_MKEPBULKOUT(&priv->devdesc), + false, USB_EP_ATTR_XFER_BULK); if (!priv->epbulkout) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPBULKOUTALLOCFAIL), 0); @@ -1342,7 +1346,7 @@ static int cdcacm_setup(FAR struct usbdevclass_driver_s *driver, #ifdef CONFIG_USBDEV_DUALSPEED ret = cdcacm_mkcfgdesc(ctrlreq->buf, dev->speed, ctrl->req); #else - ret = cdcacm_mkcfgdesc(ctrlreq->buf); + ret = cdcacm_mkcfgdesc(ctrlreq->buf, 0); #endif } break; @@ -1403,8 +1407,10 @@ static int cdcacm_setup(FAR struct usbdevclass_driver_s *driver, if (ctrl->type == USB_REQ_RECIPIENT_INTERFACE && priv->config == CDCACM_CONFIGID) { - if ((index == CDCACM_NOTIFID && value == CDCACM_NOTALTIFID) || - (index == CDCACM_DATAIFID && value == CDCACM_DATAALTIFID)) + if ((index == priv->devdesc.ifnobase && + value == CDCACM_NOTALTIFID) || + (index == (priv->devdesc.ifnobase + 1) && + value == CDCACM_DATAALTIFID)) { cdcacm_resetconfig(priv); cdcacm_setconfig(priv, priv->config); @@ -1419,8 +1425,10 @@ static int cdcacm_setup(FAR struct usbdevclass_driver_s *driver, if (ctrl->type == (USB_DIR_IN | USB_REQ_RECIPIENT_INTERFACE) && priv->config == CDCACM_CONFIGIDNONE) { - if ((index == CDCACM_NOTIFID && value == CDCACM_NOTALTIFID) || - (index == CDCACM_DATAIFID && value == CDCACM_DATAALTIFID)) + if ((index == priv->devdesc.ifnobase && + value == CDCACM_NOTALTIFID) || + (index == (priv->devdesc.ifnobase + 1) && + value == CDCACM_DATAALTIFID)) { *(FAR uint8_t *) ctrlreq->buf = value; ret = 1; @@ -1454,7 +1462,7 @@ static int cdcacm_setup(FAR struct usbdevclass_driver_s *driver, case ACM_GET_LINE_CODING: { if (ctrl->type == (USB_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE) && - index == CDCACM_NOTIFID) + index == priv->devdesc.ifnobase) { /* Return the current line status from the private data structure */ @@ -1463,7 +1471,8 @@ static int cdcacm_setup(FAR struct usbdevclass_driver_s *driver, } else { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDCLASSREQ), ctrl->type); + usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDCLASSREQ), + ctrl->type); } } break; @@ -1476,7 +1485,7 @@ static int cdcacm_setup(FAR struct usbdevclass_driver_s *driver, { if (ctrl->type == (USB_DIR_OUT | USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE) && len == SIZEOF_CDC_LINECODING && /* dataout && len == outlen && */ - index == CDCACM_NOTIFID) + index == priv->devdesc.ifnobase) { /* Save the new line coding in the private data structure. NOTE: * that this is conditional now because not all device controller @@ -1516,7 +1525,7 @@ static int cdcacm_setup(FAR struct usbdevclass_driver_s *driver, case ACM_SET_CTRL_LINE_STATE: { if (ctrl->type == (USB_DIR_OUT | USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE) && - index == CDCACM_NOTIFID) + index == priv->devdesc.ifnobase) { /* Save the control line state in the private data structure. Only bits * 0 and 1 have meaning. Respond with a zero length packet. @@ -1546,7 +1555,7 @@ static int cdcacm_setup(FAR struct usbdevclass_driver_s *driver, case ACM_SEND_BREAK: { if (ctrl->type == (USB_DIR_OUT | USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE) && - index == CDCACM_NOTIFID) + index == priv->devdesc.ifnobase) { /* If there is a registered callback to handle the SendBreak request, * then callout now. Respond with a zero length packet. @@ -2312,7 +2321,8 @@ static bool cdcuart_txempty(FAR struct uart_dev_s *dev) #ifndef CONFIG_CDCACM_COMPOSITE static #endif -int cdcacm_classobject(int minor, FAR struct usbdevclass_driver_s **classdev) +int cdcacm_classobject(int minor, FAR struct usbdev_description_s *devdesc, + FAR struct usbdevclass_driver_s **classdev) { FAR struct cdcacm_alloc_s *alloc; FAR struct cdcacm_dev_s *priv; @@ -2340,6 +2350,8 @@ int cdcacm_classobject(int minor, FAR struct usbdevclass_driver_s **classdev) sq_init(&priv->reqlist); priv->minor = minor; + memcpy(&priv->devdesc, devdesc, + sizeof(struct usbdev_description_s)); /* Fake line status */ @@ -2427,11 +2439,31 @@ errout_with_class: int cdcacm_initialize(int minor, FAR void **handle) { FAR struct usbdevclass_driver_s *drvr = NULL; + struct usbdev_description_s devdesc; int ret; + memset(&devdesc, 0, sizeof(struct usbdev_description_s)); + + /* Interfaces */ + + devdesc.ninterfaces = CDCACM_NINTERFACES; /* Number of interfaces in the configuration */ + devdesc.ifnobase = 0; /* Offset to Interface-IDs */ + + /* Strings */ + + devdesc.nstrings = CDCACM_NSTRIDS; /* Number of Strings */ + devdesc.strbase = 0; /* Offset to String Numbers */ + + /* Endpoints */ + + devdesc.nendpoints = CDCACM_NUM_EPS; + devdesc.epno[CDCACM_EP_INTIN_IDX] = 0; + devdesc.epno[CDCACM_EP_BULKIN_IDX] = 1; + devdesc.epno[CDCACM_EP_BULKOUT_IDX] = 2; + /* Get an instance of the serial driver class object */ - ret = cdcacm_classobject(minor, &drvr); + ret = cdcacm_classobject(minor, &devdesc, &drvr); if (ret == OK) { /* Register the USB serial class driver */ @@ -2549,3 +2581,60 @@ void cdcacm_uninitialize(FAR void *handle) priv->minor = (uint8_t)-1; #endif } + +/**************************************************************************** + * Name: cdcacm_get_composite_devdesc + * + * Description: + * Helper function to fill in some constants into the composite + * configuration struct. + * + * Input Parameters: + * dev - Pointer to the configuration struct we should fill + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if defined(CONFIG_USBDEV_COMPOSITE) && defined(CONFIG_CDCACM_COMPOSITE) +void cdcacm_get_composite_devdesc(struct composite_devdesc_s *dev) +{ + /* The callback functions for the CDC/ACM class */ + + dev->mkconfdesc = cdcacm_mkcfgdesc; + dev->mkstrdesc = cdcacm_mkstrdesc; + dev->board_classobject = 0; + dev->board_uninitialize = 0; + + dev->nconfigs = CDCACM_NCONFIGS; /* Number of configurations supported */ + dev->configid = CDCACM_CONFIGID; /* The only supported configuration ID */ + + /* Let the construction function calculate the size of the config descriptor */ + +#ifdef CONFIG_USBDEV_DUALSPEED + dev->cfgdescsize = cdcacm_mkcfgdesc(NULL, NULL, USB_SPEED_UNKNOWN, 0); +#else + dev->cfgdescsize = cdcacm_mkcfgdesc(NULL, NULL); +#endif + + dev->minor = 0; /* The minor interface number */ + + /* Interfaces */ + + dev->devdesc.ninterfaces = CDCACM_NINTERFACES; /* Number of interfaces in the configuration */ + dev->devdesc.ifnobase = 0; /* Offset to Interface-IDs */ + + /* Strings */ + + dev->devdesc.nstrings = CDCACM_NSTRIDS; /* Number of Strings */ + dev->devdesc.strbase = 0; /* Offset to String Numbers */ + + /* Endpoints */ + + dev->devdesc.nendpoints = CDCACM_NUM_EPS; + dev->devdesc.epno[CDCACM_EP_INTIN_IDX] = 0; + dev->devdesc.epno[CDCACM_EP_BULKIN_IDX] = 0; + dev->devdesc.epno[CDCACM_EP_BULKOUT_IDX] = 0; +} +#endif diff --git a/drivers/usbdev/cdcacm.h b/drivers/usbdev/cdcacm.h index 4b0803748a0..90828d4447e 100644 --- a/drivers/usbdev/cdcacm.h +++ b/drivers/usbdev/cdcacm.h @@ -1,7 +1,7 @@ /**************************************************************************** * drivers/usbdev/cdcacm.h * - * Copyright (C) 2011-2012, 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2011-2012, 2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -104,16 +104,9 @@ * CDCACM_DATAALTIFID No alternate for the data interface */ -#define CDCACM_NINTERFACES (2) /* Number of interfaces in the configuration */ -#define CDCACM_NOTIFID (CONFIG_CDCACM_IFNOBASE+0) #define CDCACM_NOTALTIFID (0) -#define CDCACM_DATAIFID (CONFIG_CDCACM_IFNOBASE+1) #define CDCACM_DATAALTIFID (0) -/* Configuration descriptor values */ - -#define CDCACM_CONFIGID (1) /* The only supported configuration ID */ - /* Buffer big enough for any of our descriptors (the config descriptor is the * biggest). */ @@ -124,7 +117,6 @@ /* Device descriptor values */ #define CDCACM_VERSIONNO (0x0101) /* Device version number 1.1 (BCD) */ -#define CDCACM_NCONFIGS (1) /* Number of configurations supported */ /* String language */ @@ -165,62 +157,16 @@ #define CDCACM_LASTSTRID CDCACM_DATAIFSTRID #define CDCACM_NSTRIDS (CDCACM_LASTSTRID - CDCACM_STRBASE) -/* Configuration descriptor size */ - -#if !defined(CONFIG_CDCACM_COMPOSITE) - -/* Number of individual descriptors in the configuration descriptor: - * Configuration descriptor + (2) interface descriptors + (3) endpoint - * descriptors + (3) ACM descriptors. - */ - -# define CDCACM_CFGGROUP_SIZE (9) - -/* The size of the config descriptor: (9 + 2*9 + 3*7 + 4 + 5 + 5) = 62 */ - -# define SIZEOF_CDCACM_CFGDESC \ - (USB_SIZEOF_CFGDESC + 2*USB_SIZEOF_IFDESC + 3*USB_SIZEOF_EPDESC + \ - SIZEOF_ACM_FUNCDESC + SIZEOF_HDR_FUNCDESC + SIZEOF_UNION_FUNCDESC(1)) - -#elif defined(CONFIG_COMPOSITE_IAD) - -/* Number of individual descriptors in the configuration descriptor: - * (1) interface association descriptor + (2) interface descriptors + - * (3) endpoint descriptors + (3) ACM descriptors. - */ - -# define CDCACM_CFGGROUP_SIZE (9) - -/* The size of the config descriptor: (8 + 2*9 + 3*7 + 4 + 5 + 5) = 61 */ - -# define SIZEOF_CDCACM_CFGDESC \ - (USB_SIZEOF_IADDESC +2*USB_SIZEOF_IFDESC + 3*USB_SIZEOF_EPDESC + \ - SIZEOF_ACM_FUNCDESC + SIZEOF_HDR_FUNCDESC + SIZEOF_UNION_FUNCDESC(1)) - -#else - -/* Number of individual descriptors in the configuration descriptor: - * (2) interface descriptors + (3) endpoint descriptors + (3) ACM descriptors. - */ - -# define CDCACM_CFGGROUP_SIZE (8) - -/* The size of the config descriptor: (2*9 + 3*7 + 4 + 5 + 5) = 53 */ - -# define SIZEOF_CDCACM_CFGDESC \ - (2*USB_SIZEOF_IFDESC + 3*USB_SIZEOF_EPDESC + SIZEOF_ACM_FUNCDESC + \ - SIZEOF_HDR_FUNCDESC + SIZEOF_UNION_FUNCDESC(1)) -#endif /* Endpoint configuration ****************************************************/ -#define CDCACM_EPINTIN_ADDR (USB_DIR_IN | CONFIG_CDCACM_EPINTIN) +#define CDCACM_MKEPINTIN(desc) (USB_DIR_IN | (desc)->epno[CDCACM_EP_INTIN_IDX]) #define CDCACM_EPINTIN_ATTR (USB_EP_ATTR_XFER_INT) -#define CDCACM_EPOUTBULK_ADDR (CONFIG_CDCACM_EPBULKOUT) +#define CDCACM_MKEPBULKIN(desc) (USB_DIR_IN | (desc)->epno[CDCACM_EP_BULKIN_IDX]) #define CDCACM_EPOUTBULK_ATTR (USB_EP_ATTR_XFER_BULK) -#define CDCACM_EPINBULK_ADDR (USB_DIR_IN | CONFIG_CDCACM_EPBULKIN) +#define CDCACM_MKEPBULKOUT(desc) ((desc)->epno[CDCACM_EP_BULKOUT_IDX]) #define CDCACM_EPINBULK_ATTR (USB_EP_ATTR_XFER_BULK) /* Device driver definitions ************************************************/ @@ -287,7 +233,7 @@ enum cdcacm_epdesc_e int cdcacm_mkstrdesc(uint8_t id, struct usb_strdesc_s *strdesc); /**************************************************************************** - * Name: cdcacm_getepdesc + * Name: cdcacm_getdevdesc * * Description: * Return a pointer to the raw device descriptor @@ -299,28 +245,18 @@ FAR const struct usb_devdesc_s *cdcacm_getdevdesc(void); #endif /**************************************************************************** - * Name: cdcacm_getepdesc + * Name: cdcacm_copy_epdesc * * Description: - * Return a pointer to the raw endpoint descriptor (used for configuring - * endpoints) + * Copies the requested Endpoint Description into the buffer given. + * Returns the number of Bytes filled in (sizeof(struct usb_epdesc_s)). * ****************************************************************************/ -FAR const struct usb_epdesc_s *cdcacm_getepdesc(enum cdcacm_epdesc_e epid); - -/**************************************************************************** - * Name: cdcacm_mkepdesc - * - * Description: - * Construct the endpoint descriptor using the correct max packet size. - * - ****************************************************************************/ - -#ifdef CONFIG_USBDEV_DUALSPEED -void cdcacm_mkepdesc(enum cdcacm_epdesc_e epid, - uint16_t mxpacket, FAR struct usb_epdesc_s *outdesc); -#endif +int cdcacm_copy_epdesc(enum cdcacm_epdesc_e epid, + FAR struct usb_epdesc_s *epdesc, + FAR struct usbdev_description_s *devdesc, + bool hispeed); /**************************************************************************** * Name: cdcacm_mkcfgdesc @@ -331,9 +267,10 @@ void cdcacm_mkepdesc(enum cdcacm_epdesc_e epid, ****************************************************************************/ #ifdef CONFIG_USBDEV_DUALSPEED -int16_t cdcacm_mkcfgdesc(FAR uint8_t *buf, uint8_t speed, uint8_t type); +int16_t cdcacm_mkcfgdesc(FAR uint8_t *buf, struct usbdev_description_s *devdesc, + uint8_t speed, uint8_t type); #else -int16_t cdcacm_mkcfgdesc(FAR uint8_t *buf); +int16_t cdcacm_mkcfgdesc(FAR uint8_t *buf, struct usbdev_description_s *devdesc); #endif /**************************************************************************** diff --git a/drivers/usbdev/cdcacm_desc.c b/drivers/usbdev/cdcacm_desc.c index 221734a71e5..6c42dadaa9e 100644 --- a/drivers/usbdev/cdcacm_desc.c +++ b/drivers/usbdev/cdcacm_desc.c @@ -1,7 +1,7 @@ /**************************************************************************** * drivers/usbdev/cdcacm_desc.c * - * Copyright (C) 2011-2012, 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2011-2012, 2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -46,6 +46,7 @@ #include #include +#include #include #include #include @@ -56,21 +57,31 @@ * Pre-processor Definitions ****************************************************************************/ +/* This little hack makes the compiler producing an error if the (constant) + * condition is not true. + * + * e.g. + * COMPILE_TIME_ASSERTION(sizeof(uint8_t) == 1); + * + * when not true, the output is something like + * + * test.c:28:2: error: size of unnamed array is negative + * COMPILE_TIME_ASSERTION(sizeof(uint8_t) != 1); + * ^ + * + * else the compiler produces the (empty) statement + * + * ((void)sizeof(char[1])) + * + * which is optimized out. + */ + +#define COMPILE_TIME_ASSERTION(condition) ((void)sizeof(char[1 - 2*!(condition)])) + /**************************************************************************** * Private Types ****************************************************************************/ -/* Describes one description in the group of descriptors forming the - * total configuration descriptor. - */ - -struct cfgdecsc_group_s -{ - uint16_t descsize; /* Size of the descriptor in bytes */ - uint16_t hsepsize; /* High speed max packet size */ - FAR void *desc; /* A pointer to the descriptor */ -}; - /**************************************************************************** * Private Function Prototypes ****************************************************************************/ @@ -117,241 +128,6 @@ static const struct usb_devdesc_s g_devdesc = }; #endif -/* Configuration descriptor. If the USB serial device is configured as part of - * composite device, then the configuration descriptor will be provided by the - * composite device logic. - */ - -#ifndef CONFIG_CDCACM_COMPOSITE -static const struct usb_cfgdesc_s g_cfgdesc = -{ - USB_SIZEOF_CFGDESC, /* len */ - USB_DESC_TYPE_CONFIG, /* type */ - { - LSBYTE(SIZEOF_CDCACM_CFGDESC), /* LS totallen */ - MSBYTE(SIZEOF_CDCACM_CFGDESC) /* MS totallen */ - }, - CDCACM_NINTERFACES, /* ninterfaces */ - CDCACM_CONFIGID, /* cfgvalue */ - CDCACM_CONFIGSTRID, /* icfg */ - USB_CONFIG_ATTR_ONE | /* attr */ - CDCACM_SELFPOWERED | - CDCACM_REMOTEWAKEUP, - (CONFIG_USBDEV_MAXPOWER + 1) / 2 /* mxpower */ -}; -#endif - -/* Interface association descriptor */ - -#if defined(CONFIG_CDCACM_COMPOSITE) && defined(CONFIG_COMPOSITE_IAD) -static const struct usb_iaddesc_s g_iaddesc = -{ - USB_SIZEOF_IADDESC, /* len */ - USB_DESC_TYPE_INTERFACEASSOCIATION, /* type */ - CONFIG_CDCACM_IFNOBASE, /* firstif */ - CDCACM_NINTERFACES, /* nifs */ - USB_CLASS_CDC, /* class */ - CDC_SUBCLASS_ACM, /* subclass */ - CDC_PROTO_NONE, /* protocol */ - 0 /* ifunction */ -}; -#endif - -/* Notification interface */ - -static const struct usb_ifdesc_s g_notifdesc = -{ - USB_SIZEOF_IFDESC, /* len */ - USB_DESC_TYPE_INTERFACE, /* type */ - CDCACM_NOTIFID, /* ifno */ - CDCACM_NOTALTIFID, /* alt */ - 1, /* neps */ - USB_CLASS_CDC, /* class */ - CDC_SUBCLASS_ACM, /* subclass */ - CDC_PROTO_ATM, /* proto */ -#ifdef CONFIG_CDCACM_NOTIFSTR - CDCACM_NOTIFSTRID /* iif */ -#else - 0 /* iif */ -#endif -}; - -/* Header functional descriptor */ - -static const struct cdc_hdr_funcdesc_s g_funchdr = -{ - SIZEOF_HDR_FUNCDESC, /* size */ - USB_DESC_TYPE_CSINTERFACE, /* type */ - CDC_DSUBTYPE_HDR, /* subtype */ - { - LSBYTE(CDC_VERSIONNO), /* LS cdc */ - MSBYTE(CDC_VERSIONNO) /* MS cdc */ - } -}; - -/* ACM functional descriptor */ - -static const struct cdc_acm_funcdesc_s g_acmfunc = -{ - SIZEOF_ACM_FUNCDESC, /* size */ - USB_DESC_TYPE_CSINTERFACE, /* type */ - CDC_DSUBTYPE_ACM, /* subtype */ - 0x06 /* caps */ -}; - -/* Union functional descriptor */ - -static const struct cdc_union_funcdesc_s g_unionfunc = -{ - SIZEOF_UNION_FUNCDESC(1), /* size */ - USB_DESC_TYPE_CSINTERFACE, /* type */ - CDC_DSUBTYPE_UNION, /* subtype */ - 0, /* master */ - {1} /* slave[0] */ -}; - -/* Interrupt IN endpoint descriptor */ - -static const struct usb_epdesc_s g_epintindesc = -{ - USB_SIZEOF_EPDESC, /* len */ - USB_DESC_TYPE_ENDPOINT, /* type */ - CDCACM_EPINTIN_ADDR, /* addr */ - CDCACM_EPINTIN_ATTR, /* attr */ - { - LSBYTE(CONFIG_CDCACM_EPINTIN_FSSIZE), /* maxpacket (full speed) */ - MSBYTE(CONFIG_CDCACM_EPINTIN_FSSIZE) - }, - 10 /* interval */ -}; - -/* Data interface descriptor */ - -static const struct usb_ifdesc_s g_dataifdesc = -{ - USB_SIZEOF_IFDESC, /* len */ - USB_DESC_TYPE_INTERFACE, /* type */ - CDCACM_DATAIFID, /* ifno */ - CDCACM_DATAALTIFID, /* alt */ - 2, /* neps */ - USB_CLASS_CDC_DATA, /* class */ - CDC_DATA_SUBCLASS_NONE, /* subclass */ - CDC_DATA_PROTO_NONE, /* proto */ -#ifdef CONFIG_CDCACM_DATAIFSTR - CDCACM_DATAIFSTRID /* iif */ -#else - 0 /* iif */ -#endif -}; - -/* Bulk OUT endpoint descriptor */ - -static const struct usb_epdesc_s g_epbulkoutdesc = -{ - USB_SIZEOF_EPDESC, /* len */ - USB_DESC_TYPE_ENDPOINT, /* type */ - CDCACM_EPOUTBULK_ADDR, /* addr */ - CDCACM_EPOUTBULK_ATTR, /* attr */ - { - LSBYTE(CONFIG_CDCACM_EPBULKOUT_FSSIZE), /* maxpacket (full speed) */ - MSBYTE(CONFIG_CDCACM_EPBULKOUT_FSSIZE) - }, - 1 /* interval */ -}; - -/* Bulk IN endpoint descriptor */ - -static const struct usb_epdesc_s g_epbulkindesc = -{ - USB_SIZEOF_EPDESC, /* len */ - USB_DESC_TYPE_ENDPOINT, /* type */ - CDCACM_EPINBULK_ADDR, /* addr */ - CDCACM_EPINBULK_ATTR, /* attr */ - { - LSBYTE(CONFIG_CDCACM_EPBULKIN_FSSIZE), /* maxpacket (full speed) */ - MSBYTE(CONFIG_CDCACM_EPBULKIN_FSSIZE) - }, - 1 /* interval */ -}; - -/* The components of the configuration descriptor are maintained as - * a collection of separate descriptor structure coordinated by the - * following array. These descriptors could have been combined into - * one larger "super" configuration descriptor structure. However, I - * have concerns about compiler-dependent alignment and packing. Since - * the individual structures consist only of byte types, alignment and - * packing is not an issue. And since the are concatentated at run time - * instead of compile time, there should no issues there either. - */ - -static const struct cfgdecsc_group_s g_cfggroup[CDCACM_CFGGROUP_SIZE] = -{ - /* Configuration Descriptor. If the serial device is used in as part - * or a composite device, then the configuration descriptor is - * provided by the composite device logic. - */ - -#if !defined(CONFIG_CDCACM_COMPOSITE) - { - USB_SIZEOF_CFGDESC, /* 1. Configuration descriptor */ - 0, - (FAR void *)&g_cfgdesc - }, - - /* If the serial device is part of a composite device, then it should - * begin with an interface association descriptor (IAD) because the - * CDC/ACM device consists of more than one interface. The IAD associates - * the two CDC/ACM interfaces with the same CDC/ACM device. - */ - -#elif defined(CONFIG_COMPOSITE_IAD) - { - USB_SIZEOF_IADDESC, /* 1. Interface association descriptor */ - 0, - (FAR void *)&g_iaddesc - }, -#endif - { - USB_SIZEOF_IFDESC, /* 2. Notification interface */ - 0, - (FAR void *)&g_notifdesc - }, - { - SIZEOF_HDR_FUNCDESC, /* 3. Header functional descriptor */ - 0, - (FAR void *)&g_funchdr - }, - { - SIZEOF_ACM_FUNCDESC, /* 4. ACM functional descriptor */ - 0, - (FAR void *)&g_acmfunc - }, - { - SIZEOF_UNION_FUNCDESC(1), /* 5. Union functional descriptor */ - 0, - (FAR void *)&g_unionfunc - }, - { - USB_SIZEOF_EPDESC, /* 6. Interrupt IN endpoint descriptor */ - CONFIG_CDCACM_EPINTIN_HSSIZE, - (FAR void *)&g_epintindesc - }, - { - USB_SIZEOF_IFDESC, /* 7. Data interface descriptor */ - 0, - (FAR void *)&g_dataifdesc - }, - { - USB_SIZEOF_EPDESC, /* 8. Bulk OUT endpoint descriptor */ - CONFIG_CDCACM_EPBULKOUT_HSSIZE, - (FAR void *)&g_epbulkoutdesc - }, - { - USB_SIZEOF_EPDESC, /* 9. Bulk OUT endpoint descriptor */ - CONFIG_CDCACM_EPBULKIN_HSSIZE, - (FAR void *)&g_epbulkindesc - } -}; #if !defined(CONFIG_CDCACM_COMPOSITE) && defined(CONFIG_USBDEV_DUALSPEED) static const struct usb_qualdesc_s g_qualdesc = @@ -375,29 +151,6 @@ static const struct usb_qualdesc_s g_qualdesc = * Private Functions ****************************************************************************/ -/**************************************************************************** - * Name: cdcacm_cpepdesc - * - * Description: - * Copy an endpoint descriptor using the correct max packet size. - * - ****************************************************************************/ - -#ifdef CONFIG_USBDEV_DUALSPEED -void cdcacm_cpepdesc(FAR const struct usb_epdesc_s *indesc, uint16_t mxpacket, - FAR struct usb_epdesc_s *outdesc) -{ - /* Copy the "canned" descriptor */ - - memcpy(outdesc, indesc, USB_SIZEOF_EPDESC); - - /* Then add the correct max packet size */ - - outdesc->mxpacketsize[0] = LSBYTE(mxpacket); - outdesc->mxpacketsize[1] = MSBYTE(mxpacket); -} -#endif - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -507,51 +260,116 @@ FAR const struct usb_devdesc_s *cdcacm_getdevdesc(void) #endif /**************************************************************************** - * Name: cdcacm_getepdesc + * Name: cdcacm_copy_epdesc * * Description: - * Return a pointer to the raw endpoint struct (used for configuring - * endpoints) + * Copies the requested Endpoint Description into the buffer given. + * Returns the number of Bytes filled in (sizeof(struct usb_epdesc_s)). * ****************************************************************************/ -FAR const struct usb_epdesc_s *cdcacm_getepdesc(enum cdcacm_epdesc_e epid) +int cdcacm_copy_epdesc(enum cdcacm_epdesc_e epid, + FAR struct usb_epdesc_s *epdesc, + FAR struct usbdev_description_s *devdesc, + bool hispeed) { - switch (epid) +#ifndef CONFIG_USBDEV_DUALSPEED + /* unused */ + (void)hispeed; +#endif + + switch (epid) { - case CDCACM_EPINTIN: /* Interrupt IN endpoint */ - return &g_epintindesc; - - case CDCACM_EPBULKOUT: /* Bulk OUT endpoint */ - return &g_epbulkoutdesc; - - case CDCACM_EPBULKIN: /* Bulk IN endpoint */ - return &g_epbulkindesc; - - default: - return NULL; - } -} - -/**************************************************************************** - * Name: cdcacm_mkepdesc - * - * Description: - * Construct the endpoint descriptor using the correct max packet size. - * - ****************************************************************************/ + case CDCACM_EPINTIN: /* Interrupt IN endpoint */ + { + epdesc->len = USB_SIZEOF_EPDESC; /* Descriptor length */ + epdesc->type = USB_DESC_TYPE_ENDPOINT; /* Descriptor type */ + epdesc->addr = CDCACM_MKEPINTIN(devdesc); /* Endpoint address */ + epdesc->attr = CDCACM_EPINTIN_ATTR; /* Endpoint attributes */ #ifdef CONFIG_USBDEV_DUALSPEED -void cdcacm_mkepdesc(enum cdcacm_epdesc_e epid, uint16_t mxpacket, - FAR struct usb_epdesc_s *outdesc) -{ - /* Map the ID to the correct endpoint and let cdcacm_cpepdesc to the real - * work. - */ + if (hispeed) + { + /* Maximum packet size (high speed) */ - cdcacm_cpepdesc(cdcacm_getepdesc(epid), mxpacket, outdesc); -} + epdesc->mxpacketsize[0] = LSBYTE(CONFIG_CDCACM_EPINTIN_HSSIZE); + epdesc->mxpacketsize[1] = MSBYTE(CONFIG_CDCACM_EPINTIN_HSSIZE); + } + else #endif + { + /* Maximum packet size (full speed) */ + + epdesc->mxpacketsize[0] = LSBYTE(CONFIG_CDCACM_EPINTIN_FSSIZE); + epdesc->mxpacketsize[1] = MSBYTE(CONFIG_CDCACM_EPINTIN_FSSIZE); + } + + epdesc->interval = 10; /* Interval */ + } + break; + + case CDCACM_EPBULKOUT: /* Bulk OUT endpoint */ + { + epdesc->len = USB_SIZEOF_EPDESC; /* Descriptor length */ + epdesc->type = USB_DESC_TYPE_ENDPOINT; /* Descriptor type */ + epdesc->addr = CDCACM_MKEPBULKOUT(devdesc); /* Endpoint address */ + epdesc->attr = CDCACM_EPOUTBULK_ATTR; /* Endpoint attributes */ +#ifdef CONFIG_USBDEV_DUALSPEED + if (hispeed) + { + /* Maximum packet size (high speed) */ + + epdesc->mxpacketsize[0] = LSBYTE(CONFIG_CDCACM_EPBULKOUT_HSSIZE); + epdesc->mxpacketsize[1] = MSBYTE(CONFIG_CDCACM_EPBULKOUT_HSSIZE); + } + else +#endif + { + /* Maximum packet size (full speed) */ + + epdesc->mxpacketsize[0] = LSBYTE(CONFIG_CDCACM_EPBULKOUT_FSSIZE); + epdesc->mxpacketsize[1] = MSBYTE(CONFIG_CDCACM_EPBULKOUT_FSSIZE); + } + + epdesc->interval = 1; /* Interval */ + } + break; + + case CDCACM_EPBULKIN: /* Bulk IN endpoint */ + { + epdesc->len = USB_SIZEOF_EPDESC; /* Descriptor length */ + epdesc->type = USB_DESC_TYPE_ENDPOINT; /* Descriptor type */ + epdesc->addr = CDCACM_MKEPBULKIN(devdesc); /* Endpoint address */ + epdesc->attr = CDCACM_EPINBULK_ATTR; /* Endpoint attributes */ + +#ifdef CONFIG_USBDEV_DUALSPEED + if (hispeed) + { + /* Maximum packet size (high speed) */ + + epdesc->mxpacketsize[0] = LSBYTE(CONFIG_CDCACM_EPBULKIN_HSSIZE); + epdesc->mxpacketsize[1] = MSBYTE(CONFIG_CDCACM_EPBULKIN_HSSIZE); + } + else +#endif + { + /* Maximum packet size (full speed) */ + + epdesc->mxpacketsize[0] = LSBYTE(CONFIG_CDCACM_EPBULKIN_FSSIZE); + epdesc->mxpacketsize[1] = MSBYTE(CONFIG_CDCACM_EPBULKIN_FSSIZE); + } + + epdesc->interval = 1; /* Interval */ + } + break; + + default: + return 0; + } + + COMPILE_TIME_ASSERTION(sizeof(struct usb_epdesc_s) == USB_SIZEOF_EPDESC); + return sizeof(struct usb_epdesc_s); +} /**************************************************************************** * Name: cdcacm_mkcfgdesc @@ -562,17 +380,19 @@ void cdcacm_mkepdesc(enum cdcacm_epdesc_e epid, uint16_t mxpacket, ****************************************************************************/ #ifdef CONFIG_USBDEV_DUALSPEED -int16_t cdcacm_mkcfgdesc(FAR uint8_t *buf, uint8_t speed, uint8_t type) +int16_t cdcacm_mkcfgdesc(FAR uint8_t *buf, + FAR struct usbdev_description_s *devdesc, + uint8_t speed, uint8_t type) #else -int16_t cdcacm_mkcfgdesc(FAR uint8_t *buf) +int16_t cdcacm_mkcfgdesc(FAR uint8_t *buf, + FAR struct usbdev_description_s *devdesc) #endif { - FAR const struct cfgdecsc_group_s *group; - FAR uint8_t *dest = buf; - int i; + int length = 0; + bool hispeed = false; #ifdef CONFIG_USBDEV_DUALSPEED - bool hispeed = (speed == USB_SPEED_HIGH); + hispeed = (speed == USB_SPEED_HIGH); /* Check for switches between high and full speed */ @@ -582,44 +402,242 @@ int16_t cdcacm_mkcfgdesc(FAR uint8_t *buf) } #endif - /* Copy all of the descriptors in the group */ + /* fill in all descriptors directly to the buf */ - for (i = 0, dest = buf; i < CDCACM_CFGGROUP_SIZE; i++) + /* Configuration Descriptor. If the serial device is used in as part + * or a composite device, then the configuration descriptor is + * provided by the composite device logic. + */ + +#if !defined(CONFIG_CDCACM_COMPOSITE) + if (buf != NULL) { - group = &g_cfggroup[i]; - - /* The "canned" descriptors all have full speed endpoint maxpacket - * sizes. If high speed is selected, we will have to change the - * endpoint maxpacket size. - * - * Is there a alternative high speed maxpacket size in the table? - * If so, that is sufficient proof that the descriptor that we - * just copied is an endpoint descriptor and needs the fixup + /* Configuration descriptor. If the USB serial device is configured as part of + * composite device, then the configuration descriptor will be provided by the + * composite device logic. */ + FAR struct usb_cfgdesc_s *dest = (FAR struct usb_cfgdesc_s *)buf; + + /* Let's calculate the size... */ + #ifdef CONFIG_USBDEV_DUALSPEED - if (hispeed && group->hsepsize != 0) - { - cdcacm_cpepdesc((FAR const struct usb_epdesc_s *)group->desc, - group->hsepsize, - (FAR struct usb_epdesc_s *)dest); - } - else + int16_t size = cdcacm_mkcfgdesc(NULL, NULL, speed, type); +#else + int16_t size = cdcacm_mkcfgdesc(NULL, NULL); #endif - /* Copy the "canned" descriptor with the full speed max packet - * size - */ - { - memcpy(dest, group->desc, group->descsize); - } + dest->len = USB_SIZEOF_CFGDESC; /* Descriptor length */ + dest->type = USB_DESC_TYPE_CONFIG; /* Descriptor type */ + dest->totallen[0] = LSBYTE(size); /* LS Total length */ + dest->totallen[1] = MSBYTE(size); /* MS Total length */ + dest->ninterfaces = CDCACM_NINTERFACES; /* Number of interfaces */ + dest->cfgvalue = CDCACM_CONFIGID; /* Configuration value */ + dest->icfg = CDCACM_CONFIGSTRID; /* Configuration */ + dest->attr = USB_CONFIG_ATTR_ONE | /* Attributes */ + CDCACM_SELFPOWERED | + CDCACM_REMOTEWAKEUP; + dest->mxpower = (CONFIG_USBDEV_MAXPOWER + 1) / 2; /* Max power (mA/2) */ - /* Advance to the destination location for the next descriptor */ + COMPILE_TIME_ASSERTION(sizeof(struct usb_cfgdesc_s) == USB_SIZEOF_CFGDESC); - dest += group->descsize; + buf += sizeof(struct usb_cfgdesc_s); } - return SIZEOF_CDCACM_CFGDESC; + length += sizeof(struct usb_cfgdesc_s); + + /* If the serial device is part of a composite device, then it should + * begin with an interface association descriptor (IAD) because the + * CDC/ACM device consists of more than one interface. The IAD associates + * the two CDC/ACM interfaces with the same CDC/ACM device. + */ + +#elif defined(CONFIG_COMPOSITE_IAD) + /* Interface association descriptor */ + + if (buf != NULL) + { + FAR struct usb_iaddesc_s *dest = (FAR struct usb_iaddesc_s *)buf; + + dest->len = USB_SIZEOF_IADDESC; /* Descriptor length */ + dest->type = USB_DESC_TYPE_INTERFACEASSOCIATION; /* Descriptor type */ + dest->firstif = devdesc->ifnobase; /* Number of first interface of the function */ + dest->nifs = devdesc->ninterfaces; /* Number of interfaces associated with the function */ + dest->classid = USB_CLASS_CDC; /* Class code */ + dest->subclass = CDC_SUBCLASS_ACM; /* Sub-class code */ + dest->protocol = CDC_PROTO_NONE; /* Protocol code */ + dest->ifunction = 0; /* Index to string identifying the function */ + + COMPILE_TIME_ASSERTION(sizeof(struct usb_iaddesc_s) == USB_SIZEOF_IADDESC); + + buf += sizeof(struct usb_iaddesc_s); + } + length += sizeof(struct usb_iaddesc_s); +#endif + + /* Notification interface */ + + if (buf != NULL) + { + FAR struct usb_ifdesc_s *dest = (FAR struct usb_ifdesc_s *)buf; + + dest->len = USB_SIZEOF_IFDESC; /* Descriptor length */ + dest->type = USB_DESC_TYPE_INTERFACE; /* Descriptor type */ + dest->ifno = devdesc->ifnobase; /* Interface number */ + dest->alt = CDCACM_NOTALTIFID; /* Alternate setting */ + dest->neps = 1; /* Number of endpoints */ + dest->classid = USB_CLASS_CDC; /* Interface class */ + dest->subclass = CDC_SUBCLASS_ACM; /* Interface sub-class */ + dest->protocol = CDC_PROTO_ATM; /* Interface protocol */ +#ifdef CONFIG_CDCACM_NOTIFSTR + dest->iif = devdesc->strbase + CDCACM_NOTIFSTRID; /* iInterface */ +#else + dest->iif = 0; /* iInterface */ +#endif + + COMPILE_TIME_ASSERTION(sizeof(struct usb_ifdesc_s) == USB_SIZEOF_IFDESC); + + buf += sizeof(struct usb_ifdesc_s); + } + + length += sizeof(struct usb_ifdesc_s); + + /* Header functional descriptor */ + + if (buf != NULL) + { + FAR struct cdc_hdr_funcdesc_s *dest = (FAR struct cdc_hdr_funcdesc_s *)buf; + + dest->size = SIZEOF_HDR_FUNCDESC; /* Descriptor length */ + dest->type = USB_DESC_TYPE_CSINTERFACE; /* Descriptor type */ + dest->subtype = CDC_DSUBTYPE_HDR; /* Descriptor sub-type */ + dest->cdc[0] = LSBYTE(CDC_VERSIONNO); /* CDC release number in BCD */ + dest->cdc[1] = MSBYTE(CDC_VERSIONNO); + + COMPILE_TIME_ASSERTION(sizeof(struct cdc_hdr_funcdesc_s) == SIZEOF_HDR_FUNCDESC); + + buf += sizeof(struct cdc_hdr_funcdesc_s); + } + + length += sizeof(struct cdc_hdr_funcdesc_s); + + + /* ACM functional descriptor */ + + if (buf != NULL) + { + FAR struct cdc_acm_funcdesc_s *dest = (FAR struct cdc_acm_funcdesc_s *)buf; + + dest->size = SIZEOF_ACM_FUNCDESC; /* Descriptor length */ + dest->type = USB_DESC_TYPE_CSINTERFACE; /* Descriptor type */ + dest->subtype = CDC_DSUBTYPE_ACM; /* Descriptor sub-type */ + dest->caps = 0x06; /* Bit encoded capabilities */ + + COMPILE_TIME_ASSERTION(sizeof(struct cdc_acm_funcdesc_s) == SIZEOF_ACM_FUNCDESC); + + buf += sizeof(struct cdc_acm_funcdesc_s); + } + + length += sizeof(struct cdc_acm_funcdesc_s); + + /* This codeblock is just for future use - currently we didn't need it */ + +#ifdef OPTIONAL_UNION_FUNCTIONAL_DESCRIPTOR + /* Union functional descriptor */ + if (buf != NULL) + { + FAR struct cdc_union_funcdesc_s *dest = (FAR struct cdc_union_funcdesc_s *)buf; + + dest->size = SIZEOF_UNION_FUNCDESC(1); /* Descriptor length */ + dest->type = USB_DESC_TYPE_CSINTERFACE; /* Descriptor type */ + dest->subtype = CDC_DSUBTYPE_UNION; /* Descriptor sub-type */ + dest->master = devdesc->ifnobase; /* Master interface number */ + dest->slave[0] = devdesc->ifnobase + 1; /* Slave[0] interface number */ + + COMPILE_TIME_ASSERTION(sizeof(struct cdc_union_funcdesc_s) == SIZEOF_UNION_FUNCDESC(1)); + + buf += sizeof(struct cdc_union_funcdesc_s); + } + + length += sizeof(struct cdc_union_funcdesc_s); +#endif + + /* Call Management functional descriptor */ + + if (buf != NULL) + { + FAR struct cdc_callmgmt_funcdesc_s *dest = (FAR struct cdc_callmgmt_funcdesc_s *)buf; + + dest->size = SIZEOF_CALLMGMT_FUNCDESC; /* Descriptor length */ + dest->type = USB_DESC_TYPE_CSINTERFACE; /* Descriptor type */ + dest->subtype = CDC_DSUBTYPE_CALLMGMT; /* Descriptor sub-type */ + dest->caps = 3; /* Bit encoded capabilities */ + dest->ifno = devdesc->ifnobase + 1; /* Interface number of Data Class interface */ + + COMPILE_TIME_ASSERTION(sizeof(struct cdc_callmgmt_funcdesc_s) == SIZEOF_CALLMGMT_FUNCDESC); + + buf += sizeof(struct cdc_callmgmt_funcdesc_s); + } + + length += sizeof(struct cdc_callmgmt_funcdesc_s); + + /* Interrupt IN endpoint descriptor */ + + if (buf != NULL) + { + cdcacm_copy_epdesc(CDCACM_EPINTIN, (struct usb_epdesc_s *)buf, devdesc, hispeed); + + buf += USB_SIZEOF_EPDESC; + } + length += USB_SIZEOF_EPDESC; + + /* Data interface descriptor */ + + if (buf != NULL) + { + FAR struct usb_ifdesc_s *dest = (FAR struct usb_ifdesc_s *)buf; + + dest->len = USB_SIZEOF_IFDESC; /* Descriptor length */ + dest->type = USB_DESC_TYPE_INTERFACE; /* Descriptor type */ + dest->ifno = devdesc->ifnobase + 1; /* Interface number */ + dest->alt = CDCACM_DATAALTIFID; /* Alternate setting */ + dest->neps = 2; /* Number of endpoints */ + dest->classid = USB_CLASS_CDC_DATA; /* Interface class */ + dest->subclass = CDC_DATA_SUBCLASS_NONE; /* Interface sub-class */ + dest->protocol = CDC_DATA_PROTO_NONE; /* Interface protocol */ +#ifdef CONFIG_CDCACM_DATAIFSTR + dest->iif = devdesc->strbase + CDCACM_DATAIFSTRID; /* iInterface */ +#else + dest->iif = 0; /* iInterface */ +#endif + + COMPILE_TIME_ASSERTION(sizeof(struct usb_ifdesc_s) == USB_SIZEOF_IFDESC); + + buf += sizeof(struct usb_ifdesc_s); + } + + length += sizeof(struct usb_ifdesc_s); + + /* Bulk OUT endpoint descriptor */ + + if (buf != NULL) + { + cdcacm_copy_epdesc(CDCACM_EPBULKOUT, (struct usb_epdesc_s *)buf, devdesc, hispeed); + buf += USB_SIZEOF_EPDESC; + } + + length += USB_SIZEOF_EPDESC; + + /* Bulk IN endpoint descriptor */ + + if (buf != NULL) + { + cdcacm_copy_epdesc(CDCACM_EPBULKIN, (struct usb_epdesc_s *)buf, devdesc, hispeed); + buf += USB_SIZEOF_EPDESC; + } + + length += USB_SIZEOF_EPDESC; + return length; } /**************************************************************************** @@ -636,3 +654,5 @@ FAR const struct usb_qualdesc_s *cdcacm_getqualdesc(void) return &g_qualdesc; } #endif + + diff --git a/include/nuttx/usb/usbmsc.h b/include/nuttx/usb/usbmsc.h index 270fac0da3e..fdf1463c983 100644 --- a/include/nuttx/usb/usbmsc.h +++ b/include/nuttx/usb/usbmsc.h @@ -1,7 +1,7 @@ /************************************************************************************ * include/nuttx/usb/usbmsc.h * - * Copyright (C) 2008-2010, 2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2008-2010, 2012, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * NOTE: This interface was inspired by the Linux gadget interface by @@ -56,6 +56,17 @@ * Pre-processor Definitions ************************************************************************************/ +/* Informations about the device needed in usbdev_description_s */ + +#define USBMSC_CONFIGID (1) /* The only supported configuration ID */ +#define USBMSC_NENDPOINTS (2) /* Number of endpoints in the interface */ + +#define USBMSC_EP_BULKIN_IDX (0) +#define USBMSC_EP_BULKOUT_IDX (1) + +#define USBMSC_NCONFIGS (1) /* Number of configurations supported */ +#define USBMSC_NINTERFACES (1) /* Number of interfaces in the configuration */ + /************************************************************************************ * Public Types ************************************************************************************/ @@ -102,10 +113,11 @@ extern "C" #if defined(CONFIG_USBDEV_COMPOSITE) && defined(CONFIG_USBMSC_COMPOSITE) struct usbdevclass_driver_s; -int board_mscclassobject(FAR struct usbdevclass_driver_s **classdev); +int board_mscclassobject(int minor, FAR struct usbdev_description_s *usb_dev_desc, + FAR struct usbdevclass_driver_s **classdev); #endif -/**************************************************************************** + /************************************************************************************ * Name: board_mscuninitialize * * Description: @@ -120,7 +132,7 @@ int board_mscclassobject(FAR struct usbdevclass_driver_s **classdev); * Returned Value: * None * - ****************************************************************************/ + ************************************************************************************/ #if defined(CONFIG_USBDEV_COMPOSITE) && defined(CONFIG_USBMSC_COMPOSITE) struct usbdevclass_driver_s; @@ -149,7 +161,7 @@ void board_mscuninitialize(FAR struct usbdevclass_driver_s *classdev); * ************************************************************************************/ -int usbmsc_configure(unsigned int nluns, void **handle); +int usbmsc_configure(unsigned int nluns, FAR void **handle); /************************************************************************************ * Name: usbmsc_bindlun @@ -222,13 +234,13 @@ int usbmsc_exportluns(FAR void *handle); * * Returned Value: * 0 on success; a negated errno on failure - * ************************************************************************************/ #if defined(CONFIG_USBDEV_COMPOSITE) && defined(CONFIG_USBMSC_COMPOSITE) struct usbdevclass_driver_s; -int usbmsc_classobject(FAR void *handle, FAR struct usbdevclass_driver_s **classdev); +int usbmsc_classobject(FAR void *handle, FAR struct usbdev_description_s *usb_dev_desc, + FAR struct usbdevclass_driver_s **classdev); #endif /************************************************************************************ @@ -250,6 +262,26 @@ int usbmsc_classobject(FAR void *handle, FAR struct usbdevclass_driver_s **class void usbmsc_uninitialize(FAR void *handle); + /************************************************************************************ + * Name: usbmsc_get_composite_devdesc + * + * Description: + * Helper function to fill in some constants into the composite configuration + * structure. + * + * Input Parameters: + * dev - Pointer to the configuration struct we should fill + * + * Returned Value: + * None + * + ************************************************************************************/ + +#if defined(CONFIG_USBDEV_COMPOSITE) && defined(CONFIG_USBMSC_COMPOSITE) +struct composite_devdesc_s; +void usbmsc_get_composite_devdesc(FAR struct composite_devdesc_s *dev); +#endif + #undef EXTERN #if defined(__cplusplus) }