Merge remote-tracking branch 'origin/master' into beacon802154

This commit is contained in:
Gregory Nutt 2017-07-16 08:58:39 -06:00
commit 2f01b92fe2
33 changed files with 2973 additions and 1581 deletions

View file

@ -1,7 +1,7 @@
/****************************************************************************
* configs/boardctl.c
*
* Copyright (C) 2015-2016 Gregory Nutt. All rights reserved.
* Copyright (C) 2015-2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -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);

View file

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

View file

@ -1,87 +0,0 @@
/****************************************************************************
* configs/fire-stm32v2/src/stm32_composite.c
*
* Copyright (C) 2012, 2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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 <nuttx/config.h>
#include <stdio.h>
#include <nuttx/board.h>
#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 */
}

View file

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

View file

@ -48,25 +48,290 @@
#include <nuttx/board.h>
#include <nuttx/mmcsd.h>
#include <nuttx/spi/spi.h>
#include <nuttx/usb/usbdev.h>
#include <nuttx/usb/cdcacm.h>
#include <nuttx/usb/usbmsc.h>
#include <nuttx/usb/composite.h>
#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 */

View file

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

View file

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

View file

@ -47,22 +47,26 @@
#include <nuttx/board.h>
#include <nuttx/mmcsd.h>
#include <nuttx/spi/spi.h>
#include <nuttx/usb/usbdev.h>
#include <nuttx/usb/cdcacm.h>
#include <nuttx/usb/usbmsc.h>
#include <nuttx/usb/composite.h>
#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 */

View file

@ -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 <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -40,11 +40,123 @@
#include <nuttx/config.h>
#include <sys/types.h>
#include <nuttx/usb/usbdev.h>
#include <nuttx/usb/cdcacm.h>
#include <nuttx/usb/usbmsc.h>
#include <nuttx/usb/composite.h>
#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 */

View file

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

View file

@ -1,85 +0,0 @@
/****************************************************************************
* configs/shenzhou/src/stm32_composite.c
*
* Copyright (C) 2012, 2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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 <nuttx/config.h>
#include <stdio.h>
#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 */
}

View file

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

View file

@ -54,6 +54,11 @@
# include <sys/mount.h>
#endif
#include <nuttx/usb/usbdev.h>
#include <nuttx/usb/cdcacm.h>
#include <nuttx/usb/usbmsc.h>
#include <nuttx/usb/composite.h>
#ifdef CONFIG_USBMONITOR
# include <nuttx/usb/usbmonitor.h>
#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 */

View file

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

View file

@ -48,22 +48,23 @@
#include <nuttx/sdio.h>
#include <nuttx/mmcsd.h>
#include <nuttx/board.h>
#include <nuttx/usb/usbdev.h>
#include <nuttx/usb/cdcacm.h>
#include <nuttx/usb/usbmsc.h>
#include <nuttx/usb/composite.h>
#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 */

View file

