Merged in paimonen/nuttx/pullreq_DFU_interface (pull request #754)

This commit is contained in:
Gregory Nutt
2018-11-09 07:07:29 -06:00
7 changed files with 852 additions and 2 deletions

View File

@@ -190,6 +190,19 @@ config COMPOSITE_VERSIONNO
default 0x1010
---help---
Interface version number.
config COMPOSITE_MSFT_OS_DESCRIPTORS
bool "Add support for Microsoft OS Descriptors"
default n
---help---
Microsoft Windows cannot always automatically determine appropriate
drivers for different interfaces of a USB composite device. There is
a vendor-specific mechanism called "Microsoft OS Descriptors" that
allows the interface to provide further ID code to help with driver
loading. See https://msdn.microsoft.com/en-us/windows/hardware/gg463179
Enabling this feature in composite driver will pass these requests
onwards to the interface drivers.
endif
config PL2303
@@ -720,9 +733,52 @@ config RNDIS_VERSIONNO
hex "RNDIS Version Number"
default 0x0001
endif # RNDIS
endif # !RNDIS_COMPOSITE
endif # RNDIS_COMPOSITE
menuconfig DFU
bool "DFU Device Firmware Upgrade"
default n
---help---
References:
- "Universal Serial Bus Device Class Specification for Device
Firmware Upgrade, Version 1.1, Aug 5, 2004"
This driver implements the application-part of DFU protocol. It enables
a host application to send DFU_DETACH request and to cause the device
to reboot into a bootloader mode.
if DFU
config DFU_MSFT_OS_DESCRIPTORS
bool "Microsoft OS descriptor support"
default n
depends on COMPOSITE_MSFT_OS_DESCRIPTORS
---help---
Enabling this option will cause the DFU driver to return "WINUSB" as
the compatible ID of the DFU interface. This will automatically load
the appropriate driver for use with e.g. libusb and dfu-util.
Note that as of 2018 there are some issues with libusb and
composite devices, you may need a patched version:
https://sourceforge.net/p/libusb/mailman/message/36304399/
config DFU_INTERFACE_NAME
string "DFU interface string"
default "DFU interface"
---help---
String to assign as a name for the DFU interface.
if DFU_MSFT_OS_DESCRIPTORS
config DFU_INTERFACE_GUID
string "DFU interface GUID"
default "{8FE6D4D7-49DD-41E7-9486-49AFC6BFE475}"
---help---
DeviceInterfaceGUID to use for DFU interface in Microsoft OS descriptors.
Actual value does not matter for libusb, but if using WinUSB API directly
you can request your device by this GUID.
endif # DFU_MSFT_OS_DESCRIPTORS
endif # DFU
menuconfig NET_CDCECM
bool "CDC-ECM Ethernet-over-USB"

View File

@@ -61,6 +61,10 @@ ifeq ($(CONFIG_RNDIS),y)
CSRCS += rndis.c
endif
ifeq ($(CONFIG_DFU),y)
CSRCS += dfu.c
endif
ifeq ($(CONFIG_NET_CDCECM),y)
CSRCS += cdcecm.c
endif

View File

@@ -192,6 +192,90 @@ static int composite_classsetup(FAR struct composite_dev_s *priv,
return ret;
}
/****************************************************************************
* Name: composite_msftdescriptor
*
* Description:
* Assemble the Microsoft OS descriptor from the COMPATIBLE_ID's given
* in each device's composite_devdesc_s.
*
****************************************************************************/
#ifdef CONFIG_COMPOSITE_MSFT_OS_DESCRIPTORS
static int composite_msftdescriptor(FAR struct composite_dev_s *priv,
FAR struct usbdev_s *dev,
FAR const struct usb_ctrlreq_s *ctrl, FAR struct usbdev_req_s *ctrl_rsp, FAR bool *dispatched)
{
if (ctrl->index[0] == MSFTOSDESC_INDEX_FUNCTION)
{
/* Function descriptor is common to whole device */
int i;
FAR struct usb_msft_os_feature_desc_s *response = (FAR struct usb_msft_os_feature_desc_s*)ctrl_rsp->buf;
memset(response, 0, sizeof(*response));
for (i = 0; i < priv->ndevices; i++)
{
if (priv->device[i].compdesc.msft_compatible_id[0] != 0)
{
FAR struct usb_msft_os_function_desc_s *func = &response->function[response->count];
memset(func, 0, sizeof(*func));
func->firstif = priv->device[i].compdesc.devinfo.ifnobase;
func->nifs = priv->device[i].compdesc.devinfo.ninterfaces;
memcpy(func->compatible_id, priv->device[i].compdesc.msft_compatible_id, sizeof(func->compatible_id));
memcpy(func->sub_id, priv->device[i].compdesc.msft_sub_id, sizeof(func->sub_id));
response->count++;
}
}
if (response->count > 0)
{
size_t total_len = sizeof(struct usb_msft_os_feature_desc_s) + (response->count - 1) * sizeof(struct usb_msft_os_function_desc_s);
response->len[0] = (total_len >> 0) & 0xFF;
response->len[1] = (total_len >> 8) & 0xFF;
response->len[2] = (total_len >> 16) & 0xFF;
response->len[3] = (total_len >> 24) & 0xFF;
response->version[1] = 0x01;
response->index[0] = MSFTOSDESC_INDEX_FUNCTION;
return total_len;
}
else
{
return 0;
}
}
else if (ctrl->index[0] == MSFTOSDESC_INDEX_EXTPROP || ctrl->index[0] == ctrl->value[0])
{
/* Extended properties are per-interface, pass the request to subdevice.
* NOTE: The documentation in OS_Desc_Ext_Prop.docx seems a bit incorrect here,
* the interface is in ctrl->value low byte.
* Also WinUSB driver has limitation that index[0] will not be correct if
* trying to read descriptors using e.g. libusb xusb.exe.
*/
int i;
int ret = -ENOTSUP;
uint8_t interface = ctrl->value[0];
for (i = 0; i < priv->ndevices; i++)
{
if (interface >= priv->device[i].compdesc.devinfo.ifnobase &&
interface < (priv->device[i].compdesc.devinfo.ifnobase +
priv->device[i].compdesc.devinfo.ninterfaces))
{
ret = CLASS_SETUP(priv->device[i].dev, dev, ctrl, NULL, 0);
*dispatched = true;
break;
}
}
return ret;
}
else
{
return -ENOTSUP;
}
}
#endif
/****************************************************************************
* Name: composite_allocreq
*
@@ -490,6 +574,20 @@ static int composite_setup(FAR struct usbdevclass_driver_s *driver,
{
ret = composite_mkstrdesc(strid, buf);
}
#ifdef CONFIG_COMPOSITE_MSFT_OS_DESCRIPTORS
else if (strid == USB_REQ_GETMSFTOSDESCRIPTOR)
{
/* Note: Windows has a habit of caching this response, so if you want to enable/disable
* it you'll usually need to change the device serial number afterwards. */
static const uint8_t msft_response[16] = {
'M',0,'S',0,'F',0,'T',0,'1',0,'0',0,'0',0,0xEE,0
};
buf->len = 18;
buf->type = USB_DESC_TYPE_STRING;
memcpy(buf->data, msft_response, 16);
ret = buf->len;
}
#endif
else
{
int i;
@@ -573,6 +671,14 @@ static int composite_setup(FAR struct usbdevclass_driver_s *driver,
break;
}
}
#ifdef CONFIG_COMPOSITE_MSFT_OS_DESCRIPTORS
else if (ctrl->req == USB_REQ_GETMSFTOSDESCRIPTOR &&
(ctrl->type & USB_REQ_DIR_MASK) == USB_REQ_DIR_IN &&
(ctrl->type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_VENDOR)
{
ret = composite_msftdescriptor(priv, dev, ctrl, ctrlreq, &dispatched);
}
#endif
else
{
uint8_t recipient;

526
drivers/usbdev/dfu.c Normal file

File diff suppressed because it is too large Load Diff

93
include/nuttx/usb/dfu.h Normal file
View File

@@ -0,0 +1,93 @@
/****************************************************************************
* include/nuttx/usb/dfu.h
*
* Copyright (C) 2011-2018 Gregory Nutt. All rights reserved.
* Authors: Petteri Aimonen <jpa@git.mail.kapsi.fi>
*
* 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.
*
****************************************************************************/
#ifndef __INCLUDE_NUTTX_USB_DFU_H
#define __INCLUDE_NUTTX_USB_DFU_H
/************************************************************************************
* Included Files
************************************************************************************/
#include <nuttx/config.h>
#include <nuttx/usb/usbdev.h>
/************************************************************************************
* Public Functions
************************************************************************************/
#undef EXTERN
#if defined(__cplusplus)
# define EXTERN extern "C"
extern "C"
{
#else
# define EXTERN extern
#endif
/****************************************************************************
* Name: usbdev_dfu_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
*
****************************************************************************/
void usbdev_dfu_get_composite_devdesc(struct composite_devdesc_s *dev);
/****************************************************************************
* Name: usbdev_dfu_activate_bootloader
*
* Description:
* Reboots into DFU bootloader mode. The USB DFU application side driver
* will call this when it receives DFU_DETACH request. The board-specific
* code must provide implementation for this function.
*
****************************************************************************/
void usbdev_dfu_activate_bootloader();
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif /* __INCLUDE_NUTTX_USB_DFU_H */

View File

@@ -259,6 +259,11 @@
#define USB_MAX_DEVICES (127)
/* Microsoft OS Descriptor specific values */
#define USB_REQ_GETMSFTOSDESCRIPTOR (0xEE)
#define MSFTOSDESC_INDEX_FUNCTION 4
#define MSFTOSDESC_INDEX_EXTPROP 5
/************************************************************************************
* Public Types
************************************************************************************/
@@ -417,6 +422,61 @@ struct usb_iaddesc_s
};
#define USB_SIZEOF_IADDESC 8
/* Microsoft OS function descriptor.
* This can be used to request a specific driver (such as WINUSB) to be loaded
* on Windows. Unlike other descriptors, it is requested by a special request
* USB_REQ_GETMSFTOSDESCRIPTOR.
* More details: https://msdn.microsoft.com/en-us/windows/hardware/gg463179
* And excellent explanation: https://github.com/pbatard/libwdi/wiki/WCID-Devices
*
* The device will have exactly one "Extended Compat ID Feature Descriptor",
* which may contain multiple "Function Descriptors" associated with different
* interfaces.
*/
struct usb_msft_os_function_desc_s
{
uint8_t firstif; /* Index of first associated interface */
uint8_t nifs; /* Number of associated interfaces */
uint8_t compatible_id[8]; /* COMPATIBLE_ID of the driver to load */
uint8_t sub_id[8]; /* SUB_COMPATIBLE_ID of the driver */
uint8_t reserved[6];
};
struct usb_msft_os_feature_desc_s
{
uint8_t len[4]; /* Descriptor length */
uint8_t version[2]; /* Descriptor syntax version, 0x0100 */
uint8_t index[2]; /* Set to 4 for "extended compat ID descriptors" */
uint8_t count; /* Number of function sections */
uint8_t reserved[7];
struct usb_msft_os_function_desc_s function[1];
};
/* Microsoft OS extended property descriptor.
* This can be used to set specific registry values, such as interface GUID for
* a device. It is requested per-interface by special request USB_REQ_GETMSFTOSDESCRIPTOR.
*
* The interface will have one extended properties descriptor, which may contain
* multiple properties inside it.
*/
struct usb_msft_os_extprop_hdr_s
{
uint8_t len[4]; /* Descriptor length */
uint8_t version[2]; /* Descriptor syntax version, 0x0100 */
uint8_t index[2]; /* Set to 5 for "extended property descriptors" */
uint8_t count[2]; /* Number of property sections */
/* The properties are appended after the header and follow this format:
* uint8_t prop_len[4];
* uint8_t data_type[4];
* uint8_t name_len[2];
* uint8_t name[name_len];
* uint8_t data_len[4];
* uint8_t data[data_len];
*/
};
/************************************************************************************
* Public Data
************************************************************************************/

View File

@@ -234,6 +234,11 @@ struct composite_devdesc_s
int cfgdescsize; /* The size of the config descriptor */
int minor;
#ifdef CONFIG_COMPOSITE_MSFT_OS_DESCRIPTORS
uint8_t msft_compatible_id[8];
uint8_t msft_sub_id[8];
#endif
struct usbdev_devinfo_s devinfo;
};
#endif