[[This is part 1 or several commits]]

We developed a huge Changeset over a year ago to make USB Composite configuration dynamical and be able to instanciate the CDCACM multiple times inside this device.  We use this feature to switch between one in normal and up to three CDCACMs in maintenance boot.

The control path starts in “boardctl.c” where the configuration for the device is constructed.  There are still a few issues which I’ll ask you to have a look at before this beast can be merged.

1. To be able to construct the data dynamically I have changed some USB-Structs to be packed. Maybe there are additional structs to change (just for completeness – not for current functionality).

2. I’ve added the Macro “COMPILE_TIME_ASSERTION” two times (in usbmsc_desc.c and in cdcacm_desc.c) to stay private. Maybe you’ll find a better place. It’s used to check the size of the structs against the assumptions.

3. I’ve changed the interface for some USB-Functions to receive also the dynamic configuration. Maybe this can be done more elegant.

4. The original NuttX (without the patch) seems to have problems with a Composite device holding a CDCACM and an MSC. The “USB SET CONFIGURATION” request does not to work at all. This makes the test fail under Windows and under Linux. Applying this patch doesn’t change anything – because it only changes the configuration – not the behavior. Maybe you’ll have a look at this problem before applying the patch.
This commit is contained in:
Frank Benkert 2017-06-01 14:08:22 -06:00 committed by Gregory Nutt
parent dc3a7e54a9
commit dcc9b07715
6 changed files with 655 additions and 514 deletions

View File

@ -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 <gnutt@nuttx.org>
*
* 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;

View File

@ -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"

View File

@ -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 <gnutt@nuttx.org>
*
* 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 <nuttx/usb/composite.h>
# 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

View File

@ -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 <gnutt@nuttx.org>
*
* 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
/****************************************************************************

View File

@ -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 <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -46,6 +46,7 @@
#include <debug.h>
#include <nuttx/usb/usb.h>
#include <nuttx/usb/usbdev.h>
#include <nuttx/usb/cdc.h>
#include <nuttx/usb/cdcacm.h>
#include <nuttx/usb/usbdev_trace.h>
@ -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

View File

@ -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 <gnutt@nuttx.org>
*
* 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)
}