@ -322,33 +322,10 @@ menuconfig CDCACM_COMPOSITE
Configure the CDC serial driver as part of a composite driver
(only if USBDEV_COMPOSITE is also defined)
if CDCACM_COMPOSITE
if !CDCACM_COMPOSITE
config CDCACM_IFNOBASE
int "Offset the CDC/ACM interface numbers"
default 0
---help---
If the CDC driver is part of a composite device, then this may need to
be defined to offset the CDC/ACM interface numbers so that they are
unique and contiguous. When used with the Mass Storage driver, the
correct value for this offset is zero.
config CDCACM_STRBASE
int "Offset the CDC/ACM string numbers"
default 4
---help---
If the CDC driver is part of a composite device, then this may need to
be defined to offset the CDC/ACM string numbers so that they are
unique and contiguous. When used with the Mass Storage driver, the
correct value for this offset is four (this value actuallly only needs
to be defined if names are provided for the Notification interface,
config CDCACM_NOTIFSTR, or the data interface, CDCACM_DATAIFSTR).
The default of four accounts for strings IDs 0-3 used by the composite
descriptors. Any additional CDC/ACM string descripts must then begin
with string index four.
endif
# In a composite device the EP0 config comes from the composite device
# and the EP-Number is configured dynamically via composite_initialize
config CDCACM_EP0MAXPACKET
int "Endpoint 0 max packet size"
@ -363,6 +340,8 @@ config CDCACM_EPINTIN
The logical 7-bit address of a hardware endpoint that supports
interrupt IN operation. Default 1.
endif
config CDCACM_EPINTIN_FSSIZE
int "Interupt IN full speed MAXPACKET size"
default 64
@ -377,6 +356,11 @@ config CDCACM_EPINTIN_HSSIZE
Max package size for the interrupt IN endpoint if high speed mode.
Default 64.
if !CDCACM_COMPOSITE
# In a composite device the EP-Number is configured dynamically via
# composite_initialize
config CDCACM_EPBULKOUT
int "Bulk OUT endpoint number"
default 3
@ -384,6 +368,8 @@ config CDCACM_EPBULKOUT
The logical 7-bit address of a hardware endpoint that supports
bulk OUT operation. Default: 3
endif
config CDCACM_EPBULKOUT_FSSIZE
int "Bulk OUT full speed MAXPACKET size"
default 64
@ -398,6 +384,11 @@ config CDCACM_EPBULKOUT_HSSIZE
Max package size for the bulk OUT endpoint if high speed mode.
Default 512.
if !CDCACM_COMPOSITE
# In a composite device the EP-Number is configured dynamically via
# composite_initialize
config CDCACM_EPBULKIN
int "Bulk IN endpoint number"
default 2
@ -405,6 +396,8 @@ config CDCACM_EPBULKIN
The logical 7-bit address of a hardware endpoint that supports
bulk IN operation. Default: 2
endif
config CDCACM_EPBULKIN_FSSIZE
int "Bulk IN full speed MAXPACKET size"
default 64
@ -468,6 +461,11 @@ config CDCACM_TXBUFSIZE
will hold one request of size 768; a buffer size of 193 will hold
two requests of size 96 bytes.
if !CDCACM_COMPOSITE
# In a composite device the Vendor- and Product-ID is given by the composite
# device
config CDCACM_VENDORID
hex "Vendor ID"
default 0x0525
@ -493,6 +491,7 @@ config CDCACM_PRODUCTSTR
string "Product string"
default "CDC/ACM Serial"
endif # !CDCACM_COMPOSITE
endif # CDCACM
menuconfig USBMSC
@ -530,38 +529,17 @@ config USBMSC_COMPOSITE
Configure the mass storage driver as part of a composite driver
(only if USBDEV_COMPOSITE is also defined)
config USBMSC_IFNOBASE
int "Offset the mass storage interface number"
default 2
depends on USBMSC_COMPOSITE
---help---
If the CDC driver is part of a composite device, then this may need to
be defined to offset the mass storage interface number so that it is
unique and contiguous. When used with the CDC/ACM driver, the
correct value for this offset is two (because of the two CDC/ACM
interfaces that will precede it).
config USBMSC_STRBASE
int "Offset the mass storage string numbers"
default 4
depends on USBMSC_COMPOSITE
---help---
If the CDC driver is part of a composite device, then this may need to
be defined to offset the mass storage string numbers so that they are
unique and contiguous. When used with the CDC/ACM driver, the
correct value for this offset is four (or perhaps 5 or 6, depending
on if CDCACM_NOTIFSTR or CDCACM_DATAIFSTR are defined).
String IDS 0-3 are used by the composite descriptors. This amount
may need to be incremented to account for string IDs used by other
members of the composite.
config USBMSC_EP0MAXPACKET
int "Max packet size for endpoint 0"
default 64
---help---
Max packet size for endpoint 0
if !USBMSC_COMPOSITE
# In a composite device the EP-Number and STR-Number is configured
# dynamically via composite_initialize
config USBMSC_EPBULKOUT
int "Bulk OUT endpoint number"
default 2
@ -576,6 +554,8 @@ config USBMSC_EPBULKIN
The logical 7-bit address of a hardware endpoints that support
bulk OUT and IN operations
endif
config USBMSC_NWRREQS
int "The number of write requests that can be in flight"
default 4
@ -613,6 +593,11 @@ config USBMSC_BULKOUTREQLEN
beyond the maximum size of one packet. Default: 512 or 64 bytes
(depending upon if dual speed operation is supported or not).
if !USBMSC_COMPOSITE
# In a composite device the Vendor- and Product-IDs are handled by the
# composite device
config USBMSC_VENDORID
hex "Mass storage Vendor ID"
default 0x584e
@ -638,6 +623,8 @@ config USBMSC_PRODUCTSTR
string "Mass storage product string"
default "Mass Storage"
endif # !USBMSC_COMPOSITE
config USBMSC_VERSIONNO
hex "USB MSC Version Number"
default "0x399"

