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
+58 -2
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"
+4
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
+106
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;
File diff suppressed because it is too large Load Diff