diff --git a/configs/boardctl.c b/configs/boardctl.c index 208394e49f3..0334eee794c 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 @@ -182,7 +182,10 @@ static inline int boardctl_usbdevctrl(FAR struct boardioc_usbdev_ctrl_s *ctrl) case BOARDIOC_USBDEV_CONNECT: /* Connect the Composite device */ { DEBUGASSERT(ctrl->handle != NULL); - *ctrl->handle = composite_initialize(); + + *ctrl->handle = + board_composite_connect(ctrl->instance, ctrl->config); + if (*ctrl->handle == NULL) { ret = -EIO; @@ -190,7 +193,8 @@ static inline int boardctl_usbdevctrl(FAR struct boardioc_usbdev_ctrl_s *ctrl) } break; - case BOARDIOC_USBDEV_DISCONNECT: /* Disconnect the Composite device */ + case BOARDIOC_USBDEV_DISCONNECT: /* Disconnect the Composite + * device */ { DEBUGASSERT(ctrl->handle != NULL && *ctrl->handle != NULL); composite_uninitialize(*ctrl->handle); diff --git a/configs/fire-stm32v2/src/Makefile b/configs/fire-stm32v2/src/Makefile index ea45dc76231..b848ce4993e 100644 --- a/configs/fire-stm32v2/src/Makefile +++ b/configs/fire-stm32v2/src/Makefile @@ -68,8 +68,4 @@ ifeq ($(CONFIG_USBMSC),y) CSRCS += stm32_usbmsc.c endif -ifeq ($(CONFIG_USBDEV_COMPOSITE),y) -CSRCS += stm32_composite.c -endif - include $(TOPDIR)/configs/Board.mk diff --git a/configs/fire-stm32v2/src/stm32_composite.c b/configs/fire-stm32v2/src/stm32_composite.c deleted file mode 100644 index 4a171aebe44..00000000000 --- a/configs/fire-stm32v2/src/stm32_composite.c +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************************** - * configs/fire-stm32v2/src/stm32_composite.c - * - * Copyright (C) 2012, 2016 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Configure and register the STM32 SPI-based MMC/SD block driver. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include - -#include - -#include "fire-stm32v2.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ -/* Configuration ************************************************************/ -/* Device minor number */ - -#ifndef CONFIG_SYSTEM_COMPOSITE_DEVMINOR1 -# define CONFIG_SYSTEM_COMPOSITE_DEVMINOR1 0 -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: board_composite_initialize - * - * Description: - * Perform architecture specific initialization of a composite USB device. - * - ****************************************************************************/ - -int board_composite_initialize(int port) -{ - /* If system/composite is built as an NSH command, then SD slot should - * already have been initialized in board_app_initialize() (see stm32_appinit.c). - * In this case, there is nothing further to be done here. - * - * NOTE: CONFIG_NSH_BUILTIN_APPS is not a fool-proof indication that NSH - * was built. - */ - -#ifndef CONFIG_NSH_BUILTIN_APPS - return sd_mount(CONFIG_SYSTEM_COMPOSITE_DEVMINOR1); -#else - return OK; -#endif /* CONFIG_NSH_BUILTIN_APPS */ -} diff --git a/configs/mcu123-lpc214x/composite/defconfig b/configs/mcu123-lpc214x/composite/defconfig index 0775e5506cc..73dc78cdf40 100644 --- a/configs/mcu123-lpc214x/composite/defconfig +++ b/configs/mcu123-lpc214x/composite/defconfig @@ -51,11 +51,8 @@ CONFIG_USBDEV=y CONFIG_USBMSC_BULKINREQLEN=256 CONFIG_USBMSC_BULKOUTREQLEN=256 CONFIG_USBMSC_COMPOSITE=y -CONFIG_USBMSC_EPBULKIN=5 -CONFIG_USBMSC_EPBULKOUT=4 CONFIG_USBMSC_NRDREQS=2 CONFIG_USBMSC_NWRREQS=2 -CONFIG_USBMSC_PRODUCTSTR="USBdev Storage" CONFIG_USBMSC_REMOVABLE=y CONFIG_USBMSC_VERSIONNO=0x0399 CONFIG_USBMSC=y diff --git a/configs/mcu123-lpc214x/src/lpc2148_composite.c b/configs/mcu123-lpc214x/src/lpc2148_composite.c index 995fc4234f4..7dab84d2d4f 100644 --- a/configs/mcu123-lpc214x/src/lpc2148_composite.c +++ b/configs/mcu123-lpc214x/src/lpc2148_composite.c @@ -48,25 +48,290 @@ #include #include #include +#include +#include +#include #include #include "lpc214x_spi.h" +#if defined(CONFIG_BOARDCTL_USBDEVCTRL) && defined(CONFIG_USBDEV_COMPOSITE) + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -/* Configuration ************************************************************/ - -#ifndef CONFIG_SYSTEM_COMPOSITE_DEVMINOR1 -# define CONFIG_SYSTEM_COMPOSITE_DEVMINOR1 0 -#endif - /* PORT and SLOT number depend on the board configuration */ #define LPC214X_MMCSDSPIPORTNO 1 #define LPC214X_MMCSDSLOTNO 0 +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static FAR void *g_mschandle; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_mscclassobject + * + * Description: + * If the mass storage class driver is part of composite device, then + * its instantiation and configuration is a multi-step, board-specific, + * process (See comments for usbmsc_configure below). In this case, + * board-specific logic must provide board_mscclassobject(). + * + * board_mscclassobject() is called from the composite driver. It must + * encapsulate the instantiation and configuration of the mass storage + * class and the return the mass storage device's class driver instance + * to the composite driver. + * + * Input Parameters: + * classdev - The location to return the mass storage class' device + * instance. + * + * Returned Value: + * 0 on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static int board_mscclassobject(int minor, + FAR struct usbdev_description_s *devdesc, + FAR struct usbdevclass_driver_s **classdev) +{ + int ret; + + DEBUGASSERT(g_mschandle == NULL); + + /* Configure the mass storage device */ + + uinfo("Configuring with NLUNS=1\n"); + ret = usbmsc_configure(1, &g_mschandle); + if (ret < 0) + { + uerr("ERROR: usbmsc_configure failed: %d\n", -ret); + return ret; + } + + uinfo("MSC handle=%p\n", g_mschandle); + + /* Bind the LUN(s) */ + + uinfo("Bind LUN=0 to /dev/mmcsd0\n"); + ret = usbmsc_bindlun(g_mschandle, "/dev/mmcsd0", 0, 0, 0, false); + if (ret < 0) + { + uerr("ERROR: usbmsc_bindlun failed for LUN 1 at /dev/mmcsd0: %d\n", + ret); + usbmsc_uninitialize(g_mschandle); + g_mschandle = NULL; + return ret; + } + + /* Get the mass storage device's class object */ + + ret = usbmsc_classobject(g_mschandle, devdesc, classdev); + if (ret < 0) + { + uerr("ERROR: usbmsc_classobject failed: %d\n", -ret); + usbmsc_uninitialize(g_mschandle); + g_mschandle = NULL; + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: board_mscuninitialize + * + * Description: + * Un-initialize the USB storage class driver. This is just an application- + * specific wrapper aboutn usbmsc_unitialize() that is called form the + * composite device logic. + * + * Input Parameters: + * classdev - The class driver instrance previously give to the composite + * driver by board_mscclassobject(). + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static void board_mscuninitialize(FAR struct usbdevclass_driver_s *classdev) +{ + DEBUGASSERT(g_mschandle != NULL); + usbmsc_uninitialize(g_mschandle); + g_mschandle = NULL; +} +#endif + +/**************************************************************************** + * Name: board_composite0_connect + * + * Description: + * Connect the USB composite device on the specified USB device port for + * configuration 0. + * + * Input Parameters: + * port - The USB device port. + * + * Returned Value: + * A non-NULL handle value is returned on success. NULL is returned on + * any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static FAR void *board_composite0_connect(int port) +{ + /* 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; + + /* 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].classobject = cdcacm_classobject; + dev[0].uninitialize = cdcacm_uninitialize; + + /* Interfaces */ + + dev[0].devdesc.ifnobase = ifnobase; /* Offset to Interface-IDs */ + dev[0].minor = 0; /* The minor interface number */ + + /* Strings */ + + dev[0].devdesc.strbase = strbase; /* Offset to String Numbers */ + + /* Endpoints */ + + dev[0].devdesc.epno[CDCACM_EP_INTIN_IDX] = 1; + dev[0].devdesc.epno[CDCACM_EP_BULKIN_IDX] = 2; + dev[0].devdesc.epno[CDCACM_EP_BULKOUT_IDX] = 3; + + /* Count up the base numbers */ + + ifnobase += dev[0].devdesc.ninterfaces; + strbase += dev[0].devdesc.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].classobject = board_mscclassobject; + dev[1].uninitialize = board_mscuninitialize; + + /* Interfaces */ + + dev[1].devdesc.ifnobase = ifnobase; /* Offset to Interface-IDs */ + dev[1].minor = 0; /* The minor interface number */ + + /* Strings */ + + dev[1].devdesc.strbase = strbase; /* Offset to String Numbers */ + + /* Endpoints */ + + dev[1].devdesc.epno[USBMSC_EP_BULKIN_IDX] = 5; + dev[1].devdesc.epno[USBMSC_EP_BULKOUT_IDX] = 4; + + /* Count up the base numbers */ + + ifnobase += dev[1].devdesc.ninterfaces; + strbase += dev[1].devdesc.nstrings; + + return composite_initialize(2, dev); +} +#endif + +/**************************************************************************** + * Name: board_composite1_connect + * + * Description: + * Connect the USB composite device on the specified USB device port for + * configuration 1. + * + * Input Parameters: + * port - The USB device port. + * + * Returned Value: + * A non-NULL handle value is returned on success. NULL is returned on + * any failure. + * + ****************************************************************************/ + +static FAR void *board_composite1_connect(int port) +{ + struct composite_devdesc_s dev[2]; + int strbase = COMPOSITE_NSTRIDS; + int ifnobase = 0; + int epno; + int i; + + for (i = 0, epno = 1; i < 2; i++) + { + /* Ask the cdcacm driver to fill in the constants we didn't know here */ + + cdcacm_get_composite_devdesc(&dev[i]); + + /* Overwrite and correct some values... */ + /* The callback functions for the CDC/ACM class */ + + dev[i].classobject = cdcacm_classobject; + dev[i].uninitialize = cdcacm_uninitialize; + + dev[i].minor = i; /* The minor interface number */ + + /* Interfaces */ + + dev[i].devdesc.ifnobase = ifnobase; /* Offset to Interface-IDs */ + + /* Strings */ + + dev[i].devdesc.strbase = strbase; /* Offset to String Numbers */ + + /* Endpoints */ + + dev[i].devdesc.epno[CDCACM_EP_INTIN_IDX] = epno++; + dev[i].devdesc.epno[CDCACM_EP_BULKIN_IDX] = epno++; + dev[i].devdesc.epno[CDCACM_EP_BULKOUT_IDX] = epno++; + + ifnobase += dev[i].devdesc.ninterfaces; + strbase += dev[i].devdesc.nstrings; + } + + return composite_initialize(2, dev); +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -113,8 +378,7 @@ int board_composite_initialize(int port) syslog(LOG_INFO, "Binding SPI port %d to MMC/SD slot %d\n", LPC214X_MMCSDSPIPORTNO, LPC214X_MMCSDSLOTNO); - ret = mmcsd_spislotinitialize(CONFIG_SYSTEM_COMPOSITE_DEVMINOR1, - LPC214X_MMCSDSLOTNO, spi); + ret = mmcsd_spislotinitialize(0, LPC214X_MMCSDSLOTNO, spi); if (ret < 0) { syslog(LOG_ERR, @@ -130,3 +394,43 @@ int board_composite_initialize(int port) return OK; } + +/**************************************************************************** + * Name: board_composite_connect + * + * Description: + * Connect the USB composite device on the specified USB device port using + * the specified configuration. The interpretation of the configid is + * board specific. + * + * Input Parameters: + * port - The USB device port. + * configid - The USB composite configuration + * + * Returned Value: + * A non-NULL handle value is returned on success. NULL is returned on + * any failure. + * + ****************************************************************************/ + +FAR void *board_composite_connect(int port, int configid) +{ + if (configid == 0) + { +#ifdef CONFIG_USBMSC_COMPOSITE + return board_composite0_connect(port); +#else + return NULL; +#endif + } + else if (configid == 1) + { + return board_composite1_connect(port); + } + else + { + return NULL; + } +} + +#endif /* CONFIG_BOARDCTL_USBDEVCTRL && CONFIG_USBDEV_COMPOSITE */ diff --git a/configs/olimexino-stm32/composite/defconfig b/configs/olimexino-stm32/composite/defconfig index 529767834b0..f8fe9eca0ec 100644 --- a/configs/olimexino-stm32/composite/defconfig +++ b/configs/olimexino-stm32/composite/defconfig @@ -134,8 +134,6 @@ CONFIG_USART2_RXBUFSIZE=32 CONFIG_USART2_TXBUFSIZE=32 CONFIG_USBDEV_COMPOSITE=y CONFIG_USBMSC_COMPOSITE=y -CONFIG_USBMSC_EPBULKIN=5 -CONFIG_USBMSC_EPBULKOUT=4 CONFIG_USBMSC_NRDREQS=2 CONFIG_USBMSC_NWRREQS=2 CONFIG_USBMSC_REMOVABLE=y diff --git a/configs/olimexino-stm32/src/stm32_appinit.c b/configs/olimexino-stm32/src/stm32_appinit.c index dcd7d24a301..b2a3d230011 100644 --- a/configs/olimexino-stm32/src/stm32_appinit.c +++ b/configs/olimexino-stm32/src/stm32_appinit.c @@ -99,11 +99,9 @@ int board_app_initialize(uintptr_t arg) #endif #endif -#ifdef CONFIG_USBDEV_COMPOSITE -#if !defined(CONFIG_NSH_BUILTIN_APPS) && !defined(CONFIG_SYSTEM_COMPOSITE) +#if !defined(CONFIG_NSH_BUILTIN_APPS) && defined(CONFIG_USBDEV_COMPOSITE) ret = board_composite_initialize(0); #endif -#endif #ifdef CONFIG_CAN /* Initialize CAN and register the CAN driver. */ diff --git a/configs/olimexino-stm32/src/stm32_composite.c b/configs/olimexino-stm32/src/stm32_composite.c index 339b8c879be..894a093a254 100644 --- a/configs/olimexino-stm32/src/stm32_composite.c +++ b/configs/olimexino-stm32/src/stm32_composite.c @@ -47,22 +47,26 @@ #include #include #include +#include +#include +#include +#include #include "stm32.h" #include "olimexino-stm32.h" /* There is nothing to do here if SPI support is not selected. */ -#ifdef CONFIG_STM32_SPI +#if defined(CONFIG_BOARDCTL_USBDEVCTRL) && defined(CONFIG_USBDEV_COMPOSITE) /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -/* Configuration ************************************************************/ +/* No SPI? Then no USB MSC device in composite */ -#ifndef CONFIG_SYSTEM_COMPOSITE_DEVMINOR1 -# define CONFIG_SYSTEM_COMPOSITE_DEVMINOR1 0 +#ifndef CONFIG_STM32_SPI +# undef CONFIG_USBMSC_COMPOSITE #endif /* SLOT number(s) could depend on the board configuration */ @@ -77,6 +81,282 @@ # error "Unrecognized STM32 board" #endif +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static FAR void *g_mschandle; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_mscclassobject + * + * Description: + * If the mass storage class driver is part of composite device, then + * its instantiation and configuration is a multi-step, board-specific, + * process (See comments for usbmsc_configure below). In this case, + * board-specific logic must provide board_mscclassobject(). + * + * board_mscclassobject() is called from the composite driver. It must + * encapsulate the instantiation and configuration of the mass storage + * class and the return the mass storage device's class driver instance + * to the composite driver. + * + * Input Parameters: + * classdev - The location to return the mass storage class' device + * instance. + * + * Returned Value: + * 0 on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static int board_mscclassobject(int minor, + FAR struct usbdev_description_s *devdesc, + FAR struct usbdevclass_driver_s **classdev) +{ + int ret; + + DEBUGASSERT(g_mschandle == NULL); + + /* Configure the mass storage device */ + + uinfo("Configuring with NLUNS=1\n"); + ret = usbmsc_configure(1, &g_mschandle); + if (ret < 0) + { + uerr("ERROR: usbmsc_configure failed: %d\n", -ret); + return ret; + } + + uinfo("MSC handle=%p\n", g_mschandle); + + /* Bind the LUN(s) */ + + uinfo("Bind LUN=0 to /dev/mmcsd0\n"); + ret = usbmsc_bindlun(g_mschandle, "/dev/mmcsd0", 0, 0, 0, false); + if (ret < 0) + { + uerr("ERROR: usbmsc_bindlun failed for LUN 1 at /dev/mmcsd0: %d\n", + ret); + usbmsc_uninitialize(g_mschandle); + g_mschandle = NULL; + return ret; + } + + /* Get the mass storage device's class object */ + + ret = usbmsc_classobject(g_mschandle, devdesc, classdev); + if (ret < 0) + { + uerr("ERROR: usbmsc_classobject failed: %d\n", -ret); + usbmsc_uninitialize(g_mschandle); + g_mschandle = NULL; + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: board_mscuninitialize + * + * Description: + * Un-initialize the USB storage class driver. This is just an application- + * specific wrapper aboutn usbmsc_unitialize() that is called form the + * composite device logic. + * + * Input Parameters: + * classdev - The class driver instrance previously give to the composite + * driver by board_mscclassobject(). + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static void board_mscuninitialize(FAR struct usbdevclass_driver_s *classdev) +{ + DEBUGASSERT(g_mschandle != NULL); + usbmsc_uninitialize(g_mschandle); + g_mschandle = NULL; +} +#endif + +/**************************************************************************** + * Name: board_composite0_connect + * + * Description: + * Connect the USB composite device on the specified USB device port for + * configuration 0. + * + * Input Parameters: + * port - The USB device port. + * + * Returned Value: + * A non-NULL handle value is returned on success. NULL is returned on + * any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static FAR void *board_composite0_connect(int port) +{ + /* 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; + + /* 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].classobject = cdcacm_classobject; + dev[0].uninitialize = cdcacm_uninitialize; + + /* Interfaces */ + + dev[0].devdesc.ifnobase = ifnobase; /* Offset to Interface-IDs */ + dev[0].minor = 0; /* The minor interface number */ + + /* Strings */ + + dev[0].devdesc.strbase = strbase; /* Offset to String Numbers */ + + /* Endpoints */ + + dev[0].devdesc.epno[CDCACM_EP_INTIN_IDX] = 1; + dev[0].devdesc.epno[CDCACM_EP_BULKIN_IDX] = 2; + dev[0].devdesc.epno[CDCACM_EP_BULKOUT_IDX] = 3; + + /* Count up the base numbers */ + + ifnobase += dev[0].devdesc.ninterfaces; + strbase += dev[0].devdesc.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].classobject = board_mscclassobject; + dev[1].uninitialize = board_mscuninitialize; + + /* Interfaces */ + + dev[1].devdesc.ifnobase = ifnobase; /* Offset to Interface-IDs */ + dev[1].minor = 0; /* The minor interface number */ + + /* Strings */ + + dev[1].devdesc.strbase = strbase; /* Offset to String Numbers */ + + /* Endpoints */ + + dev[1].devdesc.epno[USBMSC_EP_BULKIN_IDX] = 5; + dev[1].devdesc.epno[USBMSC_EP_BULKOUT_IDX] = 4; + + /* Count up the base numbers */ + + ifnobase += dev[1].devdesc.ninterfaces; + strbase += dev[1].devdesc.nstrings; + + return composite_initialize(2, dev); +} +#endif + +/**************************************************************************** + * Name: board_composite1_connect + * + * Description: + * Connect the USB composite device on the specified USB device port for + * configuration 1. + * + * Input Parameters: + * port - The USB device port. + * + * Returned Value: + * A non-NULL handle value is returned on success. NULL is returned on + * any failure. + * + ****************************************************************************/ + +static FAR void *board_composite1_connect(int port) +{ + /* REVISIT: This configuration currently fails. stm32_epallocpma() fails + * allocate a buffer for the 6th endpoint. Currenlty it supports 7x64 byte + * buffers, two required for EP0, leaving only buffers for 5 additional + * endpoints. + */ + +#if 0 + struct composite_devdesc_s dev[2]; + int strbase = COMPOSITE_NSTRIDS; + int ifnobase = 0; + int epno; + int i; + + for (i = 0, epno = 1; i < 2; i++) + { + /* Ask the cdcacm driver to fill in the constants we didn't know here */ + + cdcacm_get_composite_devdesc(&dev[i]); + + /* Overwrite and correct some values... */ + /* The callback functions for the CDC/ACM class */ + + dev[i].classobject = cdcacm_classobject; + dev[i].uninitialize = cdcacm_uninitialize; + + dev[i].minor = i; /* The minor interface number */ + + /* Interfaces */ + + dev[i].devdesc.ifnobase = ifnobase; /* Offset to Interface-IDs */ + + /* Strings */ + + dev[i].devdesc.strbase = strbase; /* Offset to String Numbers */ + + /* Endpoints */ + + dev[i].devdesc.epno[CDCACM_EP_INTIN_IDX] = epno++; + dev[i].devdesc.epno[CDCACM_EP_BULKIN_IDX] = epno++; + dev[i].devdesc.epno[CDCACM_EP_BULKOUT_IDX] = epno++; + + ifnobase += dev[i].devdesc.ninterfaces; + strbase += dev[i].devdesc.nstrings; + } + + return composite_initialize(2, dev); +#else + return NULL; +#endif +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -117,17 +397,16 @@ int board_composite_initialize(int port) /* Now bind the SPI interface to the MMC/SD driver */ - syslog(LOG_INFO, "Bind SPI to the MMC/SD driver, minor=%d slot=%d\n", - CONFIG_SYSTEM_COMPOSITE_DEVMINOR1, OLIMEXINO_STM32_MMCSDSLOTNO); + syslog(LOG_INFO, "Bind SPI to the MMC/SD driver, minor=0 slot=%d\n", + OLIMEXINO_STM32_MMCSDSLOTNO); - ret = mmcsd_spislotinitialize(CONFIG_SYSTEM_COMPOSITE_DEVMINOR1, - OLIMEXINO_STM32_MMCSDSLOTNO, spi); + ret = mmcsd_spislotinitialize(0, OLIMEXINO_STM32_MMCSDSLOTNO, spi); if (ret != OK) { syslog(LOG_ERR, - "ERROR: Failed to bind SPI port %d to MMC/SD minor=%d slot=%d %d\n", - OLIMEXINO_STM32_MMCSDSPIPORTNO, CONFIG_SYSTEM_COMPOSITE_DEVMINOR1, - OLIMEXINO_STM32_MMCSDSLOTNO, ret); + "ERROR: Failed to bind SPI port %d to MMC/SD minor=0 slot=%d %d\n", + OLIMEXINO_STM32_MMCSDSPIPORTNO, OLIMEXINO_STM32_MMCSDSLOTNO, + ret); return ret; } @@ -135,4 +414,43 @@ int board_composite_initialize(int port) return OK; } -#endif /* CONFIG_STM32_SPI */ + +/**************************************************************************** + * Name: board_composite_connect + * + * Description: + * Connect the USB composite device on the specified USB device port using + * the specified configuration. The interpretation of the configid is + * board specific. + * + * Input Parameters: + * port - The USB device port. + * configid - The USB composite configuration + * + * Returned Value: + * A non-NULL handle value is returned on success. NULL is returned on + * any failure. + * + ****************************************************************************/ + +FAR void *board_composite_connect(int port, int configid) +{ + if (configid == 0) + { +#ifdef CONFIG_USBMSC_COMPOSITE + return board_composite0_connect(port); +#else + return NULL; +#endif + } + else if (configid == 1) + { + return board_composite1_connect(port); + } + else + { + return NULL; + } +} + +#endif /* CONFIG_BOARDCTL_USBDEVCTRL && CONFIG_USBDEV_COMPOSITE */ diff --git a/configs/samv71-xult/src/sam_composite.c b/configs/samv71-xult/src/sam_composite.c index 81fdfbcc900..05b813f4e4b 100644 --- a/configs/samv71-xult/src/sam_composite.c +++ b/configs/samv71-xult/src/sam_composite.c @@ -1,7 +1,7 @@ /**************************************************************************** * configs/samv71-xult/src/sam_composite.c * - * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2016, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -40,11 +40,123 @@ #include #include +#include +#include +#include #include #include "samv71-xult.h" -#ifdef CONFIG_USBDEV_COMPOSITE +#if defined(CONFIG_BOARDCTL_USBDEVCTRL) && defined(CONFIG_USBDEV_COMPOSITE) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static FAR void *g_mschandle; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_mscclassobject + * + * Description: + * If the mass storage class driver is part of composite device, then + * its instantiation and configuration is a multi-step, board-specific, + * process (See comments for usbmsc_configure below). In this case, + * board-specific logic must provide board_mscclassobject(). + * + * board_mscclassobject() is called from the composite driver. It must + * encapsulate the instantiation and configuration of the mass storage + * class and the return the mass storage device's class driver instance + * to the composite driver. + * + * Input Parameters: + * classdev - The location to return the mass storage class' device + * instance. + * + * Returned Value: + * 0 on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static int board_mscclassobject(int minor, + FAR struct usbdev_description_s *devdesc, + FAR struct usbdevclass_driver_s **classdev) +{ + int ret; + + DEBUGASSERT(g_mschandle == NULL); + + /* Configure the mass storage device */ + + uinfo("Configuring with NLUNS=1\n"); + ret = usbmsc_configure(1, &g_mschandle); + if (ret < 0) + { + uerr("ERROR: usbmsc_configure failed: %d\n", -ret); + return ret; + } + + uinfo("MSC handle=%p\n", g_mschandle); + + /* Bind the LUN(s) */ + + uinfo("Bind LUN=0 to /dev/mmcsd0\n"); + ret = usbmsc_bindlun(g_mschandle, "/dev/mmcsd0", 0, 0, 0, false); + if (ret < 0) + { + uerr("ERROR: usbmsc_bindlun failed for LUN 1 at /dev/mmcsd0: %d\n", + ret); + usbmsc_uninitialize(g_mschandle); + g_mschandle = NULL; + return ret; + } + + /* Get the mass storage device's class object */ + + ret = usbmsc_classobject(g_mschandle, devdesc, classdev); + if (ret < 0) + { + uerr("ERROR: usbmsc_classobject failed: %d\n", -ret); + usbmsc_uninitialize(g_mschandle); + g_mschandle = NULL; + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: board_mscuninitialize + * + * Description: + * Un-initialize the USB storage class driver. This is just an application- + * specific wrapper aboutn usbmsc_unitialize() that is called form the + * composite device logic. + * + * Input Parameters: + * classdev - The class driver instrance previously give to the composite + * driver by board_mscclassobject(). + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static void board_mscuninitialize(FAR struct usbdevclass_driver_s *classdev) +{ + DEBUGASSERT(g_mschandle != NULL); + usbmsc_uninitialize(g_mschandle); + g_mschandle = NULL; +} +#endif /**************************************************************************** * Public Functions @@ -63,4 +175,176 @@ int board_composite_initialize(int port) return OK; } -#endif /* CONFIG_USBDEV_COMPOSITE */ +/**************************************************************************** + * Name: board_composite_connect + * + * Description: + * Connect the USB composite device on the specified USB device port using + * the specified configuration. The interpretation of the configid is + * board specific. + * + * Input Parameters: + * port - The USB device port. + * configid - The USB composite configuration + * + * Returned Value: + * A non-NULL handle value is returned on success. NULL is returned on + * any failure. + * + ****************************************************************************/ + +FAR void *board_composite_connect(int port, int configid) +{ + /* 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. + */ + + if (configid == 0) + { +#ifdef CONFIG_USBMSC_COMPOSITE + struct composite_devdesc_s dev[2]; + int ifnobase = 0; + int strbase = COMPOSITE_NSTRIDS; + + /* 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].classobject = cdcacm_classobject; + dev[0].uninitialize = cdcacm_uninitialize; + + /* Interfaces */ + + dev[0].devdesc.ifnobase = ifnobase; /* Offset to Interface-IDs */ + dev[0].minor = 0; /* The minor interface number */ + + /* Strings */ + + dev[0].devdesc.strbase = strbase; /* Offset to String Numbers */ + + /* Endpoints */ + + dev[0].devdesc.epno[CDCACM_EP_INTIN_IDX] = 3; + dev[0].devdesc.epno[CDCACM_EP_BULKIN_IDX] = 4; + dev[0].devdesc.epno[CDCACM_EP_BULKOUT_IDX] = 5; + + /* Count up the base numbers */ + + ifnobase += dev[0].devdesc.ninterfaces; + strbase += dev[0].devdesc.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].classobject = board_mscclassobject; + dev[1].uninitialize = board_mscuninitialize; + + /* Interfaces */ + + dev[1].devdesc.ifnobase = ifnobase; /* Offset to Interface-IDs */ + dev[1].minor = 0; /* The minor interface number */ + + /* Strings */ + + dev[1].devdesc.strbase = strbase; /* Offset to String Numbers */ + + /* Endpoints */ + + dev[1].devdesc.epno[USBMSC_EP_BULKIN_IDX] = 1; + dev[1].devdesc.epno[USBMSC_EP_BULKOUT_IDX] = 2; + + /* Count up the base numbers */ + + ifnobase += dev[1].devdesc.ninterfaces; + strbase += dev[1].devdesc.nstrings; + + return composite_initialize(2, dev); +#else + return NULL; +#endif + } + + /* Configuration with three CDC/ACMs + * + * This configuration can be used e.g. on a samv71-xult. The samv71 has + * 10 Endpoints (EPs). The EPs 0 up to 7 are DMA aware. The EPs 8 and 9 + * are not. + * + * In a composite device we need the EP0 as an control Endpoint. Each + * CDC/ACM needs one Interrupt driven and two bulk Endpoints. This is + * why we configure the EPs 7, 8 and 9 to be the IRQ-EPs and the + * EP-Pairs 1/2, 3/4, 5/6 to be the bulk EPs for each device. + * + * This means, that + * + * - the Composite device uses EP0 as the control-Endpoint, + * - the CDC/ACM 0 uses EP7, EP1 and EP2, + * - the CDC/ACM 1 uses EP8, EP3 and EP4, + * - the CDC/ACM 2 uses EP9, EP5 and EP6 + * + * as its EP-Configuration. + */ + + else if (configid == 1) + { + struct composite_devdesc_s dev[3]; + int strbase = COMPOSITE_NSTRIDS; + int ifnobase = 0; + int ia; + + for (ia = 0; ia < 3; ia++) + { + /* Ask the cdcacm driver to fill in the constants we didn't know here */ + + cdcacm_get_composite_devdesc(&dev[ia]); + + /* Overwrite and correct some values... */ + /* The callback functions for the CDC/ACM class */ + + dev[ia].classobject = cdcacm_classobject; + dev[ia].uninitialize = cdcacm_uninitialize; + + dev[ia].minor = ia; /* The minor interface number */ + + /* Interfaces */ + + dev[ia].devdesc.ifnobase = ifnobase; /* Offset to Interface-IDs */ + + /* Strings */ + + dev[ia].devdesc.strbase = strbase; /* Offset to String Numbers */ + + /* Endpoints */ + + dev[ia].devdesc.epno[CDCACM_EP_INTIN_IDX] = 7 + ia; + dev[ia].devdesc.epno[CDCACM_EP_BULKIN_IDX] = 1 + ia * 2; + dev[ia].devdesc.epno[CDCACM_EP_BULKOUT_IDX] = 2 + ia * 2; + + ifnobase += dev[ia].devdesc.ninterfaces; + strbase += dev[ia].devdesc.nstrings; + } + + return composite_initialize(3, dev); + } + else + { + return NULL; + } +} + +#endif /* CONFIG_BOARDCTL_USBDEVCTRL && CONFIG_USBDEV_COMPOSITE */ diff --git a/configs/shenzhou/src/Makefile b/configs/shenzhou/src/Makefile index beecc845826..9c1705874a2 100644 --- a/configs/shenzhou/src/Makefile +++ b/configs/shenzhou/src/Makefile @@ -68,10 +68,6 @@ ifeq ($(CONFIG_USBMSC),y) CSRCS += stm32_usbmsc.c endif -ifeq ($(CONFIG_USBDEV_COMPOSITE),y) -CSRCS += stm32_composite.c -endif - ifeq ($(CONFIG_CAN),y) CSRCS += stm32_can.c endif diff --git a/configs/shenzhou/src/stm32_composite.c b/configs/shenzhou/src/stm32_composite.c deleted file mode 100644 index 4b6c6250a01..00000000000 --- a/configs/shenzhou/src/stm32_composite.c +++ /dev/null @@ -1,85 +0,0 @@ -/**************************************************************************** - * configs/shenzhou/src/stm32_composite.c - * - * Copyright (C) 2012, 2016 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Configure and register the STM32 SPI-based MMC/SD block driver. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include - -#include "shenzhou.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ -/* Configuration ************************************************************/ -/* Device minor number */ - -#ifndef CONFIG_SYSTEM_COMPOSITE_DEVMINOR1 -# define CONFIG_SYSTEM_COMPOSITE_DEVMINOR1 0 -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: board_composite_initialize - * - * Description: - * Perform architecture specific initialization of a composite USB device. - * - ****************************************************************************/ - -int board_composite_initialize(int port) -{ - /* If system/composite is built as an NSH command, then SD slot should - * already have been initialized in board_app_initialize() (see - * stm32_appinit.c). In this case, there is nothing further to be done here. - * - * NOTE: CONFIG_NSH_BUILTIN_APPS is not a fool-proof indication that NSH - * was built. - */ - -#ifndef CONFIG_NSH_BUILTIN_APPS - return sd_mount(CONFIG_SYSTEM_COMPOSITE_DEVMINOR1); -#else - return OK; -#endif /* CONFIG_NSH_BUILTIN_APPS */ -} diff --git a/configs/spark/composite/defconfig b/configs/spark/composite/defconfig index daa5c9d842a..7f0ed8f05ca 100644 --- a/configs/spark/composite/defconfig +++ b/configs/spark/composite/defconfig @@ -98,8 +98,6 @@ CONFIG_STM32_SPI_DMA=y CONFIG_STM32_USART2=y CONFIG_STM32_USB=y CONFIG_SYMTAB_ORDEREDBYNAME=y -CONFIG_SYSTEM_COMPOSITE_DEVPATH1="/dev/mtdblock0" -CONFIG_SYSTEM_COMPOSITE_DEVPATH2="/dev/mtdblock1" CONFIG_SYSTEM_COMPOSITE=y CONFIG_TASK_NAME_SIZE=7 CONFIG_TASK_SPAWN_DEFAULT_STACKSIZE=768 @@ -110,8 +108,6 @@ CONFIG_USBDEV_COMPOSITE=y CONFIG_USBDEV_TRACE_NRECORDS=32 CONFIG_USBDEV_TRACE=y CONFIG_USBMSC_COMPOSITE=y -CONFIG_USBMSC_EPBULKIN=5 -CONFIG_USBMSC_EPBULKOUT=4 CONFIG_USBMSC_NRDREQS=2 CONFIG_USBMSC_NWRREQS=2 CONFIG_USBMSC_SCSI_STACKSIZE=340 diff --git a/configs/spark/src/stm32_composite.c b/configs/spark/src/stm32_composite.c index 2c50a59a1f8..f1028a80b2c 100644 --- a/configs/spark/src/stm32_composite.c +++ b/configs/spark/src/stm32_composite.c @@ -54,6 +54,11 @@ # include #endif +#include +#include +#include +#include + #ifdef CONFIG_USBMONITOR # include #endif @@ -65,6 +70,8 @@ #include "stm32.h" #include "spark.h" +#if defined(CONFIG_BOARDCTL_USBDEVCTRL) && defined(CONFIG_USBDEV_COMPOSITE) + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -116,6 +123,14 @@ # undef HAVE_USBMONITOR #endif +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static FAR void *g_mschandle; +#endif + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -280,6 +295,270 @@ static int stm32_composite_initialize(void) } #endif +/**************************************************************************** + * Name: board_mscclassobject + * + * Description: + * If the mass storage class driver is part of composite device, then + * its instantiation and configuration is a multi-step, board-specific, + * process (See comments for usbmsc_configure below). In this case, + * board-specific logic must provide board_mscclassobject(). + * + * board_mscclassobject() is called from the composite driver. It must + * encapsulate the instantiation and configuration of the mass storage + * class and the return the mass storage device's class driver instance + * to the composite driver. + * + * Input Parameters: + * classdev - The location to return the mass storage class' device + * instance. + * + * Returned Value: + * 0 on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static int board_mscclassobject(int minor, + FAR struct usbdev_description_s *devdesc, + FAR struct usbdevclass_driver_s **classdev) +{ + int ret; + + DEBUGASSERT(g_mschandle == NULL); + + /* Configure the mass storage device */ + + uinfo("Configuring with NLUNS=1\n"); + ret = usbmsc_configure(1, &g_mschandle); + if (ret < 0) + { + uerr("ERROR: usbmsc_configure failed: %d\n", -ret); + return ret; + } + + uinfo("MSC handle=%p\n", g_mschandle); + + /* Bind the LUN(s) */ + + uinfo("Bind LUN=0 to /dev/mtdblock0\n"); + ret = usbmsc_bindlun(g_mschandle, "/dev/mtdblock0", 0, 0, 0, false); + if (ret < 0) + { + uerr("ERROR: usbmsc_bindlun failed for LUN 1 at /dev/mtdblock0: %d\n", + ret); + usbmsc_uninitialize(g_mschandle); + g_mschandle = NULL; + return ret; + } + + /* Get the mass storage device's class object */ + + ret = usbmsc_classobject(g_mschandle, devdesc, classdev); + if (ret < 0) + { + uerr("ERROR: usbmsc_classobject failed: %d\n", -ret); + usbmsc_uninitialize(g_mschandle); + g_mschandle = NULL; + } + + return ret; +} +#endif + + /**************************************************************************** + * Name: board_mscuninitialize + * + * Description: + * Un-initialize the USB storage class driver. This is just an application- + * specific wrapper aboutn usbmsc_unitialize() that is called form the + * composite device logic. + * + * Input Parameters: + * classdev - The class driver instrance previously give to the composite + * driver by board_mscclassobject(). + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static void board_mscuninitialize(FAR struct usbdevclass_driver_s *classdev) +{ + DEBUGASSERT(g_mschandle != NULL); + usbmsc_uninitialize(g_mschandle); + g_mschandle = NULL; +} +#endif + +/**************************************************************************** + * Name: board_composite0_connect + * + * Description: + * Connect the USB composite device on the specified USB device port for + * configuration 0. + * + * Input Parameters: + * port - The USB device port. + * + * Returned Value: + * A non-NULL handle value is returned on success. NULL is returned on + * any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static FAR void *board_composite0_connect(int port) +{ + /* 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; + + /* 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].classobject = cdcacm_classobject; + dev[0].uninitialize = cdcacm_uninitialize; + + /* Interfaces */ + + dev[0].devdesc.ifnobase = ifnobase; /* Offset to Interface-IDs */ + dev[0].minor = 0; /* The minor interface number */ + + /* Strings */ + + dev[0].devdesc.strbase = strbase; /* Offset to String Numbers */ + + /* Endpoints */ + + dev[0].devdesc.epno[CDCACM_EP_INTIN_IDX] = 1; + dev[0].devdesc.epno[CDCACM_EP_BULKIN_IDX] = 2; + dev[0].devdesc.epno[CDCACM_EP_BULKOUT_IDX] = 3; + + /* Count up the base numbers */ + + ifnobase += dev[0].devdesc.ninterfaces; + strbase += dev[0].devdesc.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].classobject = board_mscclassobject; + dev[1].uninitialize = board_mscuninitialize; + + /* Interfaces */ + + dev[1].devdesc.ifnobase = ifnobase; /* Offset to Interface-IDs */ + dev[1].minor = 0; /* The minor interface number */ + + /* Strings */ + + dev[1].devdesc.strbase = strbase; /* Offset to String Numbers */ + + /* Endpoints */ + + dev[1].devdesc.epno[USBMSC_EP_BULKIN_IDX] = 5; + dev[1].devdesc.epno[USBMSC_EP_BULKOUT_IDX] = 4; + + /* Count up the base numbers */ + + ifnobase += dev[1].devdesc.ninterfaces; + strbase += dev[1].devdesc.nstrings; + + return composite_initialize(2, dev); +} +#endif + +/**************************************************************************** + * Name: board_composite1_connect + * + * Description: + * Connect the USB composite device on the specified USB device port for + * configuration 1. + * + * Input Parameters: + * port - The USB device port. + * + * Returned Value: + * A non-NULL handle value is returned on success. NULL is returned on + * any failure. + * + ****************************************************************************/ + +static FAR void *board_composite1_connect(int port) +{ + /* REVISIT: This configuration currently fails. stm32_epallocpma() fails + * allocate a buffer for the 6th endpoint. Currenlty it supports 7x64 byte + * buffers, two required for EP0, leaving only buffers for 5 additional + * endpoints. + */ + +#if 0 + struct composite_devdesc_s dev[2]; + int strbase = COMPOSITE_NSTRIDS; + int ifnobase = 0; + int epno; + int i; + + for (i = 0, epno = 1; i < 2; i++) + { + /* Ask the cdcacm driver to fill in the constants we didn't know here */ + + cdcacm_get_composite_devdesc(&dev[i]); + + /* Overwrite and correct some values... */ + /* The callback functions for the CDC/ACM class */ + + dev[i].classobject = cdcacm_classobject; + dev[i].uninitialize = cdcacm_uninitialize; + + dev[i].minor = i; /* The minor interface number */ + + /* Interfaces */ + + dev[i].devdesc.ifnobase = ifnobase; /* Offset to Interface-IDs */ + + /* Strings */ + + dev[i].devdesc.strbase = strbase; /* Offset to String Numbers */ + + /* Endpoints */ + + dev[i].devdesc.epno[CDCACM_EP_INTIN_IDX] = epno++; + dev[i].devdesc.epno[CDCACM_EP_BULKIN_IDX] = epno++; + dev[i].devdesc.epno[CDCACM_EP_BULKOUT_IDX] = epno++; + + ifnobase += dev[i].devdesc.ninterfaces; + strbase += dev[i].devdesc.nstrings; + } + + return composite_initialize(2, dev); +#else + return NULL; +#endif +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -300,3 +579,43 @@ int board_composite_initialize(int port) return stm32_composite_initialize(); #endif } + +/**************************************************************************** + * Name: board_composite_connect + * + * Description: + * Connect the USB composite device on the specified USB device port using + * the specified configuration. The interpretation of the configid is + * board specific. + * + * Input Parameters: + * port - The USB device port. + * configid - The USB composite configuration + * + * Returned Value: + * A non-NULL handle value is returned on success. NULL is returned on + * any failure. + * + ****************************************************************************/ + +FAR void *board_composite_connect(int port, int configid) +{ + if (configid == 0) + { +#ifdef CONFIG_USBMSC_COMPOSITE + return board_composite0_connect(port); +#else + return NULL; +#endif + } + else if (configid == 1) + { + return board_composite1_connect(port); + } + else + { + return NULL; + } +} + +#endif /* CONFIG_BOARDCTL_USBDEVCTRL && CONFIG_USBDEV_COMPOSITE */ diff --git a/configs/stm3210e-eval/composite/defconfig b/configs/stm3210e-eval/composite/defconfig index 9053356f752..c39ea0632d7 100644 --- a/configs/stm3210e-eval/composite/defconfig +++ b/configs/stm3210e-eval/composite/defconfig @@ -58,11 +58,8 @@ CONFIG_USBDEV_COMPOSITE=y CONFIG_USBMSC_BULKINREQLEN=256 CONFIG_USBMSC_BULKOUTREQLEN=256 CONFIG_USBMSC_COMPOSITE=y -CONFIG_USBMSC_EPBULKIN=5 -CONFIG_USBMSC_EPBULKOUT=4 CONFIG_USBMSC_NRDREQS=2 CONFIG_USBMSC_NWRREQS=2 -CONFIG_USBMSC_PRODUCTSTR="USBdev Storage" CONFIG_USBMSC_REMOVABLE=y CONFIG_USBMSC_VERSIONNO=0x0399 CONFIG_USBMSC=y diff --git a/configs/stm3210e-eval/src/stm32_composite.c b/configs/stm3210e-eval/src/stm32_composite.c index d38a3f6a520..325d0b86de3 100644 --- a/configs/stm3210e-eval/src/stm32_composite.c +++ b/configs/stm3210e-eval/src/stm32_composite.c @@ -48,22 +48,23 @@ #include #include #include +#include +#include +#include #include #include "stm32.h" -/* There is nothing to do here if SDIO support is not selected. */ - -#if defined(CONFIG_STM32_SDIO) && defined(CONFIG_USBDEV_COMPOSITE) +#if defined(CONFIG_BOARDCTL_USBDEVCTRL) && defined(CONFIG_USBDEV_COMPOSITE) /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -/* Configuration ************************************************************/ +/* No SDIO? Then no USB MSC device in composite */ -#ifndef CONFIG_SYSTEM_COMPOSITE_DEVMINOR1 -# define CONFIG_SYSTEM_COMPOSITE_DEVMINOR1 0 +#ifndef CONFIG_STM32_SDIO +# undef CONFIG_USBMSC_COMPOSITE #endif /* SLOT number(s) could depend on the board configuration */ @@ -76,6 +77,282 @@ # error "Unrecognized STM32 board" #endif +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static FAR void *g_mschandle; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_mscclassobject + * + * Description: + * If the mass storage class driver is part of composite device, then + * its instantiation and configuration is a multi-step, board-specific, + * process (See comments for usbmsc_configure below). In this case, + * board-specific logic must provide board_mscclassobject(). + * + * board_mscclassobject() is called from the composite driver. It must + * encapsulate the instantiation and configuration of the mass storage + * class and the return the mass storage device's class driver instance + * to the composite driver. + * + * Input Parameters: + * classdev - The location to return the mass storage class' device + * instance. + * + * Returned Value: + * 0 on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static int board_mscclassobject(int minor, + FAR struct usbdev_description_s *devdesc, + FAR struct usbdevclass_driver_s **classdev) +{ + int ret; + + DEBUGASSERT(g_mschandle == NULL); + + /* Configure the mass storage device */ + + uinfo("Configuring with NLUNS=1\n"); + ret = usbmsc_configure(1, &g_mschandle); + if (ret < 0) + { + uerr("ERROR: usbmsc_configure failed: %d\n", -ret); + return ret; + } + + uinfo("MSC handle=%p\n", g_mschandle); + + /* Bind the LUN(s) */ + + uinfo("Bind LUN=0 to /dev/mmcsd0\n"); + ret = usbmsc_bindlun(g_mschandle, "/dev/mmcsd0", 0, 0, 0, false); + if (ret < 0) + { + uerr("ERROR: usbmsc_bindlun failed for LUN 1 at /dev/mmcsd0: %d\n", + ret); + usbmsc_uninitialize(g_mschandle); + g_mschandle = NULL; + return ret; + } + + /* Get the mass storage device's class object */ + + ret = usbmsc_classobject(g_mschandle, devdesc, classdev); + if (ret < 0) + { + uerr("ERROR: usbmsc_classobject failed: %d\n", -ret); + usbmsc_uninitialize(g_mschandle); + g_mschandle = NULL; + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: board_mscuninitialize + * + * Description: + * Un-initialize the USB storage class driver. This is just an application- + * specific wrapper aboutn usbmsc_unitialize() that is called form the + * composite device logic. + * + * Input Parameters: + * classdev - The class driver instrance previously give to the composite + * driver by board_mscclassobject(). + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static void board_mscuninitialize(FAR struct usbdevclass_driver_s *classdev) +{ + DEBUGASSERT(g_mschandle != NULL); + usbmsc_uninitialize(g_mschandle); + g_mschandle = NULL; +} +#endif + +/**************************************************************************** + * Name: board_composite0_connect + * + * Description: + * Connect the USB composite device on the specified USB device port for + * configuration 0. + * + * Input Parameters: + * port - The USB device port. + * + * Returned Value: + * A non-NULL handle value is returned on success. NULL is returned on + * any failure. + * + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +static FAR void *board_composite0_connect(int port) +{ + /* 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; + + /* 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].classobject = cdcacm_classobject; + dev[0].uninitialize = cdcacm_uninitialize; + + /* Interfaces */ + + dev[0].devdesc.ifnobase = ifnobase; /* Offset to Interface-IDs */ + dev[0].minor = 0; /* The minor interface number */ + + /* Strings */ + + dev[0].devdesc.strbase = strbase; /* Offset to String Numbers */ + + /* Endpoints */ + + dev[0].devdesc.epno[CDCACM_EP_INTIN_IDX] = 1; + dev[0].devdesc.epno[CDCACM_EP_BULKIN_IDX] = 2; + dev[0].devdesc.epno[CDCACM_EP_BULKOUT_IDX] = 3; + + /* Count up the base numbers */ + + ifnobase += dev[0].devdesc.ninterfaces; + strbase += dev[0].devdesc.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].classobject = board_mscclassobject; + dev[1].uninitialize = board_mscuninitialize; + + /* Interfaces */ + + dev[1].devdesc.ifnobase = ifnobase; /* Offset to Interface-IDs */ + dev[1].minor = 0; /* The minor interface number */ + + /* Strings */ + + dev[1].devdesc.strbase = strbase; /* Offset to String Numbers */ + + /* Endpoints */ + + dev[1].devdesc.epno[USBMSC_EP_BULKIN_IDX] = 5; + dev[1].devdesc.epno[USBMSC_EP_BULKOUT_IDX] = 4; + + /* Count up the base numbers */ + + ifnobase += dev[1].devdesc.ninterfaces; + strbase += dev[1].devdesc.nstrings; + + return composite_initialize(2, dev); +} +#endif + +/**************************************************************************** + * Name: board_composite1_connect + * + * Description: + * Connect the USB composite device on the specified USB device port for + * configuration 1. + * + * Input Parameters: + * port - The USB device port. + * + * Returned Value: + * A non-NULL handle value is returned on success. NULL is returned on + * any failure. + * + ****************************************************************************/ + +static FAR void *board_composite1_connect(int port) +{ + /* REVISIT: This configuration currently fails. stm32_epallocpma() fails + * allocate a buffer for the 6th endpoint. Currenlty it supports 7x64 byte + * buffers, two required for EP0, leaving only buffers for 5 additional + * endpoints. + */ + +#if 0 + struct composite_devdesc_s dev[2]; + int strbase = COMPOSITE_NSTRIDS; + int ifnobase = 0; + int epno; + int i; + + for (i = 0, epno = 1; i < 2; i++) + { + /* Ask the cdcacm driver to fill in the constants we didn't know here */ + + cdcacm_get_composite_devdesc(&dev[i]); + + /* Overwrite and correct some values... */ + /* The callback functions for the CDC/ACM class */ + + dev[i].classobject = cdcacm_classobject; + dev[i].uninitialize = cdcacm_uninitialize; + + dev[i].minor = i; /* The minor interface number */ + + /* Interfaces */ + + dev[i].devdesc.ifnobase = ifnobase; /* Offset to Interface-IDs */ + + /* Strings */ + + dev[i].devdesc.strbase = strbase; /* Offset to String Numbers */ + + /* Endpoints */ + + dev[i].devdesc.epno[CDCACM_EP_INTIN_IDX] = epno++; + dev[i].devdesc.epno[CDCACM_EP_BULKIN_IDX] = epno++; + dev[i].devdesc.epno[CDCACM_EP_BULKOUT_IDX] = epno++; + + ifnobase += dev[i].devdesc.ninterfaces; + strbase += dev[i].devdesc.nstrings; + } + + return composite_initialize(2, dev); +#else + return NULL; +#endif +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -116,10 +393,9 @@ int board_composite_initialize(int port) /* Now bind the SDIO interface to the MMC/SD driver */ - syslog(LOG_INFO, "Bind SDIO to the MMC/SD driver, minor=%d\n", - CONFIG_SYSTEM_COMPOSITE_DEVMINOR1); + syslog(LOG_INFO, "Bind SDIO to the MMC/SD driver, minor=0\n"); - ret = mmcsd_slotinitialize(CONFIG_SYSTEM_COMPOSITE_DEVMINOR1, sdio); + ret = mmcsd_slotinitialize(0, sdio); if (ret != OK) { syslog(LOG_ERR, @@ -142,4 +418,42 @@ int board_composite_initialize(int port) return OK; } -#endif /* CONFIG_STM32_SDIO && CONFIG_USBDEV_COMPOSITE */ +/**************************************************************************** + * Name: board_composite_connect + * + * Description: + * Connect the USB composite device on the specified USB device port using + * the specified configuration. The interpretation of the configid is + * board specific. + * + * Input Parameters: + * port - The USB device port. + * configid - The USB composite configuration + * + * Returned Value: + * A non-NULL handle value is returned on success. NULL is returned on + * any failure. + * + ****************************************************************************/ + +FAR void *board_composite_connect(int port, int configid) +{ + if (configid == 0) + { +#ifdef CONFIG_USBMSC_COMPOSITE + return board_composite0_connect(port); +#else + return NULL; +#endif + } + else if (configid == 1) + { + return board_composite1_connect(port); + } + else + { + return NULL; + } +} + +#endif /* CONFIG_BOARDCTL_USBDEVCTRL && CONFIG_USBDEV_COMPOSITE */ 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..bf845f778b9 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); @@ -211,6 +213,7 @@ static bool cdcuart_txempty(FAR struct uart_dev_s *dev); /**************************************************************************** * Private Data ****************************************************************************/ + /* USB class device *********************************************************/ static const struct usbdevclass_driverops_s g_driverops = @@ -275,7 +278,8 @@ static const struct uart_ops_s g_uartops = * ****************************************************************************/ -static uint16_t cdcacm_fillrequest(FAR struct cdcacm_dev_s *priv, uint8_t *reqbuf, +static uint16_t cdcacm_fillrequest(FAR struct cdcacm_dev_s *priv, + FAR uint8_t *reqbuf, uint16_t reqlen) { FAR uart_dev_t *serdev = &priv->serdev; @@ -287,7 +291,9 @@ static uint16_t cdcacm_fillrequest(FAR struct cdcacm_dev_s *priv, uint8_t *reqbu flags = enter_critical_section(); - /* Transfer bytes while we have bytes available and there is room in the request */ + /* Transfer bytes while we have bytes available and there is room in the + * request. + */ while (xmit->head != xmit->tail && nbytes < reqlen) { @@ -302,8 +308,8 @@ static uint16_t cdcacm_fillrequest(FAR struct cdcacm_dev_s *priv, uint8_t *reqbu } } - /* When all of the characters have been sent from the buffer - * disable the "TX interrupt". + /* When all of the characters have been sent from the buffer disable the + * "TX interrupt". */ if (xmit->head == xmit->tail) @@ -311,8 +317,8 @@ static uint16_t cdcacm_fillrequest(FAR struct cdcacm_dev_s *priv, uint8_t *reqbu uart_disabletxint(serdev); } - /* If any bytes were removed from the buffer, inform any waiters - * there there is space available. + /* If any bytes were removed from the buffer, inform any waiters that + * there is space available. */ if (nbytes) @@ -329,9 +335,9 @@ static uint16_t cdcacm_fillrequest(FAR struct cdcacm_dev_s *priv, uint8_t *reqbu * * Description: * This function obtains write requests, transfers the TX data into the - * request, and submits the requests to the USB controller. This continues - * until either (1) there are no further packets available, or (2) there is - * no further data to send. + * request, and submits the requests to the USB controller. This + * continues until either (1) there are no further packets available, or + * (2) there is no further data to send. * ****************************************************************************/ @@ -359,9 +365,9 @@ static int cdcacm_sndpacket(FAR struct cdcacm_dev_s *priv) ep = priv->epbulkin; - /* Loop until either (1) we run out or write requests, or (2) cdcacm_fillrequest() - * is unable to fill the request with data (i.e., until there is no more data - * to be sent). + /* Loop until either (1) we run out or write requests, or (2) + * cdcacm_fillrequest() is unable to fill the request with data (i.e., + * until there is no more data to be sent). */ uinfo("head=%d tail=%d nwrq=%d empty=%d\n", @@ -425,7 +431,7 @@ static int cdcacm_sndpacket(FAR struct cdcacm_dev_s *priv) ****************************************************************************/ static inline int cdcacm_recvpacket(FAR struct cdcacm_dev_s *priv, - uint8_t *reqbuf, uint16_t reqlen) + FAR uint8_t *reqbuf, uint16_t reqlen) { FAR uart_dev_t *serdev = &priv->serdev; FAR struct uart_buffer_s *recv = &serdev->recv; @@ -436,11 +442,12 @@ static inline int cdcacm_recvpacket(FAR struct cdcacm_dev_s *priv, uinfo("head=%d tail=%d nrdq=%d reqlen=%d\n", priv->serdev.recv.head, priv->serdev.recv.tail, priv->nrdq, reqlen); - /* Get the next head index. During the time that RX interrupts are disabled, the - * the serial driver will be extracting data from the circular buffer and modifying - * recv.tail. During this time, we should avoid modifying recv.head; Instead we will - * use a shadow copy of the index. When interrupts are restored, the real recv.head - * will be updated with this index. + /* Get the next head index. During the time that RX interrupts are + * disabled, the the serial driver will be extracting data from the + * circular buffer and modifying recv.tail. During this time, we should + * avoid modifying recv.head; Instead we will use a shadow copy of the + * index. When interrupts are restored, the real recv.head will be + * updated with this index. */ if (priv->rxenabled) @@ -452,9 +459,9 @@ static inline int cdcacm_recvpacket(FAR struct cdcacm_dev_s *priv, currhead = priv->rxhead; } - /* Pre-calculate the head index and check for wrap around. We need to do this - * so that we can determine if the circular buffer will overrun BEFORE we - * overrun the buffer! + /* Pre-calculate the head index and check for wrap around. We need to do + * this so that we can determine if the circular buffer will overrun + * BEFORE we overrun the buffer! */ nexthead = currhead + 1; @@ -463,17 +470,17 @@ static inline int cdcacm_recvpacket(FAR struct cdcacm_dev_s *priv, nexthead = 0; } - /* Then copy data into the RX buffer until either: (1) all of the data has been - * copied, or (2) the RX buffer is full. + /* Then copy data into the RX buffer until either: (1) all of the data has + * been copied, or (2) the RX buffer is full. * - * NOTE: If the RX buffer becomes full, then we have overrun the serial driver - * and data will be lost. This is the correct behavior for a proper emulation - * of a serial link. It should not NAK, it should drop data like a physical - * serial port. + * NOTE: If the RX buffer becomes full, then we have overrun the serial + * driver and data will be lost. This is the correct behavior for a + * proper emulation of a serial link. It should not NAK, it should drop + * data like a physical serial port. * - * If you don't like that behavior. DO NOT change it here. Instead, you should - * finish the implementation of RX flow control which is the only proper way - * to throttle a serial device. + * If you don't like that behavior. DO NOT change it here. Instead, you + * should finish the implementation of RX flow control which is the only + * proper way to throttle a serial device. */ while (nexthead != recv->tail && nbytes < reqlen) @@ -527,6 +534,7 @@ static inline int cdcacm_recvpacket(FAR struct cdcacm_dev_s *priv, usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RXOVERRUN), 0); return -ENOSPC; } + return OK; } @@ -575,6 +583,7 @@ static void cdcacm_freereq(FAR struct usbdev_ep_s *ep, { EP_FREEBUFFER(ep, req->buf); } + EP_FREEREQ(ep, req); } } @@ -623,16 +632,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 +698,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 +721,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 +744,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) @@ -764,7 +772,8 @@ static int cdcacm_setconfig(FAR struct cdcacm_dev_s *priv, uint8_t config) ret = EP_SUBMIT(priv->epbulkout, req); if (ret != OK) { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSUBMIT), (uint16_t)-ret); + usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSUBMIT), + (uint16_t)-ret); goto errout; } @@ -852,7 +861,8 @@ static void cdcacm_rdcomplete(FAR struct usbdev_ep_s *ep, return; default: /* Some other error occurred */ - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDUNEXPECTED), (uint16_t)-req->result); + usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDUNEXPECTED), + (uint16_t)-req->result); break; }; @@ -862,7 +872,8 @@ static void cdcacm_rdcomplete(FAR struct usbdev_ep_s *ep, ret = EP_SUBMIT(ep, req); if (ret != OK) { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSUBMIT), (uint16_t)-req->result); + usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSUBMIT), + (uint16_t)-req->result); } leave_critical_section(flags); @@ -927,7 +938,8 @@ static void cdcacm_wrcomplete(FAR struct usbdev_ep_s *ep, default: /* Some other error occurred */ { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_WRUNEXPECTED), (uint16_t)-req->result); + usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_WRUNEXPECTED), + (uint16_t)-req->result); } break; } @@ -967,7 +979,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 +1004,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 +1017,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 +1030,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); @@ -1205,6 +1220,7 @@ static void cdcacm_unbind(FAR struct usbdevclass_driver_s *driver, flags = enter_critical_section(); DEBUGASSERT(priv->nwrq == CONFIG_CDCACM_NWRREQS); + while (!sq_empty(&priv->reqlist)) { reqcontainer = (struct cdcacm_req_s *)sq_remfirst(&priv->reqlist); @@ -1274,6 +1290,7 @@ static int cdcacm_setup(FAR struct usbdevclass_driver_s *driver, return -ENODEV; } #endif + ctrlreq = priv->ctrlreq; /* Extract the little-endian 16-bit values to host order */ @@ -1287,23 +1304,24 @@ static int cdcacm_setup(FAR struct usbdevclass_driver_s *driver, if ((ctrl->type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD) { - /*********************************************************************** + /********************************************************************** * Standard Requests - ***********************************************************************/ + **********************************************************************/ switch (ctrl->req) { case USB_REQ_GETDESCRIPTOR: { - /* The value field specifies the descriptor type in the MS byte and the - * descriptor index in the LS byte (order is little endian) + /* The value field specifies the descriptor type in the MS byte + * and the descriptor index in the LS byte (order is little + * endian) */ switch (ctrl->value[1]) { - /* If the serial device is used in as part of a composite device, - * then the device descriptor is provided by logic in the composite - * device implementation. + /* If the serial device is used in as part of a composite + * device, then the device descriptor is provided by logic in + * the composite device implementation. */ #ifndef CONFIG_CDCACM_COMPOSITE @@ -1315,9 +1333,9 @@ static int cdcacm_setup(FAR struct usbdevclass_driver_s *driver, break; #endif - /* If the serial device is used in as part of a composite device, - * then the device qualifier descriptor is provided by logic in the - * composite device implementation. + /* If the serial device is used in as part of a composite + * device, then the device qualifier descriptor is provided by + * logic in the composite device implementation. */ #if !defined(CONFIG_CDCACM_COMPOSITE) && defined(CONFIG_USBDEV_DUALSPEED) @@ -1331,26 +1349,27 @@ static int cdcacm_setup(FAR struct usbdevclass_driver_s *driver, case USB_DESC_TYPE_OTHERSPEEDCONFIG: #endif - /* If the serial device is used in as part of a composite device, - * then the configuration descriptor is provided by logic in the - * composite device implementation. + /* If the serial device is used in as part of a composite + * device, then the configuration descriptor is provided by + * logic in the composite device implementation. */ #ifndef CONFIG_CDCACM_COMPOSITE case USB_DESC_TYPE_CONFIG: { #ifdef CONFIG_USBDEV_DUALSPEED - ret = cdcacm_mkcfgdesc(ctrlreq->buf, dev->speed, ctrl->req); + ret = cdcacm_mkcfgdesc(ctrlreq->buf, dev->speed, + ctrl->req); #else - ret = cdcacm_mkcfgdesc(ctrlreq->buf); + ret = cdcacm_mkcfgdesc(ctrlreq->buf, 0); #endif } break; #endif - /* If the serial device is used in as part of a composite device, - * then the language string descriptor is provided by logic in the - * composite device implementation. + /* If the serial device is used in as part of a composite + * device, then the language string descriptor is provided by + * logic in the composite device implementation. */ #ifndef CONFIG_CDCACM_COMPOSITE @@ -1358,7 +1377,10 @@ static int cdcacm_setup(FAR struct usbdevclass_driver_s *driver, { /* index == language code. */ - ret = cdcacm_mkstrdesc(ctrl->value[0], (struct usb_strdesc_s *)ctrlreq->buf); + ret = + cdcacm_mkstrdesc(ctrl->value[0], + (FAR struct usb_strdesc_s *) + ctrlreq->buf); } break; #endif @@ -1403,8 +1425,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 +1443,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; @@ -1441,29 +1467,33 @@ static int cdcacm_setup(FAR struct usbdevclass_driver_s *driver, else if ((ctrl->type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_CLASS) { - /*********************************************************************** + /********************************************************************** * CDC ACM-Specific Requests - ***********************************************************************/ + **********************************************************************/ switch (ctrl->req) { - /* ACM_GET_LINE_CODING requests current DTE rate, stop-bits, parity, and - * number-of-character bits. (Optional) + /* ACM_GET_LINE_CODING requests current DTE rate, stop-bits, parity, + * and number-of-character bits. (Optional) */ 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 */ + /* Return the current line status from the private data + * structure. + */ - memcpy(ctrlreq->buf, &priv->linecoding, SIZEOF_CDC_LINECODING); + memcpy(ctrlreq->buf, &priv->linecoding, + SIZEOF_CDC_LINECODING); ret = SIZEOF_CDC_LINECODING; } else { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDCLASSREQ), ctrl->type); + usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDCLASSREQ), + ctrl->type); } } break; @@ -1476,12 +1506,12 @@ 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 - * drivers supported provision of EP0 OUT data with the setup - * command. + /* Save the new line coding in the private data structure. + * NOTE: that this is conditional now because not all device + * controller drivers supported provision of EP0 OUT data + * with the setup command. */ if (dataout && len <= SIZEOF_CDC_LINECODING) /* REVISIT */ @@ -1493,8 +1523,8 @@ static int cdcacm_setup(FAR struct usbdevclass_driver_s *driver, ret = 0; - /* If there is a registered callback to receive line status info, then - * callout now. + /* If there is a registered callback to receive line status + * info, then callout now. */ if (priv->callback) @@ -1509,24 +1539,25 @@ static int cdcacm_setup(FAR struct usbdevclass_driver_s *driver, } break; - /* ACM_SET_CTRL_LINE_STATE: RS-232 signal used to tell the DCE device the - * DTE device is now present. (Optional) + /* ACM_SET_CTRL_LINE_STATE: RS-232 signal used to tell the DCE + * device the DTE device is now present. (Optional) */ 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. + /* Save the control line state in the private data + * structure. Only bits 0 and 1 have meaning. Respond with + * a zero length packet. */ priv->ctrlline = value & 3; ret = 0; - /* If there is a registered callback to receive control line status info, - * then callout now. + /* If there is a registered callback to receive control line + * status info, then callout now. */ if (priv->callback) @@ -1546,10 +1577,11 @@ 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. + /* If there is a registered callback to handle the SendBreak + * request, then callout now. Respond with a zero length + * packet. */ ret = 0; @@ -1922,9 +1954,9 @@ static int cdcuart_ioctl(FAR struct file *filep, int cmd, unsigned long arg) /* CAIOC_NOTIFY * Send a serial state to the host via the Interrupt IN endpoint. - * Argument: int. This includes the current state of the carrier detect, - * DSR, break, and ring signal. See "Table 69: UART State Bitmap Values" - * and CDC_UART_definitions in include/nuttx/usb/cdc.h. + * Argument: int. This includes the current state of the carrier + * detect, DSR, break, and ring signal. See "Table 69: UART State + * Bitmap Values" and CDC_UART_definitions in include/nuttx/usb/cdc.h. */ case CAIOC_NOTIFY: @@ -1937,7 +1969,8 @@ static int cdcuart_ioctl(FAR struct file *filep, int cmd, unsigned long arg) * 1. Format and send a request header with: * * bmRequestType: - * USB_REQ_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE + * USB_REQ_DIR_IN | USB_REQ_TYPE_CLASS | + * USB_REQ_RECIPIENT_INTERFACE * bRequest: ACM_SERIAL_STATE * wValue: 0 * wIndex: 0 @@ -2166,6 +2199,7 @@ static void cdcuart_rxint(FAR struct uart_dev_s *dev, bool enable) priv->rxhead = serdev->recv.head; priv->rxenabled = false; } + leave_critical_section(flags); } @@ -2312,7 +2346,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; @@ -2322,7 +2357,9 @@ int cdcacm_classobject(int minor, FAR struct usbdevclass_driver_s **classdev) /* Allocate the structures needed */ - alloc = (FAR struct cdcacm_alloc_s *)kmm_malloc(sizeof(struct cdcacm_alloc_s)); + alloc = (FAR struct cdcacm_alloc_s *) + kmm_malloc(sizeof(struct cdcacm_alloc_s)); + if (!alloc) { usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_ALLOCDEVSTRUCT), 0); @@ -2340,6 +2377,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 */ @@ -2368,12 +2407,12 @@ int cdcacm_classobject(int minor, FAR struct usbdevclass_driver_s **classdev) /* Initialize the USB class driver structure */ #ifdef CONFIG_USBDEV_DUALSPEED - drvr->drvr.speed = USB_SPEED_HIGH; + drvr->drvr.speed = USB_SPEED_HIGH; #else - drvr->drvr.speed = USB_SPEED_FULL; + drvr->drvr.speed = USB_SPEED_FULL; #endif - drvr->drvr.ops = &g_driverops; - drvr->dev = priv; + drvr->drvr.ops = &g_driverops; + drvr->dev = priv; /* Register the USB serial console */ @@ -2427,11 +2466,35 @@ 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. + * + * ifnobase must be provided by board-specific logic + */ + + devdesc.ninterfaces = CDCACM_NINTERFACES; /* Number of interfaces in the configuration */ + + /* Strings. + * + * strbase must be provided by board-specific logic + */ + + devdesc.nstrings = CDCACM_NSTRIDS; /* Number of Strings */ + + /* Endpoints. + * + * Endpoint numbers must be provided by board-specific logic. + */ + + devdesc.nendpoints = CDCACM_NUM_EPS; + /* 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 */ @@ -2439,7 +2502,8 @@ int cdcacm_initialize(int minor, FAR void **handle) ret = usbdev_register(drvr); if (ret < 0) { - usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_DEVREGISTER), (uint16_t)-ret); + usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_DEVREGISTER), + (uint16_t)-ret); } } @@ -2470,8 +2534,7 @@ int cdcacm_initialize(int minor, FAR void **handle) * CDC/ACM driver is an internal part of a composite device, or a standalone * USB driver: * - * classdev - The class object returned by board_cdcclassobject() or - * cdcacm_classobject() + * classdev - The class object returned by cdcacm_classobject() * handle - The opaque handle representing the class object returned by * a previous call to cdcacm_initialize(). * @@ -2549,3 +2612,68 @@ 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) +{ + memset(dev, 0, sizeof(struct composite_devdesc_s)); + + /* The callback functions for the CDC/ACM class. + * + * classobject() and uninitialize() must be provided by board-specific + * logic + */ + + dev->mkconfdesc = cdcacm_mkcfgdesc; + dev->mkstrdesc = cdcacm_mkstrdesc; + + 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 + + /* Board-specific logic must provide the device minor */ + + /* Interfaces. + * + * ifnobase must be provided by board-specific logic + */ + + dev->devdesc.ninterfaces = CDCACM_NINTERFACES; /* Number of interfaces in the configuration */ + + /* Strings. + * + * strbase must be provided by board-specific logic + */ + + dev->devdesc.nstrings = CDCACM_NSTRIDS; /* Number of Strings */ + + /* Endpoints. + * + * Endpoint numbers must be provided by board-specific logic. + */ + + dev->devdesc.nendpoints = CDCACM_NUM_EPS; +} +#endif diff --git a/drivers/usbdev/cdcacm.h b/drivers/usbdev/cdcacm.h index 4b0803748a0..a70c61e9e42 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,12 @@ 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, + 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 /**************************************************************************** diff --git a/drivers/usbdev/cdcacm_desc.c b/drivers/usbdev/cdcacm_desc.c index 221734a71e5..365480770a7 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,35 +46,13 @@ #include #include +#include #include #include #include #include "cdcacm.h" -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * 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 - ****************************************************************************/ - /**************************************************************************** * Private Data ****************************************************************************/ @@ -117,241 +95,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 +118,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 +227,115 @@ 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; + } + + return sizeof(struct usb_epdesc_s); +} /**************************************************************************** * Name: cdcacm_mkcfgdesc @@ -562,17 +346,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 +368,226 @@ 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 */ - - 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 */ + + 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 + + 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); + + 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 */ + + 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 */ + + 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 */ + + 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 + + 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 +604,5 @@ FAR const struct usb_qualdesc_s *cdcacm_getqualdesc(void) return &g_qualdesc; } #endif + + diff --git a/drivers/usbdev/composite.c b/drivers/usbdev/composite.c index 54bc3c827e3..ae9c73697ef 100644 --- a/drivers/usbdev/composite.c +++ b/drivers/usbdev/composite.c @@ -1,7 +1,7 @@ /**************************************************************************** * drivers/usbdev/composite.c * - * Copyright (C) 2012, 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2012, 2016-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -60,17 +60,6 @@ * Private Types ****************************************************************************/ -/* This structure describes the internal state of the driver */ - -struct composite_dev_s -{ - FAR struct usbdev_s *usbdev; /* usbdev driver pointer */ - uint8_t config; /* Configuration number */ - FAR struct usbdev_req_s *ctrlreq; /* Allocated control request */ - struct usbdevclass_driver_s *dev1; /* Device 1 class object */ - struct usbdevclass_driver_s *dev2; /* Device 2 class object */ -}; - /* The internal version of the class driver */ struct composite_driver_s @@ -123,6 +112,7 @@ static void composite_resume(FAR struct usbdevclass_driver_s *driver, /**************************************************************************** * Private Data ****************************************************************************/ + /* USB class device *********************************************************/ static const struct usbdevclass_driverops_s g_driverops = @@ -146,9 +136,6 @@ const char g_compserialstr[] = CONFIG_COMPOSITE_SERIALSTR; /**************************************************************************** * Private Functions ****************************************************************************/ -/**************************************************************************** - * Helpers - ****************************************************************************/ /**************************************************************************** * Name: composite_ep0incomplete @@ -165,7 +152,8 @@ static void composite_ep0incomplete(FAR struct usbdev_ep_s *ep, if (req->result || req->xfrd != req->len) { - usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_REQRESULT), (uint16_t)-req->result); + usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_REQRESULT), + (uint16_t)-req->result); } } @@ -185,17 +173,20 @@ static int composite_classsetup(FAR struct composite_dev_s *priv, uint16_t index; uint8_t interface; int ret = -EOPNOTSUPP; + int i; index = GETUINT16(ctrl->index); interface = (uint8_t)(index & 0xff); - if (interface >= DEV1_FIRSTINTERFACE && interface < (DEV1_FIRSTINTERFACE + DEV1_NINTERFACES)) + for (i = 0; i < priv->ndevices; i++) { - ret = CLASS_SETUP(priv->dev1, dev, ctrl, dataout, outlen); - } - else if (interface >= DEV2_FIRSTINTERFACE && interface < (DEV2_FIRSTINTERFACE + DEV2_NINTERFACES)) - { - ret = CLASS_SETUP(priv->dev2, dev, ctrl, dataout, outlen); + if (interface >= priv->device[i].compdesc.devdesc.ifnobase && + interface < (priv->device[i].compdesc.devdesc.ifnobase + + priv->device[i].compdesc.devdesc.ninterfaces)) + { + ret = CLASS_SETUP(priv->device[i].dev, dev, ctrl, dataout, outlen); + break; + } } return ret; @@ -225,6 +216,7 @@ static struct usbdev_req_s *composite_allocreq(FAR struct usbdev_ep_s *ep, req = NULL; } } + return req; } @@ -245,6 +237,7 @@ static void composite_freereq(FAR struct usbdev_ep_s *ep, { EP_FREEBUFFER(ep, req->buf); } + EP_FREEREQ(ep, req); } } @@ -264,8 +257,11 @@ static void composite_freereq(FAR struct usbdev_ep_s *ep, static int composite_bind(FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_s *dev) { - FAR struct composite_dev_s *priv = ((FAR struct composite_driver_s *)driver)->dev; + FAR struct composite_dev_s *priv = + ((FAR struct composite_driver_s *)driver)->dev; + int ret; + int i; usbtrace(TRACE_CLASSBIND, 0); @@ -281,7 +277,7 @@ static int composite_bind(FAR struct usbdevclass_driver_s *driver, /* Preallocate one control request */ - priv->ctrlreq = composite_allocreq(dev->ep0, COMPOSITE_CFGDESCSIZE); + priv->ctrlreq = composite_allocreq(dev->ep0, priv->cfgdescsize); if (priv->ctrlreq == NULL) { usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_ALLOCCTRLREQ), 0); @@ -295,16 +291,13 @@ static int composite_bind(FAR struct usbdevclass_driver_s *driver, /* Then bind each of the constituent class drivers */ - ret = CLASS_BIND(priv->dev1, dev); - if (ret < 0) + for (i = 0; i < priv->ndevices; i++) { - goto errout; - } - - ret = CLASS_BIND(priv->dev2, dev); - if (ret < 0) - { - goto errout; + ret = CLASS_BIND(priv->device[i].dev, dev); + if (ret < 0) + { + goto errout; + } } /* Report if we are selfpowered */ @@ -363,11 +356,15 @@ static void composite_unbind(FAR struct usbdevclass_driver_s *driver, if (priv != NULL) { + int i; + /* Unbind the constituent class drivers */ flags = enter_critical_section(); - CLASS_UNBIND(priv->dev1, dev); - CLASS_UNBIND(priv->dev2, dev); + for (i = 0; i < priv->ndevices; i++) + { + CLASS_UNBIND(priv->device[i].dev, dev); + } /* Free the pre-allocated control request */ @@ -377,6 +374,7 @@ static void composite_unbind(FAR struct usbdevclass_driver_s *driver, composite_freereq(dev->ep0, priv->ctrlreq); priv->ctrlreq = NULL; } + leave_critical_section(flags); } } @@ -423,6 +421,7 @@ static int composite_setup(FAR struct usbdevclass_driver_s *driver, return -ENODEV; } #endif + ctrlreq = priv->ctrlreq; /* Extract the little-endian 16-bit values to host order */ @@ -472,10 +471,10 @@ static int composite_setup(FAR struct usbdevclass_driver_s *driver, case USB_DESC_TYPE_CONFIG: { #ifdef CONFIG_USBDEV_DUALSPEED - ret = composite_mkcfgdesc(ctrlreq->buf, dev->speed, + ret = composite_mkcfgdesc(priv, ctrlreq->buf, dev->speed, ctrl->value[1]); #else - ret = composite_mkcfgdesc(ctrlreq->buf); + ret = composite_mkcfgdesc(priv, ctrlreq->buf); #endif } break; @@ -491,18 +490,21 @@ static int composite_setup(FAR struct usbdevclass_driver_s *driver, { ret = composite_mkstrdesc(strid, buf); } -#if DEV1_NSTRIDS > 0 - else if (strid <= DEV1_STRIDBASE + DEV1_NSTRIDS) + else { - ret = DEV1_MKSTRDESC(strid, buf); + int i; + + for (i = 0; i < priv->ndevices; i++) + { + if (strid >= priv->device[i].compdesc.devdesc.strbase && + strid < priv->device[i].compdesc.devdesc.strbase + + priv->device[i].compdesc.devdesc.nstrings) + { + ret = priv->device[i].compdesc.mkstrdesc(strid - priv->device[i].compdesc.devdesc.strbase, buf); + break; + } + } } -#endif -#if DEV2_NSTRIDS > 0 - else if (strid <= DEV2_STRIDBASE + DEV2_NSTRIDS) - { - ret = DEV2_MKSTRDESC(strid, buf); - } -#endif } break; @@ -519,19 +521,17 @@ static int composite_setup(FAR struct usbdevclass_driver_s *driver, { if (ctrl->type == 0) { + int i; + /* Save the configuration and inform the constituent classes */ - ret = CLASS_SETUP(priv->dev1, dev, ctrl, dataout, outlen); - dispatched = true; - - if (ret >= 0) + for (i = 0; i < priv->ndevices; i++) { - ret = CLASS_SETUP(priv->dev2, dev, ctrl, dataout, outlen); - if (ret >= 0) - { - priv->config = value; - } + ret = CLASS_SETUP(priv->device[i].dev, dev, ctrl, dataout, outlen); } + + dispatched = true; + priv->config = value; } } break; @@ -593,10 +593,9 @@ static int composite_setup(FAR struct usbdevclass_driver_s *driver, } } - - /* Respond to the setup command if (1) data was returned, and (2) the request was - * NOT successfully dispatched to the component class driver. On an error return - * value (ret < 0), the USB driver will stall EP0. + /* Respond to the setup command if (1) data was returned, and (2) the + * request was NOT successfully dispatched to the component class driver. + * On an error return value (ret < 0), the USB driver will stall EP0. */ if (ret >= 0 && !dispatched) @@ -635,6 +634,7 @@ static void composite_disconnect(FAR struct usbdevclass_driver_s *driver, { FAR struct composite_dev_s *priv; irqstate_t flags; + int i; usbtrace(TRACE_CLASSDISCONNECT, 0); @@ -664,8 +664,12 @@ static void composite_disconnect(FAR struct usbdevclass_driver_s *driver, flags = enter_critical_section(); priv->config = COMPOSITE_CONFIGIDNONE; - CLASS_DISCONNECT(priv->dev1, dev); - CLASS_DISCONNECT(priv->dev2, dev); + + for (i = 0; i < priv->ndevices; i++) + { + CLASS_DISCONNECT(priv->device[i].dev, dev); + } + leave_critical_section(flags); /* Perform the soft connect function so that we will we can be @@ -688,6 +692,7 @@ static void composite_suspend(FAR struct usbdevclass_driver_s *driver, { FAR struct composite_dev_s *priv; irqstate_t flags; + int i; usbtrace(TRACE_CLASSSUSPEND, 0); @@ -714,8 +719,12 @@ static void composite_suspend(FAR struct usbdevclass_driver_s *driver, /* Forward the suspend event to the constituent devices */ flags = enter_critical_section(); - CLASS_SUSPEND(priv->dev1, priv->usbdev); - CLASS_SUSPEND(priv->dev2, priv->usbdev); + + for (i = 0; i < priv->ndevices; i++) + { + CLASS_SUSPEND(priv->device[i].dev, priv->usbdev); + } + leave_critical_section(flags); } @@ -732,6 +741,7 @@ static void composite_resume(FAR struct usbdevclass_driver_s *driver, { FAR struct composite_dev_s *priv = NULL; irqstate_t flags; + int i; #ifdef CONFIG_DEBUG_FEATURES if (!dev) @@ -756,8 +766,12 @@ static void composite_resume(FAR struct usbdevclass_driver_s *driver, /* Forward the resume event to the constituent devices */ flags = enter_critical_section(); - CLASS_RESUME(priv->dev1, priv->usbdev); - CLASS_RESUME(priv->dev2, priv->usbdev); + + for (i = 0; i < priv->ndevices; i++) + { + CLASS_RESUME(priv->device[i].dev, priv->usbdev); + } + leave_critical_section(flags); } @@ -770,8 +784,7 @@ static void composite_resume(FAR struct usbdevclass_driver_s *driver, * Description: * Register USB composite device as configured. This function will call * board-specific implementations in order to obtain the class objects for - * each of the members of the composite (see board_mscclassobject(), - * board_cdcclassobjec(), ...) + * each of the members of the composite. * * Input Parameter: * None @@ -786,16 +799,22 @@ static void composite_resume(FAR struct usbdevclass_driver_s *driver, * ****************************************************************************/ -FAR void *composite_initialize(void) +FAR void *composite_initialize(uint8_t ndevices, + FAR struct composite_devdesc_s *pdevices) { FAR struct composite_alloc_s *alloc; FAR struct composite_dev_s *priv; FAR struct composite_driver_s *drvr; int ret; + int i; + + DEBUGASSERT(pdevices != NULL && ndevices <= NUM_DEVICES_TO_HANDLE); /* Allocate the structures needed */ - alloc = (FAR struct composite_alloc_s *)kmm_malloc(sizeof(struct composite_alloc_s)); + alloc = (FAR struct composite_alloc_s *) + kmm_malloc(sizeof(struct composite_alloc_s)); + if (!alloc) { usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_ALLOCDEVSTRUCT), 0); @@ -811,21 +830,32 @@ FAR void *composite_initialize(void) memset(priv, 0, sizeof(struct composite_dev_s)); - /* Get the constitueat class driver objects */ + priv->cfgdescsize = USB_SIZEOF_CFGDESC; + priv->ninterfaces = 0; - ret = DEV1_CLASSOBJECT(&priv->dev1); - if (ret < 0) + /* Get the constituent class driver objects */ + + for (i = 0; i < ndevices; i++) { - usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_CLASSOBJECT), (uint16_t)-ret); - goto errout_with_alloc; + memcpy(&priv->device[i].compdesc, &pdevices[i], + sizeof(struct composite_devdesc_s)); + + ret = + priv->device[i].compdesc.classobject(priv->device[i].compdesc.minor, + &priv->device[i].compdesc.devdesc, + &priv->device[i].dev); + if (ret < 0) + { + usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_CLASSOBJECT), + (uint16_t)-ret); + goto errout_with_alloc; + } + + priv->cfgdescsize += priv->device[i].compdesc.cfgdescsize; + priv->ninterfaces += priv->device[i].compdesc.devdesc.ninterfaces; } - ret = DEV2_CLASSOBJECT(&priv->dev2); - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_CLASSOBJECT), (uint16_t)-ret); - goto errout_with_alloc; - } + priv->ndevices = ndevices; /* Initialize the USB class driver structure */ @@ -840,9 +870,10 @@ FAR void *composite_initialize(void) /* Register the USB composite class driver */ ret = usbdev_register(&drvr->drvr); - if (ret) + if (ret < 0) { - usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_DEVREGISTER), (uint16_t)-ret); + usbtrace(TRACE_CLSERROR(USBCOMPOSITE_TRACEERR_DEVREGISTER), + (uint16_t)-ret); goto errout_with_alloc; } @@ -860,8 +891,7 @@ errout_with_alloc: * Un-initialize the USB composite driver. The handle is the USB composite * class' device object as was returned by composite_initialize(). This * function will call board-specific implementations in order to free the - * class objects for each of the members of the composite (see - * board_mscuninitialize(), board_cdcuninitialize(), ...) + * class objects for each of the members of the composite. * * Input Parameters: * handle - The handle returned by a previous call to composite_initialize(). @@ -875,6 +905,7 @@ void composite_uninitialize(FAR void *handle) { FAR struct composite_alloc_s *alloc = (FAR struct composite_alloc_s *)handle; FAR struct composite_dev_s *priv; + int i; DEBUGASSERT(alloc != NULL); @@ -882,8 +913,10 @@ void composite_uninitialize(FAR void *handle) priv = &alloc->dev; - DEV1_UNINITIALIZE(priv->dev1); - DEV2_UNINITIALIZE(priv->dev2); + for (i = 0; i < priv->ndevices; i++) + { + priv->device[i].compdesc.uninitialize(priv->device[i].dev); + } /* Then unregister and destroy the composite class */ @@ -894,8 +927,10 @@ void composite_uninitialize(FAR void *handle) /* Second phase uninitialization: Clean up all memory resources */ - DEV1_UNINITIALIZE(priv->dev1); - DEV2_UNINITIALIZE(priv->dev2); + for (i = 0; i < priv->ndevices; i++) + { + priv->device[i].compdesc.uninitialize(priv->device[i].dev); + } /* Then free the composite driver state structure itself */ diff --git a/drivers/usbdev/composite.h b/drivers/usbdev/composite.h index f1adb4337c1..7bf30bc1415 100644 --- a/drivers/usbdev/composite.h +++ b/drivers/usbdev/composite.h @@ -1,7 +1,7 @@ /**************************************************************************** * drivers/usbdev/composite.h * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2011-2012, 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 #ifdef CONFIG_USBDEV_COMPOSITE @@ -62,6 +63,7 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ + /* Configuration ************************************************************/ /* Packet sizes */ @@ -106,136 +108,21 @@ #ifdef CONFIG_USBDEV_SELFPOWERED # define COMPOSITE_SELFPOWERED USB_CONFIG_ATTR_SELFPOWER #else -# define COMPOSITE_SELFPOWERED (0) +# define COMPOSITE_SELFPOWERED (0) #endif #ifdef CONFIG_USBDEV_REMOTEWAKEUP # define COMPOSITE_REMOTEWAKEUP USB_CONFIG_ATTR_WAKEUP #else -# define COMPOSITE_REMOTEWAKEUP (0) +# define COMPOSITE_REMOTEWAKEUP (0) #endif -/* Constituent devices ******************************************************/ - -#undef DEV1_IS_CDCACM -#undef DEV1_IS_USBMSC - -#undef DEV2_IS_CDCACM -#undef DEV2_IS_USBMSC - -/* Pick the first device in the composite. At present, this may only be - * the CDC serial device or the mass storage device. - */ - -#if defined(CONFIG_CDCACM_COMPOSITE) -# define DEV1_IS_CDCACM 1 -# define DEV1_MKCFGDESC cdcacm_mkcfgdesc -# define DEV1_MKSTRDESC cdcacm_mkstrdesc -# define DEV1_CLASSOBJECT board_cdcclassobject -# define DEV1_UNINITIALIZE board_cdcuninitialize -# define DEV1_NCONFIGS CDCACM_NCONFIGS -# define DEV1_CONFIGID CDCACM_CONFIGID -# define DEV1_FIRSTINTERFACE CONFIG_CDCACM_IFNOBASE -# define DEV1_NINTERFACES CDCACM_NINTERFACES -# define DEV1_STRIDBASE CONFIG_CDCACM_STRBASE -# define DEV1_NSTRIDS CDCACM_NSTRIDS -# define DEV1_CFGDESCSIZE SIZEOF_CDCACM_CFGDESC -#elif defined(CONFIG_USBMSC_COMPOSITE) -# define DEV1_IS_USBMSC 1 -# define DEV1_MKCFGDESC usbmsc_mkcfgdesc -# define DEV1_MKSTRDESC usbmsc_mkstrdesc -# define DEV1_CLASSOBJECT board_mscclassobject -# define DEV1_UNINITIALIZE board_mscuninitialize -# define DEV1_NCONFIGS USBMSC_NCONFIGS -# define DEV1_CONFIGID USBMSC_CONFIGID -# define DEV1_FIRSTINTERFACE CONFIG_USBMSC_IFNOBASE -# define DEV1_NINTERFACES USBMSC_NINTERFACES -# define DEV1_STRIDBASE CONFIG_USBMSC_IFNOBASE -# define DEV1_NSTRIDS USBMSC_NSTRIDS -# define DEV1_CFGDESCSIZE SIZEOF_USBMSC_CFGDESC -#else -# error "No members of the composite defined" -#endif - -/* Pick the second device in the composite. At present, this may only be - * the CDC serial device or the mass storage device. - */ - -#if defined(CONFIG_CDCACM_COMPOSITE) && !defined(DEV1_IS_CDCACM) -# define DEV2_IS_CDCACM 1 -# define DEV2_MKCFGDESC cdcacm_mkcfgdesc -# define DEV2_MKSTRDESC cdcacm_mkstrdesc -# define DEV2_CLASSOBJECT board_cdcclassobject -# define DEV2_UNINITIALIZE board_cdcuninitialize -# define DEV2_NCONFIGS CDCACM_NCONFIGS -# define DEV2_CONFIGID CDCACM_CONFIGID -# define DEV2_FIRSTINTERFACE CONFIG_CDCACM_IFNOBASE -# define DEV2_NINTERFACES CDCACM_NINTERFACES -# define DEV2_STRIDBASE CONFIG_CDCACM_STRBASE -# define DEV2_NSTRIDS CDCACM_NSTRIDS -# define DEV2_CFGDESCSIZE SIZEOF_CDCACM_CFGDESC -#elif defined(CONFIG_USBMSC_COMPOSITE) && !defined(DEV1_IS_USBMSC) -# define DEV2_IS_USBMSC 1 -# define DEV2_MKCFGDESC usbmsc_mkcfgdesc -# define DEV2_MKSTRDESC usbmsc_mkstrdesc -# define DEV2_UNINITIALIZE board_mscuninitialize -# define DEV2_CLASSOBJECT board_mscclassobject -# define DEV2_NCONFIGS USBMSC_NCONFIGS -# define DEV2_CONFIGID USBMSC_CONFIGID -# define DEV2_FIRSTINTERFACE CONFIG_USBMSC_IFNOBASE -# define DEV2_NINTERFACES USBMSC_NINTERFACES -# define DEV2_STRIDBASE CONFIG_USBMSC_STRBASE -# define DEV2_NSTRIDS USBMSC_NSTRIDS -# define DEV2_CFGDESCSIZE SIZEOF_USBMSC_CFGDESC -#else -# error "Insufficient members of the composite defined" -#endif - -/* Verify interface configuration */ - -#if DEV1_FIRSTINTERFACE != 0 -# warning "The first interface number should be zero" -#endif - -#if (DEV1_FIRSTINTERFACE + DEV1_NINTERFACES) != DEV2_FIRSTINTERFACE -# warning "Interface numbers are not contiguous" -#endif - -/* Check if an IAD is needed */ - -#ifdef CONFIG_COMPOSITE_IAD -# if DEV1_NINTERFACES == 1 && DEV2_NINTERFACES == 1 -# warning "CONFIG_COMPOSITE_IAD not needed" -# endif -#endif - -#if !defined(CONFIG_COMPOSITE_IAD) && DEV1_NINTERFACES > 1 && DEV2_NINTERFACES > 1 -# warning "CONFIG_COMPOSITE_IAD may be needed" -#endif - -/* Total size of the configuration descriptor: */ - -#define COMPOSITE_CFGDESCSIZE (USB_SIZEOF_CFGDESC + DEV1_CFGDESCSIZE + DEV2_CFGDESCSIZE) - -/* The total number of interfaces */ - -#define COMPOSITE_NINTERFACES (DEV1_NINTERFACES + DEV2_NINTERFACES) - -/* Composite configuration ID value */ - -#if DEV1_NCONFIGS != 1 || DEV1_CONFIGID != 1 -# error "DEV1: Only a single configuration is supported" -#endif - -#if DEV2_NCONFIGS != 1 || DEV2_CONFIGID != 1 -# error "DEV2: Only a single configuration is supported" -#endif +#define NUM_DEVICES_TO_HANDLE (4) /* Descriptors **************************************************************/ /* These settings are not modifiable via the NuttX configuration */ #define COMPOSITE_CONFIGIDNONE (0) /* Config ID = 0 means to return to address mode */ -#define COMPOSITE_NCONFIGS (1) /* The number of configurations supported */ #define COMPOSITE_CONFIGID (1) /* The only supported configuration ID */ /* String language */ @@ -248,17 +135,6 @@ #define COMPOSITE_PRODUCTSTRID (2) #define COMPOSITE_SERIALSTRID (3) #define COMPOSITE_CONFIGSTRID (4) -#define COMPOSITE_NSTRIDS (4) - -/* Verify string configuration */ - -#if COMPOSITE_NSTRIDS != DEV1_STRIDBASE -# warning "The DEV1 string base should be COMPOSITE_NSTRIDS" -#endif - -#if (DEV1_STRIDBASE + DEV1_NSTRIDS) != DEV2_STRIDBASE -# warning "String IDs are not contiguous" -#endif /* Everpresent MIN/MAX macros ***********************************************/ @@ -274,6 +150,33 @@ * Public Types ****************************************************************************/ +struct composite_devobj_s +{ + /* Device description given by the user code in the dynamic + * configuration. + */ + + struct composite_devdesc_s compdesc; + + /* Pointer to device class */ + + FAR struct usbdevclass_driver_s *dev; +}; + +/* This structure describes the internal state of the driver */ + +struct composite_dev_s +{ + FAR struct usbdev_s *usbdev; /* usbdev driver pointer */ + uint8_t config; /* Configuration number */ + FAR struct usbdev_req_s *ctrlreq; /* Allocated control request */ + uint8_t ndevices; /* Num devices in this composite device */ + int cfgdescsize; /* Total size of the configuration descriptor: */ + int ninterfaces; /* The total number of interfaces in this composite device */ + + struct composite_devobj_s device[NUM_DEVICES_TO_HANDLE]; /* Device class object */ +}; + /**************************************************************************** * Public Data ****************************************************************************/ @@ -317,9 +220,11 @@ FAR const struct usb_devdesc_s *composite_getdevdesc(void); ****************************************************************************/ #ifdef CONFIG_USBDEV_DUALSPEED -int16_t composite_mkcfgdesc(uint8_t *buf, uint8_t speed, uint8_t type); +int16_t composite_mkcfgdesc(FAR struct composite_dev_s *priv, + FAR uint8_t *buf, uint8_t speed, uint8_t type); #else -int16_t composite_mkcfgdesc(uint8_t *buf); +int16_t composite_mkcfgdesc(FAR struct composite_dev_s *priv, + FAR uint8_t *buf); #endif /**************************************************************************** diff --git a/drivers/usbdev/composite_desc.c b/drivers/usbdev/composite_desc.c index 2cc94e07f10..3a86099fd93 100644 --- a/drivers/usbdev/composite_desc.c +++ b/drivers/usbdev/composite_desc.c @@ -1,7 +1,7 @@ /**************************************************************************** * drivers/usbdev/composite_desc.c * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2011-2012, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -61,12 +61,6 @@ * Private Types ****************************************************************************/ -#ifdef CONFIG_USBDEV_DUALSPEED -typedef int16_t (*mkcfgdesc)(FAR uint8_t *buf, uint8_t speed, uint8_t type); -#else -typedef int16_t (*mkcfgdesc)(FAR uint8_t *buf); -#endif - /**************************************************************************** * Private Function Prototypes ****************************************************************************/ @@ -74,6 +68,7 @@ typedef int16_t (*mkcfgdesc)(FAR uint8_t *buf); /**************************************************************************** * Private Data ****************************************************************************/ + /* Device Descriptor */ static const struct usb_devdesc_s g_devdesc = @@ -84,7 +79,7 @@ static const struct usb_devdesc_s g_devdesc = LSBYTE(0x0200), MSBYTE(0x0200) }, -#ifdef CONFIG_COMPOSITE_IAD +#ifndef CONFIG_COMPOSITE_IAD USB_CLASS_MISC, /* classid */ 2, /* subclass */ 1, /* protocol */ @@ -112,25 +107,6 @@ static const struct usb_devdesc_s g_devdesc = COMPOSITE_NCONFIGS /* nconfigs */ }; -/* Configuration descriptor for the composite device */ - -static const struct usb_cfgdesc_s g_cfgdesc = -{ - USB_SIZEOF_CFGDESC, /* len */ - USB_DESC_TYPE_CONFIG, /* type */ - { - LSBYTE(COMPOSITE_CFGDESCSIZE), /* LS totallen */ - MSBYTE(COMPOSITE_CFGDESCSIZE) /* MS totallen */ - }, - COMPOSITE_NINTERFACES, /* ninterfaces */ - COMPOSITE_CONFIGID, /* cfgvalue */ - COMPOSITE_CONFIGSTRID, /* icfg */ - USB_CONFIG_ATTR_ONE | /* attr */ - COMPOSITE_SELFPOWERED | - COMPOSITE_REMOTEWAKEUP, - (CONFIG_USBDEV_MAXPOWER + 1) / 2 /* mxpower */ -}; - #ifdef CONFIG_USBDEV_DUALSPEED static const struct usb_qualdesc_s g_qualdesc = { @@ -243,35 +219,55 @@ FAR const struct usb_devdesc_s *composite_getdevdesc(void) ****************************************************************************/ #ifdef CONFIG_USBDEV_DUALSPEED -int16_t composite_mkcfgdesc(uint8_t *buf, uint8_t speed, uint8_t type) +int16_t composite_mkcfgdesc(FAR struct composite_dev_s *priv, FAR uint8_t *buf, + uint8_t speed, uint8_t type) #else -int16_t composite_mkcfgdesc(uint8_t *buf) +int16_t composite_mkcfgdesc(FAR struct composite_dev_s *priv, FAR uint8_t *buf) #endif { + FAR struct usb_cfgdesc_s *cfgdesc = (FAR struct usb_cfgdesc_s *)buf; int16_t len; int16_t total; + int i; - /* Configuration descriptor -- Copy the canned configuration descriptor. */ + /* Configuration descriptor for the composite device */ + /* Fill in the values directly into the buf */ + + cfgdesc->len = USB_SIZEOF_CFGDESC; /* Descriptor length */ + cfgdesc->type = USB_DESC_TYPE_CONFIG; /* Descriptor type */ + cfgdesc->totallen[0] = LSBYTE(priv->cfgdescsize); /* Lower Byte of Total length */ + cfgdesc->totallen[1] = MSBYTE(priv->cfgdescsize); /* High Byte of Total length */ + cfgdesc->ninterfaces = priv->ninterfaces; /* Number of interfaces */ + cfgdesc->cfgvalue = COMPOSITE_CONFIGID; /* Configuration value */ + cfgdesc->icfg = COMPOSITE_CONFIGSTRID; /* Configuration */ + cfgdesc->attr = USB_CONFIG_ATTR_ONE | /* Attributes */ + COMPOSITE_SELFPOWERED | + COMPOSITE_REMOTEWAKEUP; + cfgdesc->mxpower = (CONFIG_USBDEV_MAXPOWER + 1) / 2; /* Max power (mA/2) */ + + /* increment the size and buf to point right behind the information filled in */ - memcpy(buf, &g_cfgdesc, USB_SIZEOF_CFGDESC); total = USB_SIZEOF_CFGDESC; - buf += USB_SIZEOF_CFGDESC; + buf += USB_SIZEOF_CFGDESC; - /* Copy DEV1/DEV2 interface descriptors */ + /* Copy all contained interface descriptors into the buffer too */ + for (i = 0; i < priv->ndevices; i++) + { #ifdef CONFIG_USBDEV_DUALSPEED - len = DEV1_MKCFGDESC(buf, speed, type); - total += len; - buf += len; - total += DEV2_MKCFGDESC(buf, speed, type); + len = priv->device[i].compdesc.mkconfdesc(buf, + &priv->device[i].compdesc.devdesc, + speed, type); + total += len; + buf += len; #else - len = DEV1_MKCFGDESC(buf); - total += len; - buf += len; - total += DEV2_MKCFGDESC(buf); + len = priv->device[i].compdesc.mkconfdesc(buf, + &priv->device[i].compdesc.devdesc); + total += len; + buf += len; #endif + } - DEBUGASSERT(total == COMPOSITE_CFGDESCSIZE); return total; } diff --git a/drivers/usbdev/usbmsc.c b/drivers/usbdev/usbmsc.c index f7e1e58a4c3..aecd1d3d5f7 100644 --- a/drivers/usbdev/usbmsc.c +++ b/drivers/usbdev/usbmsc.c @@ -1,7 +1,7 @@ /**************************************************************************** * drivers/usbdev/usbmsc.c * - * Copyright (C) 2008-2012, 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2008-2012, 2016-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Mass storage class device. Bulk-only with SCSI subclass. @@ -246,6 +246,7 @@ static void usbmsc_freereq(FAR struct usbdev_ep_s *ep, struct usbdev_req_s *req) /**************************************************************************** * Class Driver Interfaces ****************************************************************************/ + /**************************************************************************** * Name: usbmsc_bind * @@ -267,7 +268,7 @@ static int usbmsc_bind(FAR struct usbdevclass_driver_s *driver, /* Bind the structures */ - priv->usbdev = dev; + priv->usbdev = dev; /* Save the reference to our private data structure in EP0 so that it * can be recovered in ep0 completion events (Unless we are part of @@ -307,7 +308,8 @@ static int usbmsc_bind(FAR struct usbdevclass_driver_s *driver, /* Pre-allocate the IN bulk endpoint */ - priv->epbulkin = DEV_ALLOCEP(dev, USBMSC_EPINBULK_ADDR, true, USB_EP_ATTR_XFER_BULK); + priv->epbulkin = DEV_ALLOCEP(dev, USBMSC_MKEPBULKIN(&priv->devdesc), + true, USB_EP_ATTR_XFER_BULK); if (!priv->epbulkin) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EPBULKINALLOCFAIL), 0); @@ -319,7 +321,8 @@ static int usbmsc_bind(FAR struct usbdevclass_driver_s *driver, /* Pre-allocate the OUT bulk endpoint */ - priv->epbulkout = DEV_ALLOCEP(dev, USBMSC_EPOUTBULK_ADDR, false, USB_EP_ATTR_XFER_BULK); + priv->epbulkout = DEV_ALLOCEP(dev, USBMSC_MKEPBULKOUT(&priv->devdesc), + false, USB_EP_ATTR_XFER_BULK); if (!priv->epbulkout) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EPBULKOUTALLOCFAIL), 0); @@ -334,7 +337,8 @@ static int usbmsc_bind(FAR struct usbdevclass_driver_s *driver, for (i = 0; i < CONFIG_USBMSC_NRDREQS; i++) { reqcontainer = &priv->rdreqs[i]; - reqcontainer->req = usbmsc_allocreq(priv->epbulkout, CONFIG_USBMSC_BULKOUTREQLEN); + reqcontainer->req = usbmsc_allocreq(priv->epbulkout, + CONFIG_USBMSC_BULKOUTREQLEN); if (reqcontainer->req == NULL) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_RDALLOCREQ), @@ -342,6 +346,7 @@ static int usbmsc_bind(FAR struct usbdevclass_driver_s *driver, ret = -ENOMEM; goto errout; } + reqcontainer->req->priv = reqcontainer; reqcontainer->req->callback = usbmsc_rdcomplete; } @@ -351,7 +356,8 @@ static int usbmsc_bind(FAR struct usbdevclass_driver_s *driver, for (i = 0; i < CONFIG_USBMSC_NWRREQS; i++) { reqcontainer = &priv->wrreqs[i]; - reqcontainer->req = usbmsc_allocreq(priv->epbulkin, CONFIG_USBMSC_BULKINREQLEN); + reqcontainer->req = usbmsc_allocreq(priv->epbulkin, + CONFIG_USBMSC_BULKINREQLEN); if (reqcontainer->req == NULL) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_WRALLOCREQ), @@ -359,6 +365,7 @@ static int usbmsc_bind(FAR struct usbdevclass_driver_s *driver, ret = -ENOMEM; goto errout; } + reqcontainer->req->priv = reqcontainer; reqcontainer->req->callback = usbmsc_wrcomplete; @@ -482,7 +489,9 @@ static void usbmsc_unbind(FAR struct usbdevclass_driver_s *driver, flags = enter_critical_section(); while (!sq_empty(&priv->wrreqlist)) { - reqcontainer = (struct usbmsc_req_s *)sq_remfirst(&priv->wrreqlist); + reqcontainer = (struct usbmsc_req_s *) + sq_remfirst(&priv->wrreqlist); + if (reqcontainer->req != NULL) { usbmsc_freereq(priv->epbulkin, reqcontainer->req); @@ -569,9 +578,9 @@ static int usbmsc_setup(FAR struct usbdevclass_driver_s *driver, switch (ctrl->value[1]) { - /* If the mass storage device is used in as part of a composite - * device, then the device descriptor is is provided by logic - * in the composite device implementation. + /* If the mass storage device is used in as part of a + * composite device, then the device descriptor is is + * provided by logic in the composite device implementation. */ #ifndef CONFIG_USBMSC_COMPOSITE @@ -583,9 +592,9 @@ static int usbmsc_setup(FAR struct usbdevclass_driver_s *driver, break; #endif - /* If the mass storage device is used in as part of a composite device, - * then the device qualifier descriptor is provided by logic in the - * composite device implementation. + /* If the mass storage device is used in as part of a + * composite device, then the device qualifier descriptor is + * provided by logic in the composite device implementation. */ #if !defined(CONFIG_USBMSC_COMPOSITE) && defined(CONFIG_USBDEV_DUALSPEED) @@ -608,7 +617,8 @@ static int usbmsc_setup(FAR struct usbdevclass_driver_s *driver, case USB_DESC_TYPE_CONFIG: { #ifdef CONFIG_USBDEV_DUALSPEED - ret = usbmsc_mkcfgdesc(ctrlreq->buf, dev->speed, ctrl->value[1]); + ret = usbmsc_mkcfgdesc(ctrlreq->buf, dev->speed, + ctrl->value[1]); #else ret = usbmsc_mkcfgdesc(ctrlreq->buf); #endif @@ -616,9 +626,9 @@ static int usbmsc_setup(FAR struct usbdevclass_driver_s *driver, break; #endif - /* If the mass storage device is used in as part of a composite device, - * then the language string descriptor is provided by logic in the - * composite device implementation. + /* If the mass storage device is used in as part of a + * composite device, then the language string descriptor is + * provided by logic in the composite device implementation. */ #ifndef CONFIG_USBMSC_COMPOSITE @@ -626,7 +636,8 @@ static int usbmsc_setup(FAR struct usbdevclass_driver_s *driver, { /* index == language code. */ - ret = usbmsc_mkstrdesc(ctrl->value[0], (struct usb_strdesc_s *)ctrlreq->buf); + ret = usbmsc_mkstrdesc(ctrl->value[0], + (struct usb_strdesc_s *)ctrlreq->buf); } break; #endif @@ -644,7 +655,9 @@ static int usbmsc_setup(FAR struct usbdevclass_driver_s *driver, { if (ctrl->type == 0) { - /* Signal the worker thread to instantiate the new configuration */ + /* Signal the worker thread to instantiate the new + * configuration. + */ priv->theventset |= USBMSC_EVENT_CFGCHANGE; priv->thvalue = value; @@ -659,9 +672,9 @@ static int usbmsc_setup(FAR struct usbdevclass_driver_s *driver, } break; - /* If the mass storage device is used in as part of a composite device, - * then the overall composite class configuration is managed by logic - * in the composite device implementation. + /* If the mass storage device is used in as part of a composite + * device, then the overall composite class configuration is + * managed by logic in the composite device implementation. */ #ifndef CONFIG_USBMSC_COMPOSITE @@ -689,8 +702,8 @@ static int usbmsc_setup(FAR struct usbdevclass_driver_s *driver, priv->theventset |= USBMSC_EVENT_IFCHANGE; usbmsc_scsi_signal(priv); - /* Return here... the response will be provided later by the - * worker thread. + /* Return here... the response will be provided later by + * the worker thread. */ return OK; @@ -751,13 +764,15 @@ static int usbmsc_setup(FAR struct usbdevclass_driver_s *driver, } else { - /* Signal to stop the current operation and reinitialize state */ + /* Signal to stop the current operation and reinitialize + * state. + */ priv->theventset |= USBMSC_EVENT_RESET; usbmsc_scsi_signal(priv); - /* Return here... the response will be provided later by the - * worker thread. + /* Return here... the response will be provided later by + * the worker thread. */ return OK; @@ -891,6 +906,7 @@ static void usbmsc_disconnect(FAR struct usbdevclass_driver_s *driver, /**************************************************************************** * Initialization/Un-Initialization ****************************************************************************/ + /**************************************************************************** * Name: usbmsc_lununinitialize ****************************************************************************/ @@ -912,6 +928,7 @@ static void usbmsc_lununinitialize(struct usbmsc_lun_s *lun) /**************************************************************************** * Public Functions ****************************************************************************/ + /**************************************************************************** * Internal Interfaces ****************************************************************************/ @@ -929,10 +946,8 @@ int usbmsc_setconfig(FAR struct usbmsc_dev_s *priv, uint8_t config) { FAR struct usbmsc_req_s *privreq; FAR struct usbdev_req_s *req; -#ifdef CONFIG_USBDEV_DUALSPEED - FAR const struct usb_epdesc_s *epdesc; - bool hispeed = (priv->usbdev->speed == USB_SPEED_HIGH); -#endif + struct usb_epdesc_s epdesc; + bool hispeed = false; int i; int ret = 0; @@ -952,6 +967,10 @@ int usbmsc_setconfig(FAR struct usbmsc_dev_s *priv, uint8_t config) return OK; } +#ifdef CONFIG_USBDEV_DUALSPEED + hispeed = (priv->usbdev->speed == USB_SPEED_HIGH); +#endif + /* Discard the previous configuration data */ usbmsc_resetconfig(priv); @@ -974,13 +993,9 @@ int usbmsc_setconfig(FAR struct usbmsc_dev_s *priv, uint8_t config) /* Configure the IN bulk endpoint */ -#ifdef CONFIG_USBDEV_DUALSPEED - epdesc = USBMSC_EPBULKINDESC(hispeed); - ret = EP_CONFIGURE(priv->epbulkin, epdesc, false); -#else - ret = EP_CONFIGURE(priv->epbulkin, - usbmsc_getepdesc(USBMSC_EPFSBULKIN), false); -#endif + usbmsc_copy_epdesc(USBMSC_EPBULKIN, &epdesc, &priv->devdesc, + hispeed); + ret = EP_CONFIGURE(priv->epbulkin, &epdesc, false); if (ret < 0) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EPBULKINCONFIGFAIL), 0); @@ -991,13 +1006,9 @@ int usbmsc_setconfig(FAR struct usbmsc_dev_s *priv, uint8_t config) /* Configure the OUT bulk endpoint */ -#ifdef CONFIG_USBDEV_DUALSPEED - epdesc = USBMSC_EPBULKOUTDESC(hispeed); - ret = EP_CONFIGURE(priv->epbulkout, epdesc, true); -#else - ret = EP_CONFIGURE(priv->epbulkout, - usbmsc_getepdesc(USBMSC_EPFSBULKOUT), true); -#endif + usbmsc_copy_epdesc(USBMSC_EPBULKOUT, &epdesc, &priv->devdesc, + hispeed); + ret = EP_CONFIGURE(priv->epbulkout, &epdesc, true); if (ret < 0) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EPBULKOUTCONFIGFAIL), 0); @@ -1015,10 +1026,12 @@ int usbmsc_setconfig(FAR struct usbmsc_dev_s *priv, uint8_t config) req->len = CONFIG_USBMSC_BULKOUTREQLEN; req->priv = privreq; req->callback = usbmsc_rdcomplete; + ret = EP_SUBMIT(priv->epbulkout, req); if (ret < 0) { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_RDSUBMIT), (uint16_t)-ret); + usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_RDSUBMIT), + (uint16_t)-ret); goto errout; } } @@ -1067,7 +1080,8 @@ void usbmsc_resetconfig(FAR struct usbmsc_dev_s *priv) * ****************************************************************************/ -void usbmsc_wrcomplete(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req) +void usbmsc_wrcomplete(FAR struct usbdev_ep_s *ep, + FAR struct usbdev_req_s *req) { FAR struct usbmsc_dev_s *priv; FAR struct usbmsc_req_s *privreq; @@ -1127,7 +1141,8 @@ void usbmsc_wrcomplete(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req) * ****************************************************************************/ -void usbmsc_rdcomplete(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req) +void usbmsc_rdcomplete(FAR struct usbdev_ep_s *ep, + FAR struct usbdev_req_s *req) { FAR struct usbmsc_dev_s *priv; FAR struct usbmsc_req_s *privreq; @@ -1290,6 +1305,7 @@ static inline void usbmsc_sync_wait(FAR struct usbmsc_dev_s *priv) /**************************************************************************** * User Interfaces ****************************************************************************/ + /**************************************************************************** * Name: usbmsc_configure * @@ -1494,10 +1510,10 @@ int usbmsc_bindlun(FAR void *handle, FAR const char *drvrpath, memset(lun, 0, sizeof(struct usbmsc_lun_s)); - /* Allocate an I/O buffer big enough to hold one hardware sector. SCSI commands - * are processed one at a time so all LUNs may share a single I/O buffer. The - * I/O buffer will be allocated so that is it as large as the largest block - * device sector size + /* Allocate an I/O buffer big enough to hold one hardware sector. SCSI + * commands are processed one at a time so all LUNs may share a single I/O + * buffer. The I/O buffer will be allocated so that is it as large as the + * largest block device sector size */ if (!priv->iobuffer) @@ -1513,8 +1529,9 @@ int usbmsc_bindlun(FAR void *handle, FAR const char *drvrpath, } else if (priv->iosize < geo.geo_sectorsize) { - void *tmp; - tmp = (FAR uint8_t *)kmm_realloc(priv->iobuffer, geo.geo_sectorsize); + FAR void *tmp; + + tmp = (FAR void *)kmm_realloc(priv->iobuffer, geo.geo_sectorsize); if (!tmp) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_REALLOCIOBUFFER), geo.geo_sectorsize); @@ -1669,7 +1686,8 @@ int usbmsc_exportluns(FAR void *handle) usbmsc_scsi_main, NULL); if (priv->thpid <= 0) { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_THREADCREATE), (uint16_t)errno); + usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_THREADCREATE), + (uint16_t)errno); goto errout_with_lock; } @@ -1720,12 +1738,17 @@ errout_with_lock: #ifdef CONFIG_USBMSC_COMPOSITE int usbmsc_classobject(FAR void *handle, + FAR struct usbdev_description_s *devdesc, FAR struct usbdevclass_driver_s **classdev) { FAR struct usbmsc_alloc_s *alloc = (FAR struct usbmsc_alloc_s *)handle; int ret; - DEBUGASSERT(handle && classdev); + DEBUGASSERT(handle != NULL && classdev != NULL); + + /* Save the device description */ + + memcpy(&alloc->dev.devdesc, devdesc, sizeof(struct usbdev_description_s)); /* Export the LUNs as with the "standalone" USB mass storage driver, but * don't register the class instance with the USB device infrastructure. @@ -1762,9 +1785,6 @@ void usbmsc_uninitialize(FAR void *handle) FAR struct usbmsc_alloc_s *alloc = (FAR struct usbmsc_alloc_s *)handle; FAR struct usbmsc_dev_s *priv; irqstate_t flags; -#if 0 - void *value; -#endif int i; #ifdef CONFIG_DEBUG_FEATURES @@ -1860,3 +1880,61 @@ void usbmsc_uninitialize(FAR void *handle) kmm_free(priv); #endif } + +/**************************************************************************** + * Name: usbmsc_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_USBMSC_COMPOSITE) +void usbmsc_get_composite_devdesc(FAR struct composite_devdesc_s *dev) +{ + memset(dev, 0, sizeof(struct composite_devdesc_s)); + + /* The callback functions for the CDC/ACM class. + * + * classobject() and uninitializ() must be provided by board-specific + * logic + */ + + dev->mkconfdesc = usbmsc_mkcfgdesc; + dev->mkstrdesc = usbmsc_mkstrdesc; + + dev->nconfigs = USBMSC_NCONFIGS; /* Number of configurations supported */ + dev->configid = USBMSC_CONFIGID; /* The only supported configuration ID */ + dev->cfgdescsize = SIZEOF_USBMSC_CFGDESC; /* The size of the config descriptor */ + + /* Board-specific logic must provide the device minor */ + + /* Interfaces. + * + * ifnobase must be provided by board-specific logic + */ + + dev->devdesc.ninterfaces = USBMSC_NINTERFACES; /* Number of interfaces in the configuration */ + + /* Strings. + * + * strbase must be provided by board-specific logic + */ + + dev->devdesc.nstrings = USBMSC_NSTRIDS; /* Number of Strings */ + + /* Endpoints. + * + * Endpoint numbers must be provided by board-specific logic. + */ + + dev->devdesc.nendpoints = USBMSC_NENDPOINTS; +} +#endif \ No newline at end of file diff --git a/drivers/usbdev/usbmsc.h b/drivers/usbdev/usbmsc.h index 4fa8405248c..0b5b4f5876d 100644 --- a/drivers/usbdev/usbmsc.h +++ b/drivers/usbdev/usbmsc.h @@ -1,7 +1,7 @@ /**************************************************************************** * drivers/usbdev/usbmsc.h * - * Copyright (C) 2008-2013, 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2008-2013, 2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Mass storage class device. Bulk-only with SCSI subclass. @@ -57,6 +57,7 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ + /* Configuration ************************************************************/ /* If the USB mass storage device is configured as part of a composite device * then both CONFIG_USBDEV_COMPOSITE and CONFIG_USBMSC_COMPOSITE must be @@ -98,14 +99,18 @@ /* Logical endpoint numbers / max packet sizes */ -#ifndef CONFIG_USBMSC_EPBULKOUT -# warning "EPBULKOUT not defined in the configuration" -# define CONFIG_USBMSC_EPBULKOUT 2 +#ifndef CONFIG_USBMSC_COMPOSITE +# ifndef CONFIG_USBMSC_EPBULKOUT +# warning "EPBULKOUT not defined in the configuration" +# define CONFIG_USBMSC_EPBULKOUT 2 +# endif #endif -#ifndef CONFIG_USBMSC_EPBULKIN -# warning "EPBULKIN not defined in the configuration" -# define CONFIG_USBMSC_EPBULKIN 3 +#ifndef CONFIG_USBMSC_COMPOSITE +# ifndef CONFIG_USBMSC_EPBULKIN +# warning "EPBULKIN not defined in the configuration" +# define CONFIG_USBMSC_EPBULKIN 3 +# endif #endif /* Packet and request buffer sizes */ @@ -293,27 +298,19 @@ #define USBMSC_LASTSTRID USBMSC_INTERFACESTRID #define USBMSC_NSTRIDS (USBMSC_LASTSTRID - CONFIG_USBMSC_STRBASE) -#define USBMSC_NCONFIGS (1) /* Number of configurations supported */ - /* Configuration Descriptor */ -#define USBMSC_NINTERFACES (1) /* Number of interfaces in the configuration */ #define USBMSC_INTERFACEID (CONFIG_USBMSC_IFNOBASE+0) #define USBMSC_ALTINTERFACEID (0) #define USBMSC_CONFIGIDNONE (0) /* Config ID means to return to address mode */ -#define USBMSC_CONFIGID (1) /* The only supported configuration ID */ - -/* Interface description */ - -#define USBMSC_NENDPOINTS (2) /* Number of endpoints in the interface */ /* Endpoint configuration */ -#define USBMSC_EPOUTBULK_ADDR (CONFIG_USBMSC_EPBULKOUT) +#define USBMSC_MKEPBULKOUT(devDesc) ((devDesc)->epno[USBMSC_EP_BULKOUT_IDX]) #define USBMSC_EPOUTBULK_ATTR (USB_EP_ATTR_XFER_BULK) -#define USBMSC_EPINBULK_ADDR (USB_DIR_IN|CONFIG_USBMSC_EPBULKIN) +#define USBMSC_MKEPBULKIN(devDesc) (USB_DIR_IN | (devDesc)->epno[USBMSC_EP_BULKIN_IDX]) #define USBMSC_EPINBULK_ATTR (USB_EP_ATTR_XFER_BULK) #define USBMSC_HSBULKMAXPACKET (512) @@ -323,38 +320,10 @@ #define USBMSC_FSBULKMXPKTSHIFT (6) #define USBMSC_FSBULKMXPKTMASK (0x0000003f) -/* Macros for dual speed vs. full speed only operation */ - -#ifdef CONFIG_USBDEV_DUALSPEED -# define USBMSC_EPBULKINDESC(hs) \ - usbmsc_getepdesc((hs) ? USBMSC_EPHSBULKIN : USBMSC_EPFSBULKIN) -# define USBMSC_EPBULKOUTDESC(hs) \ - usbmsc_getepdesc((hs) ? USBMSC_EPHSBULKOUT : USBMSC_EPFSBULKOUT) -# define USBMSC_BULKMAXPACKET(hs) \ - ((hs) ? USBMSC_HSBULKMAXPACKET : USBMSC_FSBULKMAXPACKET) -# define USBMSC_BULKMXPKTSHIFT(d) \ - (((d)->speed==USB_SPEED_HIGH) ? USBMSC_HSBULKMXPKTSHIFT : USBMSC_FSBULKMXPKTSHIFT) -# define USBMSC_BULKMXPKTMASK(d) \ - (((d)->speed==USB_SPEED_HIGH) ? USBMSC_HSBULKMXPKTMASK : USBMSC_FSBULKMXPKTMASK) -#else -# define USBMSC_EPBULKINDESC(d) usbmsc_getepdesc(USBMSC_EPFSBULKIN) -# define USBMSC_EPBULKOUTDESC(d) usbmsc_getepdesc(USBMSC_EPFSBULKOUT) -# define USBMSC_BULKMAXPACKET(hs) USBMSC_FSBULKMAXPACKET -# define USBMSC_BULKMXPKTSHIFT(d) USBMSC_FSBULKMXPKTSHIFT -# define USBMSC_BULKMXPKTMASK(d) USBMSC_FSBULKMXPKTMASK -#endif - /* Configuration descriptor size */ #ifndef CONFIG_USBMSC_COMPOSITE -/* Number of individual descriptors in the configuration descriptor: - * (1) Configuration descriptor + (1) interface descriptor + (2) interface - * descriptors. - */ - -# define USBMSC_CFGGROUP_SIZE (4) - /* The size of the config descriptor: (9 + 9 + 2*7) = 32 */ # define SIZEOF_USBMSC_CFGDESC \ @@ -362,12 +331,6 @@ #else -/* Number of individual descriptors in the configuration descriptor: - * (1) interface descriptor + (2) interface descriptors. - */ - -# define USBMSC_CFGGROUP_SIZE (3) - /* The size of the config descriptor: (9 + 2*7) = 23 */ # define SIZEOF_USBMSC_CFGDESC \ @@ -377,9 +340,12 @@ /* Block driver helpers *****************************************************/ -#define USBMSC_DRVR_READ(l,b,s,n) ((l)->inode->u.i_bops->read((l)->inode,b,s,n)) -#define USBMSC_DRVR_WRITE(l,b,s,n) ((l)->inode->u.i_bops->write((l)->inode,b,s,n)) -#define USBMSC_DRVR_GEOMETRY(l,g) ((l)->inode->u.i_bops->geometry((l)->inode,g)) +#define USBMSC_DRVR_READ(l,b,s,n) \ + ((l)->inode->u.i_bops->read((l)->inode,b,s,n)) +#define USBMSC_DRVR_WRITE(l,b,s,n) \ + ((l)->inode->u.i_bops->write((l)->inode,b,s,n)) +#define USBMSC_DRVR_GEOMETRY(l,g) \ + ((l)->inode->u.i_bops->geometry((l)->inode,g)) /* Everpresent MIN/MAX macros ***********************************************/ @@ -398,13 +364,8 @@ enum usbmsc_epdesc_e { - USBMSC_EPFSBULKOUT = 0, /* Full speed bulk OUT endpoint descriptor */ - USBMSC_EPFSBULKIN /* Full speed bulk IN endpoint descriptor */ -#ifdef CONFIG_USBDEV_DUALSPEED - , - USBMSC_EPHSBULKOUT, /* High speed bulk OUT endpoint descriptor */ - USBMSC_EPHSBULKIN /* High speed bulk IN endpoint descriptor */ -#endif + USBMSC_EPBULKOUT = 0, /* Bulk OUT endpoint descriptor */ + USBMSC_EPBULKIN /* Bulk IN endpoint descriptor */ }; /* Container to support a list of requests */ @@ -419,7 +380,7 @@ struct usbmsc_req_s struct usbmsc_lun_s { - struct inode *inode; /* Inode structure of open'ed block driver */ + FAR struct inode *inode; /* Inode structure of open'ed block driver */ uint8_t readonly:1; /* Media is read-only */ uint8_t locked:1; /* Media removal is prevented */ uint16_t sectorsize; /* The size of one sector */ @@ -487,6 +448,8 @@ struct usbmsc_dev_s struct sq_queue_s wrreqlist; /* List of empty write request containers */ struct sq_queue_s rdreqlist; /* List of filled read request containers */ + struct usbdev_description_s devdesc; + /* Pre-allocated write request containers. The write requests will * be linked in a free list (wrreqlist), and used to send requests to * EPBULKIN; Read requests will be queued in the EBULKOUT. @@ -536,11 +499,11 @@ EXTERN const char g_compserialstr[]; EXTERN FAR struct usbmsc_dev_s *g_usbmsc_handoff; -/************************************************************************************ +/**************************************************************************** * Public Function Prototypes - ************************************************************************************/ + ****************************************************************************/ -/************************************************************************************ +/**************************************************************************** * Name: usbmsc_scsi_lock * * Description: @@ -550,91 +513,95 @@ EXTERN FAR struct usbmsc_dev_s *g_usbmsc_handoff; void usbmsc_scsi_lock(FAR struct usbmsc_dev_s *priv); -/************************************************************************************ +/**************************************************************************** * Name: usbmsc_scsi_unlock * * Description: * Relinquish exclusive access to SCSI state data. * - ************************************************************************************/ + ****************************************************************************/ #define usbmsc_scsi_unlock(priv) sem_post(&priv->thlock) -/************************************************************************************ +/***************************************************************************** * Name: usbmsc_scsi_signal * * Description: * Signal the SCSI worker thread that SCSI events need service. * - ************************************************************************************/ + ****************************************************************************/ void usbmsc_scsi_signal(FAR struct usbmsc_dev_s *priv); -/************************************************************************************ +/**************************************************************************** * Name: usbmsc_synch_signal * * Description: * ACK controlling tasks request for synchronization. * - ************************************************************************************/ + ****************************************************************************/ #define usbmsc_synch_signal(priv) sem_post(&priv->thsynch) -/************************************************************************************ +/**************************************************************************** * Name: usbmsc_mkstrdesc * * Description: * Construct a string descriptor * - ************************************************************************************/ + ****************************************************************************/ struct usb_strdesc_s; int usbmsc_mkstrdesc(uint8_t id, struct usb_strdesc_s *strdesc); -/************************************************************************************ +/**************************************************************************** * Name: usbmsc_getdevdesc * * Description: * Return a pointer to the raw device descriptor * - ************************************************************************************/ + ****************************************************************************/ #ifndef CONFIG_USBMSC_COMPOSITE FAR const struct usb_devdesc_s *usbmsc_getdevdesc(void); #endif -/************************************************************************************ - * Name: usbmsc_getepdesc +/**************************************************************************** + * Name: usbmsc_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) ). * - ************************************************************************************/ + ****************************************************************************/ -struct usb_epdesc_s; -FAR const struct usb_epdesc_s *usbmsc_getepdesc(enum usbmsc_epdesc_e epid); +int usbmsc_copy_epdesc(enum usbmsc_epdesc_e epid, + FAR struct usb_epdesc_s *epdesc, + FAR struct usbdev_description_s *devdesc, + bool hispeed); -/************************************************************************************ +/**************************************************************************** * Name: usbmsc_mkcfgdesc * * Description: * Construct the configuration descriptor * - ************************************************************************************/ + ****************************************************************************/ #ifdef CONFIG_USBDEV_DUALSPEED -int16_t usbmsc_mkcfgdesc(FAR uint8_t *buf, uint8_t speed, uint8_t type); +int16_t usbmsc_mkcfgdesc(FAR uint8_t *buf, FAR struct usbdev_description_s *devdesc, + uint8_t speed, uint8_t type); #else -int16_t usbmsc_mkcfgdesc(FAR uint8_t *buf); +int16_t usbmsc_mkcfgdesc(FAR uint8_t *buf, FAR struct usbdev_description_s *devdesc); #endif -/************************************************************************************ +/**************************************************************************** * Name: usbmsc_getqualdesc * * Description: * Return a pointer to the raw qual descriptor * - ************************************************************************************/ + ****************************************************************************/ #if !defined(CONFIG_USBMSC_COMPOSITE) && defined(CONFIG_USBDEV_DUALSPEED) FAR const struct usb_qualdesc_s *usbmsc_getqualdesc(void); @@ -725,4 +692,4 @@ void usbmsc_deferredresponse(FAR struct usbmsc_dev_s *priv, bool failed); } #endif -#endif /* #define __DRIVERS_USBDEV_USBMSC_H */ +#endif /* __DRIVERS_USBDEV_USBMSC_H */ diff --git a/drivers/usbdev/usbmsc_desc.c b/drivers/usbdev/usbmsc_desc.c index 1a97da82243..e700ca98449 100644 --- a/drivers/usbdev/usbmsc_desc.c +++ b/drivers/usbdev/usbmsc_desc.c @@ -1,7 +1,7 @@ /**************************************************************************** * drivers/usbdev/usbmsc_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 @@ -50,21 +50,10 @@ #include "usbmsc.h" -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - /**************************************************************************** * Private Data ****************************************************************************/ + /* Descriptors **************************************************************/ /* Device descriptor. If the USB mass storage device is configured as part * of a composite device, then the device descriptor will be provided by the @@ -92,79 +81,13 @@ static const struct usb_devdesc_s g_devdesc = LSBYTE(CONFIG_USBMSC_VERSIONNO), MSBYTE(CONFIG_USBMSC_VERSIONNO) }, - USBMSC_MANUFACTURERSTRID, /* imfgr */ - USBMSC_PRODUCTSTRID, /* iproduct */ - USBMSC_SERIALSTRID, /* serno */ - USBMSC_NCONFIGS /* nconfigs */ + USBMSC_MANUFACTURERSTRID, /* imfgr */ + USBMSC_PRODUCTSTRID, /* iproduct */ + USBMSC_SERIALSTRID, /* serno */ + USBMSC_NCONFIGS /* nconfigs */ }; #endif -/* Configuration descriptor If the USB mass storage device is configured as part - * of a composite device, then the configuration descriptor will be provided by the - * composite device logic. - */ - -#ifndef CONFIG_USBMSC_COMPOSITE -static const struct usb_cfgdesc_s g_cfgdesc = -{ - USB_SIZEOF_CFGDESC, /* len */ - USB_DESC_TYPE_CONFIG, /* type */ - { /* totallen */ - LSBYTE(SIZEOF_USBMSC_CFGDESC), - MSBYTE(SIZEOF_USBMSC_CFGDESC) - }, - USBMSC_NINTERFACES, /* ninterfaces */ - USBMSC_CONFIGID, /* cfgvalue */ - USBMSC_CONFIGSTRID, /* icfg */ - USB_CONFIG_ATTR_ONE | /* attr */ - USBMSC_SELFPOWERED | - USBMSC_REMOTEWAKEUP, - (CONFIG_USBDEV_MAXPOWER + 1) / 2 /* mxpower */ -}; -#endif - -/* Single interface descriptor */ - -static const struct usb_ifdesc_s g_ifdesc = -{ - USB_SIZEOF_IFDESC, /* len */ - USB_DESC_TYPE_INTERFACE, /* type */ - USBMSC_INTERFACEID, /* ifno */ - USBMSC_ALTINTERFACEID, /* alt */ - USBMSC_NENDPOINTS, /* neps */ - USB_CLASS_MASS_STORAGE, /* classid */ - USBMSC_SUBCLASS_SCSI, /* subclass */ - USBMSC_PROTO_BULKONLY, /* protocol */ - USBMSC_INTERFACESTRID /* iif */ -}; - -/* Endpoint descriptors */ - -static const struct usb_epdesc_s g_fsepbulkoutdesc = -{ - USB_SIZEOF_EPDESC, /* len */ - USB_DESC_TYPE_ENDPOINT, /* type */ - USBMSC_EPOUTBULK_ADDR, /* addr */ - USBMSC_EPOUTBULK_ATTR, /* attr */ - { /* maxpacket */ - LSBYTE(USBMSC_FSBULKMAXPACKET), - MSBYTE(USBMSC_FSBULKMAXPACKET) - }, - 0 /* interval */ -}; - -static const struct usb_epdesc_s g_fsepbulkindesc = -{ - USB_SIZEOF_EPDESC, /* len */ - USB_DESC_TYPE_ENDPOINT, /* type */ - USBMSC_EPINBULK_ADDR, /* addr */ - USBMSC_EPINBULK_ATTR, /* attr */ - { /* maxpacket */ - LSBYTE(USBMSC_FSBULKMAXPACKET), - MSBYTE(USBMSC_FSBULKMAXPACKET) - }, - 0 /* interval */ -}; #ifdef CONFIG_USBDEV_DUALSPEED #ifndef CONFIG_USBMSC_COMPOSITE @@ -184,32 +107,6 @@ static const struct usb_qualdesc_s g_qualdesc = 0, /* reserved */ }; #endif - -static const struct usb_epdesc_s g_hsepbulkoutdesc = -{ - USB_SIZEOF_EPDESC, /* len */ - USB_DESC_TYPE_ENDPOINT, /* type */ - USBMSC_EPOUTBULK_ADDR, /* addr */ - USBMSC_EPOUTBULK_ATTR, /* attr */ - { /* maxpacket */ - LSBYTE(USBMSC_HSBULKMAXPACKET), - MSBYTE(USBMSC_HSBULKMAXPACKET) - }, - 0 /* interval */ -}; - -static const struct usb_epdesc_s g_hsepbulkindesc = -{ - USB_SIZEOF_EPDESC, /* len */ - USB_DESC_TYPE_ENDPOINT, /* type */ - USBMSC_EPINBULK_ADDR, /* addr */ - USBMSC_EPINBULK_ATTR, /* attr */ - { /* maxpacket */ - LSBYTE(USBMSC_HSBULKMAXPACKET), - MSBYTE(USBMSC_HSBULKMAXPACKET) - }, - 0 /* interval */ -}; #endif /**************************************************************************** @@ -304,7 +201,7 @@ int usbmsc_mkstrdesc(uint8_t id, struct usb_strdesc_s *strdesc) } /**************************************************************************** - * Name: usbmsc_getepdesc + * Name: usbmsc_getdevdesc * * Description: * Return a pointer to the raw device descriptor @@ -319,35 +216,89 @@ FAR const struct usb_devdesc_s *usbmsc_getdevdesc(void) #endif /**************************************************************************** - * Name: usbmsc_getepdesc + * Name: usbmsc_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 *usbmsc_getepdesc(enum usbmsc_epdesc_e epid) +int usbmsc_copy_epdesc(enum usbmsc_epdesc_e epid, + FAR struct usb_epdesc_s *epdesc, + FAR struct usbdev_description_s *devdesc, + bool hispeed) { - switch (epid) - { - case USBMSC_EPFSBULKOUT: /* Full speed bulk OUT endpoint descriptor */ - return &g_fsepbulkoutdesc; +#ifndef CONFIG_USBDEV_DUALSPEED + /* unused */ - case USBMSC_EPFSBULKIN: /* Full speed bulk IN endpoint descriptor */ - return &g_fsepbulkindesc; - -#ifdef CONFIG_USBDEV_DUALSPEED - case USBMSC_EPHSBULKOUT: /* High speed bulk OUT endpoint descriptor */ - return &g_hsepbulkoutdesc; - - case USBMSC_EPHSBULKIN: /* High speed bulk IN endpoint descriptor */ - return &g_hsepbulkindesc; + (void)hispeed; #endif - default: - return NULL; + + switch (epid) + { + case USBMSC_EPBULKOUT: /* Bulk OUT endpoint */ + { + epdesc->len = USB_SIZEOF_EPDESC; /* Descriptor length */ + epdesc->type = USB_DESC_TYPE_ENDPOINT; /* Descriptor type */ + epdesc->addr = USBMSC_MKEPBULKOUT(devdesc); /* Endpoint address */ + epdesc->attr = USBMSC_EPOUTBULK_ATTR; /* Endpoint attributes */ + +#ifdef CONFIG_USBDEV_DUALSPEED + if (hispeed) + { + /* Maximum packet size (high speed) */ + + epdesc->mxpacketsize[0] = LSBYTE(USBMSC_HSBULKMAXPACKET); + epdesc->mxpacketsize[1] = MSBYTE(USBMSC_HSBULKMAXPACKET); + } + else +#endif + { + /* Maximum packet size (full speed) */ + + epdesc->mxpacketsize[0] = LSBYTE(USBMSC_FSBULKMAXPACKET); + epdesc->mxpacketsize[1] = MSBYTE(USBMSC_FSBULKMAXPACKET); + } + + epdesc->interval = 0; /* Interval */ + } + break; + + case USBMSC_EPBULKIN: /* Bulk IN endpoint */ + { + epdesc->len = USB_SIZEOF_EPDESC; /* Descriptor length */ + epdesc->type = USB_DESC_TYPE_ENDPOINT; /* Descriptor type */ + epdesc->addr = USBMSC_MKEPBULKIN(devdesc); /* Endpoint address */ + epdesc->attr = USBMSC_EPINBULK_ATTR; /* Endpoint attributes */ + +#ifdef CONFIG_USBDEV_DUALSPEED + if (hispeed) + { + /* Maximum packet size (high speed) */ + + epdesc->mxpacketsize[0] = LSBYTE(USBMSC_HSBULKMAXPACKET); + epdesc->mxpacketsize[1] = MSBYTE(USBMSC_HSBULKMAXPACKET); + } + else +#endif + { + /* Maximum packet size (full speed) */ + + epdesc->mxpacketsize[0] = LSBYTE(USBMSC_FSBULKMAXPACKET); + epdesc->mxpacketsize[1] = MSBYTE(USBMSC_FSBULKMAXPACKET); + } + + epdesc->interval = 0; /* Interval */ + } + break; + + default: + return 0; } -}; + + return sizeof(struct usb_epdesc_s); +} /**************************************************************************** * Name: usbmsc_mkcfgdesc @@ -358,53 +309,104 @@ FAR const struct usb_epdesc_s *usbmsc_getepdesc(enum usbmsc_epdesc_e epid) ****************************************************************************/ #ifdef CONFIG_USBDEV_DUALSPEED -int16_t usbmsc_mkcfgdesc(uint8_t *buf, uint8_t speed, uint8_t type) +int16_t usbmsc_mkcfgdesc(uint8_t *buf, + FAR struct usbdev_description_s *devdesc, + uint8_t speed, uint8_t type) #else -int16_t usbmsc_mkcfgdesc(uint8_t *buf) +int16_t usbmsc_mkcfgdesc(uint8_t *buf, + FAR struct usbdev_description_s *devdesc) #endif { + int length = 0; + bool hispeed = false; + #ifdef CONFIG_USBDEV_DUALSPEED - FAR const struct usb_epdesc_s *epdesc; - bool hispeed; + hispeed = (speed == USB_SPEED_HIGH); + + /* Check for switches between high and full speed */ + + if (type == USB_DESC_TYPE_OTHERSPEEDCONFIG) + { + hispeed = !hispeed; + } #endif + /* Fill in all descriptors directly to the buf */ + /* Configuration descriptor. If the USB mass storage device is * configured as part of a composite device, then the configuration * descriptor will be provided by the composite device logic. */ #ifndef CONFIG_USBMSC_COMPOSITE - memcpy(buf, &g_cfgdesc, USB_SIZEOF_CFGDESC); - buf += USB_SIZEOF_CFGDESC; + { + /* Configuration descriptor If the USB mass storage device is configured as part + * of a 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; + + dest->len = USB_SIZEOF_CFGDESC; /* Descriptor length */ + dest->type = USB_DESC_TYPE_CONFIG; /* Descriptor type */ + dest->totallen[0] = LSBYTE(SIZEOF_USBMSC_CFGDESC); /* LS Total length */ + dest->totallen[1] = MSBYTE(SIZEOF_USBMSC_CFGDESC); /* MS Total length */ + dest->ninterfaces = USBMSC_NINTERFACES; /* Number of interfaces */ + dest->cfgvalue = USBMSC_CONFIGID; /* Configuration value */ + dest->icfg = USBMSC_CONFIGSTRID; /* Configuration */ + dest->attr = USB_CONFIG_ATTR_ONE | /* Attributes */ + USBMSC_SELFPOWERED | + USBMSC_REMOTEWAKEUP; + dest->mxpower = (CONFIG_USBDEV_MAXPOWER + 1) / 2; /* Max power (mA/2) */ + + buf += sizeof(struct usb_cfgdesc_s); + length += sizeof(struct usb_cfgdesc_s); + } #endif /* Copy the canned interface descriptor */ - memcpy(buf, &g_ifdesc, USB_SIZEOF_IFDESC); - buf += USB_SIZEOF_IFDESC; + { + /* Single interface descriptor */ + + FAR struct usb_ifdesc_s * dest = (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 = USBMSC_ALTINTERFACEID; /* Alternate setting */ + dest->neps = USBMSC_NENDPOINTS; /* Number of endpoints */ + dest->classid = USB_CLASS_MASS_STORAGE; /* Interface class */ + dest->subclass = USBMSC_SUBCLASS_SCSI; /* Interface sub-class */ + dest->protocol = USBMSC_PROTO_BULKONLY; /* Interface protocol */ + dest->iif = devdesc->strbase + USBMSC_INTERFACESTRID; /* iInterface */ + + buf += sizeof(struct usb_ifdesc_s); + length += sizeof(struct usb_ifdesc_s); + } /* Make the two endpoint configurations */ -#ifdef CONFIG_USBDEV_DUALSPEED - /* Check for switches between high and full speed */ + /* Bulk IN endpoint descriptor */ - hispeed = (speed == USB_SPEED_HIGH); - if (type == USB_DESC_TYPE_OTHERSPEEDCONFIG) - { - hispeed = !hispeed; - } + { + int len = usbmsc_copy_epdesc(USBMSC_EPBULKIN, (FAR struct usb_epdesc_s *)buf, + devdesc, hispeed); - epdesc = USBMSC_EPBULKINDESC(hispeed); - memcpy(buf, epdesc, USB_SIZEOF_EPDESC); - buf += USB_SIZEOF_EPDESC; + buf += len; + length += len; + } - epdesc = USBMSC_EPBULKOUTDESC(hispeed); - memcpy(buf, epdesc, USB_SIZEOF_EPDESC); -#else - memcpy(buf, &g_fsepbulkoutdesc, USB_SIZEOF_EPDESC); - buf += USB_SIZEOF_EPDESC; - memcpy(buf, &g_fsepbulkindesc, USB_SIZEOF_EPDESC); -#endif + /* Bulk OUT endpoint descriptor */ + + { + int len = usbmsc_copy_epdesc(USBMSC_EPBULKOUT, + (FAR struct usb_epdesc_s *)buf, devdesc, + hispeed); + + buf += len; + length += len; + } return SIZEOF_USBMSC_CFGDESC; } @@ -423,4 +425,3 @@ FAR const struct usb_qualdesc_s *usbmsc_getqualdesc(void) return &g_qualdesc; } #endif - diff --git a/include/nuttx/board.h b/include/nuttx/board.h index bc67a03a2de..d19d6e7dc0f 100644 --- a/include/nuttx/board.h +++ b/include/nuttx/board.h @@ -263,6 +263,28 @@ int board_composite_initialize(int port); #endif #endif +/**************************************************************************** + * Name: board_composite_connect + * + * Description: + * Connect the USB composite device on the specified USB device port using + * the specified configuration. The interpretation of the configid is + * board specific. + * + * Input Parameters: + * port - The USB device port. + * configid - The USB composite configuration + * + * Returned Value: + * A non-NULL handle value is returned on success. NULL is returned on + * any failure. + * + ****************************************************************************/ + +#if defined(CONFIG_BOARDCTL_USBDEVCTRL) && defined(CONFIG_USBDEV_COMPOSITE) +FAR void *board_composite_connect(int port, int configid); +#endif + /**************************************************************************** * Name: board_tsc_setup * diff --git a/include/nuttx/usb/cdc.h b/include/nuttx/usb/cdc.h index d9f0f9e9a8b..a331a9bfc74 100644 --- a/include/nuttx/usb/cdc.h +++ b/include/nuttx/usb/cdc.h @@ -1,7 +1,7 @@ /******************************************************************************************** * include/nuttx/usb/cdc.h * - * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Copyright (C) 2011, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * References: "Universal Serial Bus Class Definitions for Communication @@ -73,7 +73,7 @@ /* Table 17: Communication Interface Class Control Protocol Codes */ #define CDC_PROTO_NONE 0x00 /* No class specific protocol required */ -#define CDC_PROTO_ATM 0x01 /* Common AT commands (also known as Hayes compatible”) */ +#define CDC_PROTO_ATM 0x01 /* Common AT commands (also known as Hayes compatible) */ /* 0x02-0xfe Reserved (future use) */ #define CDC_PROTO_VENDOR 0xff /* Vendor-specific */ @@ -242,12 +242,12 @@ * (Optional) */ #define ECM_SET_MCAST_FILTERS 0x40 /* As applications are loaded and unloaded on the host, - * the networking transport will instruct the device’s MAC - * driver to change settings of the Networking device’s + * the networking transport will instruct the device's MAC + * driver to change settings of the Networking device's * multicast filters. (Optional) */ #define ECM_SET_PM_PAT_FILTER 0x41 /* Some hosts are able to conserve energy and stay quiet - * in a “sleeping” state while not being used. USB + * in a "sleeping" state while not being used. USB * Networking devices may provide special pattern filtering * hardware that enables it to wake up the attached host * on demand when something is attempting to contact the @@ -593,9 +593,8 @@ struct cdc_hdr_funcdesc_s uint8_t size; /* bFunctionLength, Size of this descriptor */ uint8_t type; /* bDescriptorType, USB_DESC_TYPE_CSINTERFACE */ uint8_t subtype; /* bDescriptorSubType, CDC_DSUBTYPE_HDR as defined in Table 25 */ - uint8_t cdc[2]; /* bcdCDC, USB Class Definitions for Communication Devices Specification release - * number in binary-coded decimal. - */ + uint8_t cdc[2]; /* bcdCDC, USB Class Definitions for Communication Devices Specification + * release number in binary-coded decimal. */ }; #define SIZEOF_HDR_FUNCDESC 5 @@ -788,7 +787,7 @@ struct cdc_capi_funcdesc_s }; #define SIZEOF_CAPI_FUNCDESC 4 -/* Table 41: Ethernet Networking Functional Descriptor*/ +/* Table 41: Ethernet Networking Functional Descriptor */ struct cdc_ecm_funcdesc_s { @@ -833,7 +832,7 @@ struct cdc_atm_funcdesc_s * capable of supporting */ }; -#define SIZEOF_CALLMGMT_FUNCDESC 12 +#define SIZEOF_ATM_FUNCDESC 12 /* Descriptor Data Structures ***************************************************************/ /* Table 50: Line Coding Structure */ diff --git a/include/nuttx/usb/cdcacm.h b/include/nuttx/usb/cdcacm.h index 8ae1e7f3f78..724259d5349 100644 --- a/include/nuttx/usb/cdcacm.h +++ b/include/nuttx/usb/cdcacm.h @@ -1,7 +1,7 @@ /**************************************************************************** * include/nuttx/usb/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 @@ -47,6 +47,7 @@ /**************************************************************************** * Preprocessor definitions ****************************************************************************/ + /* Configuration ************************************************************/ /* CONFIG_CDCACM * Enable compilation of the USB serial driver @@ -96,6 +97,22 @@ * Size of the serial receive/transmit buffers. Default 256. */ +/* Informations needed in usbdev_description_s */ + +#define CDCACM_NUM_EPS (3) + +#define CDCACM_EP_INTIN_IDX (0) +#define CDCACM_EP_BULKIN_IDX (1) +#define CDCACM_EP_BULKOUT_IDX (2) + +#define CDCACM_NCONFIGS (1) /* Number of configurations supported */ + +/* Configuration descriptor values */ + +#define CDCACM_CONFIGID (1) /* The only supported configuration ID */ + +#define CDCACM_NINTERFACES (2) /* Number of interfaces in the configuration */ + /* EP0 max packet size */ #ifndef CONFIG_CDCACM_EP0MAXPACKET @@ -106,8 +123,10 @@ * notification interrupt endpoint. */ -#ifndef CONFIG_CDCACM_EPINTIN -# define CONFIG_CDCACM_EPINTIN 1 +#ifndef CONFIG_CDCACM_COMPOSITE +# ifndef CONFIG_CDCACM_EPINTIN +# define CONFIG_CDCACM_EPINTIN 1 +# endif #endif #ifndef CONFIG_CDCACM_EPINTIN_FSSIZE @@ -127,8 +146,10 @@ * size will be followed by a NULL packet. */ -#ifndef CONFIG_CDCACM_EPBULKIN -# define CONFIG_CDCACM_EPBULKIN 2 +#ifndef CONFIG_CDCACM_COMPOSITE +# ifndef CONFIG_CDCACM_EPBULKIN +# define CONFIG_CDCACM_EPBULKIN 2 +# endif #endif #ifndef CONFIG_CDCACM_EPBULKIN_FSSIZE @@ -155,8 +176,10 @@ * maxpacket size. */ -#ifndef CONFIG_CDCACM_EPBULKOUT -# define CONFIG_CDCACM_EPBULKOUT 3 +#ifndef CONFIG_CDCACM_COMPOSITE +# ifndef CONFIG_CDCACM_EPBULKOUT +# define CONFIG_CDCACM_EPBULKOUT 3 +# endif #endif #ifndef CONFIG_CDCACM_EPBULKOUT_FSSIZE @@ -306,51 +329,6 @@ typedef FAR void (*cdcacm_callback_t)(enum cdcacm_event_e event); * Public Function Prototypes ****************************************************************************/ -/**************************************************************************** - * Name: board_cdcclassobject - * - * Description: - * If the CDC serial class driver is part of composite device, then - * board-specific logic must provide board_cdcclassobject(). In the - * simplest case, board_cdcclassobject() is simply a wrapper around - * cdcacm_classobject() that provides the correct device minor number. - * - * Input Parameters: - * classdev - The location to return the CDC serial class' device - * instance. - * - * Returned Value: - * 0 on success; a negated errno on failure - * - ****************************************************************************/ - -#if defined(CONFIG_USBDEV_COMPOSITE) && defined(CONFIG_CDCACM_COMPOSITE) -struct usbdevclass_driver_s; -int board_cdcclassobject(FAR struct usbdevclass_driver_s **classdev); -#endif - -/**************************************************************************** - * Name: board_cdcuninitialize - * - * Description: - * Un-initialize the USB serial class driver. This is just an application- - * specific wrapper around cdcadm_unitialize() that is called form the - * composite device logic. - * - * Input Parameters: - * classdev - The class driver instance previously give to the composite - * driver by board_cdcclassobject(). - * - * Returned Value: - * None - * - ****************************************************************************/ - -#if defined(CONFIG_USBDEV_COMPOSITE) && defined(CONFIG_CDCACM_COMPOSITE) -struct usbdevclass_driver_s; -void board_cdcuninitialize(FAR struct usbdevclass_driver_s *classdev); -#endif - /**************************************************************************** * Name: cdcacm_classobject * @@ -370,7 +348,10 @@ void board_cdcuninitialize(FAR struct usbdevclass_driver_s *classdev); ****************************************************************************/ #if defined(CONFIG_USBDEV_COMPOSITE) && defined(CONFIG_CDCACM_COMPOSITE) -int cdcacm_classobject(int minor, FAR struct usbdevclass_driver_s **classdev); +struct usbdev_description_s; +struct usbdevclass_driver_s; +int cdcacm_classobject(int minor, FAR struct usbdev_description_s *devdesc, + FAR struct usbdevclass_driver_s **classdev); #endif /**************************************************************************** @@ -409,8 +390,7 @@ int cdcacm_initialize(int minor, FAR void **handle); * CDC/ACM driver is an internal part of a composite device, or a * standalone USB driver: * - * classdev - The class object returned by board_cdcclassobject() or - * cdcacm_classobject() + * classdev - The class object returned by cdcacm_classobject() * handle - The opaque handle representing the class object returned by * a previous call to cdcacm_initialize(). * @@ -425,6 +405,26 @@ void cdcacm_uninitialize(FAR struct usbdevclass_driver_s *classdev); void cdcacm_uninitialize(FAR void *handle); #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) +struct composite_devdesc_s; +void cdcacm_get_composite_devdesc(struct composite_devdesc_s *dev); +#endif + #undef EXTERN #if defined(__cplusplus) } diff --git a/include/nuttx/usb/composite.h b/include/nuttx/usb/composite.h index 722f9c46670..be728423cba 100644 --- a/include/nuttx/usb/composite.h +++ b/include/nuttx/usb/composite.h @@ -1,7 +1,7 @@ /************************************************************************************ * include/nuttx/usb/composite.h * - * Copyright (C) 2008-2011, 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2008-2011, 2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -41,12 +41,14 @@ ****************************************************************************/ #include +#include #ifdef CONFIG_USBDEV_COMPOSITE /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ + /* Configuration ************************************************************/ /* CONFIG_USBDEV_COMPOSITE * Enables USB composite device support @@ -70,6 +72,11 @@ * Interface version number. */ +#define COMPOSITE_NSTRIDS (5) /* The numer of String-IDs to + * reserve for the composite device */ +#define COMPOSITE_NCONFIGS (1) /* The number of configurations + * supported */ + /**************************************************************************** * Public Types ****************************************************************************/ @@ -97,8 +104,7 @@ extern "C" * Description: * Register USB composite device as configured. This function will call * board-specific implementations in order to obtain the class objects for - * each of the members of the composite (see board_mscclassobject(), - * board_cdcclassobjec(), ...) + * each of the members of the composite. * * Input Parameter: * None @@ -113,7 +119,8 @@ extern "C" * ****************************************************************************/ -FAR void *composite_initialize(void); +FAR void *composite_initialize(uint8_t ndevices, + FAR struct composite_devdesc_s *pdevices); /**************************************************************************** * Name: composite_uninitialize @@ -122,8 +129,7 @@ FAR void *composite_initialize(void); * Un-initialize the USB composite driver. The handle is the USB composite * class' device object as was returned by composite_initialize(). This * function will call board-specific implementations in order to free the - * class objects for each of the members of the composite (see - * board_mscuninitialize(), board_cdcuninitialize(), ...) + * class objects for each of the members of the composite. * * Input Parameters: * handle - The handle returned by a previous call to composite_initialize(). @@ -135,30 +141,6 @@ FAR void *composite_initialize(void); void composite_uninitialize(FAR void *handle); -/**************************************************************************** - * Name: composite_initialize - * - * Description: - * Register USB composite device as configured. This function will call - * board-specific implementations in order to obtain the class objects for - * each of the members of the composite (see board_mscclassobject(), - * board_cdcclassobjec(), ...) - * - * Input Parameter: - * None - * - * Returned Value: - * A non-NULL "handle" is returned on success. This handle may be used - * later with composite_uninitialize() in order to removed the composite - * device. This handle is the (untyped) internal representation of the - * the class driver instance. - * - * NULL is returned on any failure. - * - ****************************************************************************/ - -FAR void *composite_initialize(void); - /**************************************************************************** * Name: composite_ep0submit * diff --git a/include/nuttx/usb/usbdev.h b/include/nuttx/usb/usbdev.h index ed7fe433ee5..3418aeb554a 100644 --- a/include/nuttx/usb/usbdev.h +++ b/include/nuttx/usb/usbdev.h @@ -196,6 +196,48 @@ /* USB Controller Structures ********************************************************/ +/* usbdev_description_s - describes the low level bindings of an usb device */ + +struct usbdev_description_s +{ + int ninterfaces; /* Number of interfaces in the configuration */ + int ifnobase; /* Offset to Interface-IDs */ + + int nstrings; /* Number of Strings */ + int strbase; /* Offset to String Numbers */ + + int nendpoints; /* Number of Endpoints referenced in the following allay */ + int epno[5]; /* Array holding the endpoint configuration for this device */ +}; + +#ifdef CONFIG_USBDEV_COMPOSITE +struct composite_devdesc_s +{ +#ifdef CONFIG_USBDEV_DUALSPEED + CODE int16_t (*mkconfdesc)(FAR uint8_t *buf, + FAR struct usbdev_description_s *devdesc, + uint8_t speed, uint8_t type); +#else + CODE int16_t (*mkconfdesc)(FAR uint8_t *buf, + FAR struct usbdev_description_s *devdesc); +#endif + + CODE int (*mkstrdesc)(uint8_t id, FAR struct usb_strdesc_s *strdesc); + CODE int (*classobject)(int minor, + FAR struct usbdev_description_s *devdesc, + FAR struct usbdevclass_driver_s **classdev); + CODE void (*uninitialize)(FAR struct usbdevclass_driver_s *classdev); + + int nconfigs; /* Number of configurations supported */ + int configid; /* The only supported configuration ID */ + + int cfgdescsize; /* The size of the config descriptor */ + int minor; + + struct usbdev_description_s devdesc; +}; +#endif + /* struct usbdev_req_s - describes one i/o request */ struct usbdev_ep_s; diff --git a/include/nuttx/usb/usbmsc.h b/include/nuttx/usb/usbmsc.h index 701fc958370..2533d62b10d 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 @@ -37,14 +37,14 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * - ************************************************************************************/ + ****************************************************************************/ #ifndef __INCLUDE_NUTTX_USB_USBMSC_H #define __INCLUDE_NUTTX_USB_USBMSC_H -/************************************************************************************ +/**************************************************************************** * Included Files - ************************************************************************************/ + ****************************************************************************/ #include @@ -52,17 +52,28 @@ #include #include -/************************************************************************************ +/**************************************************************************** * 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 - ************************************************************************************/ + ****************************************************************************/ -/************************************************************************************ +/**************************************************************************** * Public Data - ************************************************************************************/ + ****************************************************************************/ #undef EXTERN #if defined(__cplusplus) @@ -73,61 +84,11 @@ extern "C" # define EXTERN extern #endif -/************************************************************************************ - * Public Functions - ************************************************************************************/ - -/************************************************************************************ - * Name: board_mscclassobject - * - * Description: - * If the mass storage class driver is part of composite device, then - * its instantiation and configuration is a multi-step, board-specific, - * process (See comments for usbmsc_configure below). In this case, - * board-specific logic must provide board_mscclassobject(). - * - * board_mscclassobject() is called from the composite driver. It must - * encapsulate the instantiation and configuration of the mass storage - * class and the return the mass storage device's class driver instance - * to the composite dirver. - * - * Input Parameters: - * classdev - The location to return the mass storage class' device - * instance. - * - * Returned Value: - * 0 on success; a negated errno on failure - * - ************************************************************************************/ - -#if defined(CONFIG_USBDEV_COMPOSITE) && defined(CONFIG_USBMSC_COMPOSITE) -struct usbdevclass_driver_s; -int board_mscclassobject(FAR struct usbdevclass_driver_s **classdev); -#endif - /**************************************************************************** - * Name: board_mscuninitialize - * - * Description: - * Un-initialize the USB storage class driver. This is just an application- - * specific wrapper aboutn usbmsc_unitialize() that is called form the composite - * device logic. - * - * Input Parameters: - * classdev - The class driver instrance previously give to the composite - * driver by board_mscclassobject(). - * - * Returned Value: - * None - * + * Public Functions ****************************************************************************/ -#if defined(CONFIG_USBDEV_COMPOSITE) && defined(CONFIG_USBMSC_COMPOSITE) -struct usbdevclass_driver_s; -void board_mscuninitialize(FAR struct usbdevclass_driver_s *classdev); -#endif - -/************************************************************************************ +/**************************************************************************** * Name: usbmsc_configure * * Description: @@ -145,20 +106,21 @@ void board_mscuninitialize(FAR struct usbdevclass_driver_s *classdev); * * Returned Value: * 0 on success; a negated errno on failure. The returned handle value is - * an untyped equivalent to the usbmsc_classobject() or board_mscclassobject(). + * an untyped equivalent to the usbmsc_classobject(). * - ************************************************************************************/ + ****************************************************************************/ -int usbmsc_configure(unsigned int nluns, void **handle); +int usbmsc_configure(unsigned int nluns, FAR void **handle); -/************************************************************************************ +/**************************************************************************** * Name: usbmsc_bindlun * * Description: * Bind the block driver specified by drvrpath to a USB storage LUN. * * Input Parameters: - * handle - The handle returned by a previous call to usbmsc_configure(). + * handle - The handle returned by a previous call to + * usbmsc_configure(). * drvrpath - the full path to the block driver * startsector - A sector offset into the block driver to the start of the * partition on drvrpath (0 if no partitions) @@ -169,12 +131,12 @@ int usbmsc_configure(unsigned int nluns, void **handle); * Returned Value: * 0 on success; a negated errno on failure. * - ************************************************************************************/ + ****************************************************************************/ int usbmsc_bindlun(FAR void *handle, FAR const char *drvrpath, unsigned int lunno, off_t startsector, size_t nsectors, bool readonly); -/************************************************************************************ +/**************************************************************************** * Name: usbmsc_unbindlun * * Description: @@ -187,16 +149,16 @@ int usbmsc_bindlun(FAR void *handle, FAR const char *drvrpath, unsigned int lunn * Returned Value: * 0 on success; a negated errno on failure. * - ************************************************************************************/ + ****************************************************************************/ int usbmsc_unbindlun(FAR void *handle, unsigned int lunno); -/************************************************************************************ +/**************************************************************************** * Name: usbmsc_exportluns * * Description: - * After all of the LUNs have been bound, this function may be called in order to - * export those LUNs in the USB storage device. + * After all of the LUNs have been bound, this function may be called in + * order to export those LUNs in the USB storage device. * * Input Parameters: * handle - The handle returned by a previous call to usbmsc_configure(). @@ -204,13 +166,13 @@ int usbmsc_unbindlun(FAR void *handle, unsigned int lunno); * Returned Value: * 0 on success; a negated errno on failure * - ************************************************************************************/ + ****************************************************************************/ #if !defined(CONFIG_USBDEV_COMPOSITE) || !defined(CONFIG_USBMSC_COMPOSITE) int usbmsc_exportluns(FAR void *handle); #endif -/************************************************************************************ +/**************************************************************************** * Name: usbmsc_classobject * * Description: @@ -222,22 +184,22 @@ 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 *devdesc, + FAR struct usbdevclass_driver_s **classdev); #endif -/************************************************************************************ +/**************************************************************************** * Name: usbmsc_uninitialize * * Description: * Un-initialize the USB storage class driver. The handle is the USB MSC - * class' device object. This is the same value as returned by usbmsc_classobject - * (typed) or by usbmsc_configure (untyped). + * class' device object. This is the same value as returned by + * usbmsc_classobject (typed) or by usbmsc_configure (untyped). * * Input Parameters: * handle - The handle returned by a previous call to usbmsc_configure() @@ -246,10 +208,30 @@ int usbmsc_classobject(FAR void *handle, FAR struct usbdevclass_driver_s **class * Returned Value: * None * - ***********************************************************************************/ + ****************************************************************************/ 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) } diff --git a/include/sys/boardctl.h b/include/sys/boardctl.h index e0294e6437c..38896e233e0 100644 --- a/include/sys/boardctl.h +++ b/include/sys/boardctl.h @@ -247,6 +247,7 @@ struct boardioc_usbdev_ctrl_s uint8_t usbdev; /* See enum boardioc_usbdev_identifier_e */ uint8_t action; /* See enum boardioc_usbdev_action_e */ uint8_t instance; /* Identifies the USB device class instance */ + uint8_t config; /* Configuration used with BOARDIOC_USBDEV_CONNECT */ FAR void **handle; /* Connection handle */ }; #endif /* CONFIG_BOARDCTL_USBDEVCTRL */