View file

@ -1,7 +1,7 @@
/****************************************************************************
* drivers/usbdev/cdcacm.c
*
* Copyright (C) 2011-2013, 2016 Gregory Nutt. All rights reserved.
* Copyright (C) 2011-2013, 2016-2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -64,7 +64,7 @@
#include "cdcacm.h"
#ifdef CONFIG_USBMSC_COMPOSITE
#ifdef CONFIG_CDCACM_COMPOSITE
# include <nuttx/usb/composite.h>
# include "composite.h"
#endif
@ -105,6 +105,8 @@ struct cdcacm_dev_s
FAR struct usbdev_req_s *ctrlreq; /* Allocated control request */
struct sq_queue_s reqlist; /* List of write request containers */
struct usbdev_description_s devdesc;
/* Pre-allocated write request containers. The write requests will
* be linked in a free list (reqlist), and used to send requests to
* EPBULKIN; Read requests will be queued in the EBULKOUT.
@ -157,10 +159,10 @@ static void cdcacm_freereq(FAR struct usbdev_ep_s *ep,
/* Configuration ***********************************************************/
static void cdcacm_resetconfig(FAR struct cdcacm_dev_s *priv);
#ifdef CONFIG_USBDEV_DUALSPEED
static int cdcacm_epconfigure(FAR struct usbdev_ep_s *ep,
enum cdcacm_epdesc_e epid, uint16_t mxpacket, bool last);
#endif
enum cdcacm_epdesc_e epid, bool last,
FAR struct usbdev_description_s *devdesc,
bool hispeed);
static int cdcacm_setconfig(FAR struct cdcacm_dev_s *priv,
uint8_t config);
@ -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

View file

@ -1,7 +1,7 @@
/****************************************************************************
* drivers/usbdev/cdcacm.h
*
* Copyright (C) 2011-2012, 2015 Gregory Nutt. All rights reserved.
* Copyright (C) 2011-2012, 2015, 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -104,16 +104,9 @@
* CDCACM_DATAALTIFID No alternate for the data interface
*/
#define CDCACM_NINTERFACES (2) /* Number of interfaces in the configuration */
#define CDCACM_NOTIFID (CONFIG_CDCACM_IFNOBASE+0)
#define CDCACM_NOTALTIFID (0)
#define CDCACM_DATAIFID (CONFIG_CDCACM_IFNOBASE+1)
#define CDCACM_DATAALTIFID (0)
/* Configuration descriptor values */
#define CDCACM_CONFIGID (1) /* The only supported configuration ID */
/* Buffer big enough for any of our descriptors (the config descriptor is the
* biggest).
*/
@ -124,7 +117,6 @@
/* Device descriptor values */
#define CDCACM_VERSIONNO (0x0101) /* Device version number 1.1 (BCD) */
#define CDCACM_NCONFIGS (1) /* Number of configurations supported */
/* String language */
@ -165,62 +157,16 @@
#define CDCACM_LASTSTRID CDCACM_DATAIFSTRID
#define CDCACM_NSTRIDS (CDCACM_LASTSTRID - CDCACM_STRBASE)
/* Configuration descriptor size */
#if !defined(CONFIG_CDCACM_COMPOSITE)
/* Number of individual descriptors in the configuration descriptor:
* Configuration descriptor + (2) interface descriptors + (3) endpoint
* descriptors + (3) ACM descriptors.
*/
# define CDCACM_CFGGROUP_SIZE (9)
/* The size of the config descriptor: (9 + 2*9 + 3*7 + 4 + 5 + 5) = 62 */
# define SIZEOF_CDCACM_CFGDESC \
(USB_SIZEOF_CFGDESC + 2*USB_SIZEOF_IFDESC + 3*USB_SIZEOF_EPDESC + \
SIZEOF_ACM_FUNCDESC + SIZEOF_HDR_FUNCDESC + SIZEOF_UNION_FUNCDESC(1))
#elif defined(CONFIG_COMPOSITE_IAD)
/* Number of individual descriptors in the configuration descriptor:
* (1) interface association descriptor + (2) interface descriptors +
* (3) endpoint descriptors + (3) ACM descriptors.
*/
# define CDCACM_CFGGROUP_SIZE (9)
/* The size of the config descriptor: (8 + 2*9 + 3*7 + 4 + 5 + 5) = 61 */
# define SIZEOF_CDCACM_CFGDESC \
(USB_SIZEOF_IADDESC +2*USB_SIZEOF_IFDESC + 3*USB_SIZEOF_EPDESC + \
SIZEOF_ACM_FUNCDESC + SIZEOF_HDR_FUNCDESC + SIZEOF_UNION_FUNCDESC(1))
#else
/* Number of individual descriptors in the configuration descriptor:
* (2) interface descriptors + (3) endpoint descriptors + (3) ACM descriptors.
*/
# define CDCACM_CFGGROUP_SIZE (8)
/* The size of the config descriptor: (2*9 + 3*7 + 4 + 5 + 5) = 53 */
# define SIZEOF_CDCACM_CFGDESC \
(2*USB_SIZEOF_IFDESC + 3*USB_SIZEOF_EPDESC + SIZEOF_ACM_FUNCDESC + \
SIZEOF_HDR_FUNCDESC + SIZEOF_UNION_FUNCDESC(1))
#endif
/* Endpoint configuration ****************************************************/
#define CDCACM_EPINTIN_ADDR (USB_DIR_IN | CONFIG_CDCACM_EPINTIN)
#define CDCACM_MKEPINTIN(desc) (USB_DIR_IN | (desc)->epno[CDCACM_EP_INTIN_IDX])
#define CDCACM_EPINTIN_ATTR (USB_EP_ATTR_XFER_INT)
#define CDCACM_EPOUTBULK_ADDR (CONFIG_CDCACM_EPBULKOUT)
#define CDCACM_MKEPBULKIN(desc) (USB_DIR_IN | (desc)->epno[CDCACM_EP_BULKIN_IDX])
#define CDCACM_EPOUTBULK_ATTR (USB_EP_ATTR_XFER_BULK)
#define CDCACM_EPINBULK_ADDR (USB_DIR_IN | CONFIG_CDCACM_EPBULKIN)
#define CDCACM_MKEPBULKOUT(desc) ((desc)->epno[CDCACM_EP_BULKOUT_IDX])
#define CDCACM_EPINBULK_ATTR (USB_EP_ATTR_XFER_BULK)
/* Device driver definitions ************************************************/
@ -287,7 +233,7 @@ enum cdcacm_epdesc_e
int cdcacm_mkstrdesc(uint8_t id, struct usb_strdesc_s *strdesc);
/****************************************************************************
* Name: cdcacm_getepdesc
* Name: cdcacm_getdevdesc
*
* Description:
* Return a pointer to the raw device descriptor
@ -299,28 +245,18 @@ FAR const struct usb_devdesc_s *cdcacm_getdevdesc(void);
#endif
/****************************************************************************
* Name: cdcacm_getepdesc
* Name: cdcacm_copy_epdesc
*
* Description:
* Return a pointer to the raw endpoint descriptor (used for configuring
* endpoints)
* Copies the requested Endpoint Description into the buffer given.
* Returns the number of Bytes filled in (sizeof(struct usb_epdesc_s)).
*
****************************************************************************/
FAR const struct usb_epdesc_s *cdcacm_getepdesc(enum cdcacm_epdesc_e epid);
/****************************************************************************
* Name: cdcacm_mkepdesc
*
* Description:
* Construct the endpoint descriptor using the correct max packet size.
*
****************************************************************************/
#ifdef CONFIG_USBDEV_DUALSPEED
void cdcacm_mkepdesc(enum cdcacm_epdesc_e epid,
uint16_t mxpacket, FAR struct usb_epdesc_s *outdesc);
#endif
int cdcacm_copy_epdesc(enum cdcacm_epdesc_e epid,
FAR struct usb_epdesc_s *epdesc,
FAR struct usbdev_description_s *devdesc,
bool hispeed);
/****************************************************************************
* Name: cdcacm_mkcfgdesc
@ -331,9 +267,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
/****************************************************************************

View file

@ -1,7 +1,7 @@
/****************************************************************************
* drivers/usbdev/cdcacm_desc.c
*
* Copyright (C) 2011-2012, 2015 Gregory Nutt. All rights reserved.
* Copyright (C) 2011-2012, 2015, 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -46,35 +46,13 @@
#include <debug.h>
#include <nuttx/usb/usb.h>
#include <nuttx/usb/usbdev.h>
#include <nuttx/usb/cdc.h>
#include <nuttx/usb/cdcacm.h>
#include <nuttx/usb/usbdev_trace.h>
#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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 <gnutt@nuttx.org>
*
* 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 devices MAC
* driver to change settings of the Networking devices
* 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 */

View file

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

View file

@ -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 <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -41,12 +41,14 @@
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/usb/usbdev.h>
#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
*

View file

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

View file

@ -1,7 +1,7 @@
/************************************************************************************
/****************************************************************************
* include/nuttx/usb/usbmsc.h
*
* Copyright (C) 2008-2010, 2012 Gregory Nutt. All rights reserved.
* Copyright (C) 2008-2010, 2012, 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* NOTE: This interface was inspired by the Linux gadget interface by
@ -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 <nuttx/config.h>
@ -52,17 +52,28 @@
#include <stdint.h>
#include <stdbool.h>
/************************************************************************************
/****************************************************************************
* 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)
}

View file

@ -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 */

View file

@ -109,9 +109,12 @@ fi
WD=${PWD}
BOARDDIR=configs/$BOARDSUBDIR
SCRIPTSDIR=$BOARDDIR/scripts
MAKEDEFS1=$SCRIPTSDIR/Make.defs
CONFIGDIR=$BOARDDIR/$CONFIGSUBDIR
DEFCONFIG=$CONFIGDIR/defconfig
MAKEDEFS=$CONFIGDIR/Make.defs
MAKEDEFS2=$CONFIGDIR/Make.defs
CMPCONFIG_TARGET=cmpconfig
CMPCONFIG1=tools/cmpconfig
@ -136,9 +139,15 @@ if [ ! -r "$DEFCONFIG" ]; then
exit 1
fi
if [ ! -r "$MAKEDEFS" ]; then
echo "No readable Make.defs file at $MAKEDEFS"
exit 1
if [ -r "$MAKEDEFS1" ]; then
MAKEDEFS=$MAKEDEFS1
else
if [ -r "$MAKEDEFS2" ]; then
MAKEDEFS=$MAKEDEFS2
else
echo "No readable Make.defs file at $MAKEDEFS1 or $MAKEDEFS2"
exit 1
fi
fi
# If the cmpconfig executable does not exist, then build it