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
commit 2fad9b86d1
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
View File

@ -0,0 +1,526 @@
/****************************************************************************
* drivers/usbdev/dfu.c
*
* 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.
*
****************************************************************************/
/* This is a driver for the USB Device Firmware Upgrade protocol v1.1.
* Currently it supports the app-side ("Run-Time") part of the protocol:
* a sequence of DFU_DETACH and USB reset commands, which will reboot into
* a separate USB DFU bootloader.
*
* The bootloader is provided by board-specific logic, or STM32's
* built-in ROM bootloader can be used.
*
* https://www.usb.org/sites/default/files/DFU_1.1.pdf
*/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/usb/usb.h>
#include <nuttx/usb/usbdev.h>
#include <nuttx/usb/usbdev_trace.h>
#include <nuttx/usb/dfu.h>
#include <nuttx/kmalloc.h>
#include <nuttx/wqueue.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
/****************************************************************************
* Pre-processor definitions
****************************************************************************/
#define DFU_MAX_TIMEOUT 255
#define DFU_MAX_TRANSFER 2048
#define DFU_VERSION 0x011A
#define USB_REQ_DFU_DETACH 0
#define USB_REQ_DFU_GETSTATUS 3
#ifdef CONFIG_DFU_MSFT_OS_DESCRIPTORS
#define DFU_MAX_DESCRIPTOR_LEN 256
#else
#define DFU_MAX_DESCRIPTOR_LEN sizeof(struct dfu_cfgdesc_s)
#endif
/****************************************************************************
* Private Types
****************************************************************************/
/* Response to DFU_GETSTATUS */
struct dfu_getstatus_response_s
{
uint8_t status; /* Status of latest command */
uint8_t poll_timeout[3]; /* Time until next GETSTATUS request */
uint8_t state; /* Current state of the device */
uint8_t string_idx; /* Optional string description */
};
/* DFU functional descriptor */
struct dfu_funcdesc_s
{
uint8_t len; /* Descriptor length */
uint8_t type; /* 0x21 = DFU FUNCTIONAL */
uint8_t attributes; /* Bit mask of supported features */
uint8_t detach_timeout[2]; /* Maximum time in milliseconds between DFU_DETACH and USB reset */
uint8_t transfer_size[2]; /* Maximum number of bytes in control writes */
uint8_t dfu_version[2]; /* Version of DFU specification supported */
};
/* USB configuration descriptor */
struct dfu_cfgdesc_s
{
struct usb_ifdesc_s ifdesc; /* DFU interface descriptor */
struct dfu_funcdesc_s funcdesc; /* DFU functional descriptor */
};
struct dfu_driver_s
{
struct usbdevclass_driver_s drvr;
struct usbdev_devinfo_s devinfo;
FAR struct usbdev_req_s *ctrlreq; /* Pointer to preallocated control request */
struct work_s work_item; /* Work queue entry for activating bootloader */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* usbclass callbacks */
static int usbclass_setup(FAR struct usbdevclass_driver_s *driver,
FAR struct usbdev_s *dev,
FAR const struct usb_ctrlreq_s *ctrl,
FAR uint8_t *dataout, size_t outlen);
static int usbclass_bind(FAR struct usbdevclass_driver_s *driver,
FAR struct usbdev_s *dev);
static void usbclass_unbind(FAR struct usbdevclass_driver_s *driver,
FAR struct usbdev_s *dev);
static void usbclass_disconnect(FAR struct usbdevclass_driver_s *driver,
FAR struct usbdev_s *dev);
/****************************************************************************
* Private Data
****************************************************************************/
/* USB driver operations */
const static struct usbdevclass_driverops_s g_dfu_driverops =
{
&usbclass_bind,
&usbclass_unbind,
&usbclass_setup,
&usbclass_disconnect,
NULL,
NULL
};
static const struct dfu_cfgdesc_s g_dfu_cfgdesc =
{
{
.len = USB_SIZEOF_IFDESC,
.type = USB_DESC_TYPE_INTERFACE,
.ifno = 0,
.alt = 0,
.neps = 0,
.classid = 0xFE,
.subclass = 0x01,
.protocol = 0x01, /* DFU runtime protocol */
.iif = 0
},
{
.len = sizeof(struct dfu_funcdesc_s),
.type = 0x21,
.attributes = 0x0B,
.detach_timeout = { LSBYTE(DFU_MAX_TIMEOUT), MSBYTE(DFU_MAX_TIMEOUT) },
.transfer_size = { LSBYTE(DFU_MAX_TRANSFER), MSBYTE(DFU_MAX_TRANSFER) },
.dfu_version = { LSBYTE(DFU_VERSION), MSBYTE(DFU_VERSION) }
}
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: usbclass_freereq
*
* Description:
* Free a request instance along with its buffer
*
****************************************************************************/
static void usbclass_freereq(FAR struct usbdev_ep_s *ep,
FAR struct usbdev_req_s *req)
{
if (ep != NULL && req != NULL)
{
if (req->buf != NULL)
{
EP_FREEBUFFER(ep, req->buf);
}
EP_FREEREQ(ep, req);
}
}
/****************************************************************************
* Name: usbclass_allocreq
*
* Description:
* Allocate a request instance along with its buffer
*
****************************************************************************/
static FAR struct usbdev_req_s *usbclass_allocreq(FAR struct usbdev_ep_s *ep,
uint16_t len)
{
FAR struct usbdev_req_s *req;
req = EP_ALLOCREQ(ep);
if (req != NULL)
{
req->len = len;
req->buf = EP_ALLOCBUFFER(ep, len);
if (req->buf == NULL)
{
EP_FREEREQ(ep, req);
req = NULL;
}
}
return req;
}
static void usbclass_ep0incomplete(FAR struct usbdev_ep_s *ep,
FAR struct usbdev_req_s *req)
{
}
static int16_t usbclass_mkcfgdesc(FAR uint8_t *buf,
FAR struct usbdev_devinfo_s *devinfo)
{
FAR struct dfu_cfgdesc_s *dest = (FAR struct dfu_cfgdesc_s*)buf;
*dest = g_dfu_cfgdesc;
dest->ifdesc.ifno += devinfo->ifnobase;
dest->ifdesc.iif = devinfo->strbase;
return sizeof(g_dfu_cfgdesc);
}
static int convert_to_utf16(FAR uint8_t *dest, FAR const char *src)
{
int bytes = 0;
while (*src)
{
*dest++ = *src++;
*dest++ = 0x00;
bytes += 2;
}
return bytes;
}
static int usbclass_mkstrdesc(uint8_t id, FAR struct usb_strdesc_s *strdesc)
{
FAR const char *str;
if (id == 0)
{
str = CONFIG_DFU_INTERFACE_NAME;
}
else
{
return -EINVAL;
}
strdesc->len = 2 + convert_to_utf16(strdesc->data, str);
strdesc->type = USB_DESC_TYPE_STRING;
return strdesc->len;
}
#ifdef CONFIG_DFU_MSFT_OS_DESCRIPTORS
static int dfu_make_msft_extprop_desc(FAR uint8_t *buf)
{
FAR const char *propname = "DeviceInterfaceGUIDs";
FAR const char *propval = CONFIG_DFU_INTERFACE_GUID;
FAR struct usb_msft_os_extprop_hdr_s *hdr = (FAR struct usb_msft_os_extprop_hdr_s*)buf;
FAR uint8_t *payload = buf + sizeof(struct usb_msft_os_extprop_hdr_s);
int namelen, valuelen, proplen, totallen;
namelen = strlen(propname) * 2 + 2;
valuelen = strlen(propval) * 2 + 4;
proplen = 14 + namelen + valuelen;
totallen = sizeof(struct usb_msft_os_extprop_hdr_s) + proplen;
memset(buf, 0, totallen);
hdr->len[0] = LSBYTE(totallen);
hdr->len[1] = MSBYTE(totallen);
hdr->version[1] = 0x01;
hdr->index[0] = MSFTOSDESC_INDEX_EXTPROP;
hdr->count[0] = 1;
*payload++ = LSBYTE(proplen); // dwSize
*payload++ = MSBYTE(proplen);
*payload++ = 0;
*payload++ = 0;
*payload++ = 7; // dwPropertyDataType = REG_MULTI_SZ
*payload++ = 0;
*payload++ = 0;
*payload++ = 0;
*payload++ = LSBYTE(namelen); // wPropertyNameLength
*payload++ = MSBYTE(namelen);
payload += convert_to_utf16(payload, propname); // bPropertyName
*payload++ = 0; // Null terminator
*payload++ = 0;
*payload++= LSBYTE(valuelen); // dwPropertyDataLength
*payload++= MSBYTE(valuelen);
*payload++ = 0;
*payload++ = 0;
payload += convert_to_utf16(payload, propval);
*payload++ = 0; // Null terminator for string
*payload++ = 0;
*payload++ = 0; // Null terminator for array
*payload++ = 0;
return totallen;
}
#endif
static void dfu_workqueue_callback(void *arg)
{
usbdev_dfu_activate_bootloader();
}
static int usbclass_setup(FAR struct usbdevclass_driver_s *driver,
FAR struct usbdev_s *dev,
FAR const struct usb_ctrlreq_s *ctrl,
FAR uint8_t *dataout, size_t outlen)
{
FAR struct dfu_driver_s *priv = (FAR struct dfu_driver_s *)driver;
FAR struct usbdev_req_s *ctrlreq = priv->ctrlreq;
uint16_t value;
uint16_t len;
int ret = -EOPNOTSUPP;
value = GETUINT16(ctrl->value);
len = GETUINT16(ctrl->len);
usbtrace(TRACE_CLASSSETUP, ctrl->req);
uinfo("type=%02x req=%02x value=%04x len=%04x\n",
ctrl->type, ctrl->req, value, len);
if ((ctrl->type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD)
{
if (ctrl->req == USB_REQ_GETDESCRIPTOR)
{
if (ctrl->value[1] == USB_DESC_TYPE_CONFIG)
{
ret = usbclass_mkcfgdesc(ctrlreq->buf, &priv->devinfo);
}
else if (ctrl->value[1] == USB_DESC_TYPE_STRING)
{
ret = usbclass_mkstrdesc(ctrl->value[0], (struct usb_strdesc_s *)ctrlreq->buf);
}
}
else if (ctrl->req == USB_REQ_SETCONFIGURATION)
{
return 0; // Composite driver will send the reply
}
else if (ctrl->req == USB_REQ_SETINTERFACE)
{
// Only one alternate setting (0) is supported
if (value == 0)
{
ret = 0;
}
}
else if (ctrl->req == USB_REQ_GETINTERFACE)
{
*(FAR uint8_t *) ctrlreq->buf = 0;
ret = 1;
}
}
else if ((ctrl->type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_CLASS)
{
if (ctrl->req == USB_REQ_DFU_DETACH)
{
// Execute the bootloader activation through work queue, so that we can send
// the USB reply packet first.
work_queue(HPWORK, &priv->work_item, dfu_workqueue_callback, NULL, 1);
ret = 0;
}
else if (ctrl->req == USB_REQ_DFU_GETSTATUS)
{
/* Respond with APP_IDLE status */
FAR struct dfu_getstatus_response_s *response = (FAR struct dfu_getstatus_response_s*)ctrlreq->buf;
memset(response, 0, sizeof(struct dfu_getstatus_response_s));
ret = sizeof(struct dfu_getstatus_response_s);
}
}
#ifdef CONFIG_DFU_MSFT_OS_DESCRIPTORS
else if (ctrl->req == USB_REQ_GETMSFTOSDESCRIPTOR)
{
ret = dfu_make_msft_extprop_desc(ctrlreq->buf);
}
#endif
/* Respond to the setup command if data was returned. On an error return
* value (ret < 0), the USB driver will stall.
*/
if (ret >= 0)
{
ctrlreq->len = (len < ret) ? len : ret;
ctrlreq->flags = USBDEV_REQFLAGS_NULLPKT;
ret = composite_ep0submit(driver, dev, ctrlreq);
if (ret < 0)
{
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPRESPQ), (uint16_t)-ret);
ctrlreq->result = OK;
}
}
return ret;
}
static int usbclass_bind(FAR struct usbdevclass_driver_s *driver,
FAR struct usbdev_s *dev)
{
FAR struct dfu_driver_s *priv = (FAR struct dfu_driver_s *)driver;
priv->ctrlreq = usbclass_allocreq(dev->ep0, DFU_MAX_DESCRIPTOR_LEN);
if (priv->ctrlreq == NULL)
{
usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_ALLOCCTRLREQ), 0);
return -ENOMEM;
}
priv->ctrlreq->callback = usbclass_ep0incomplete;
return OK;
}
static void usbclass_unbind(FAR struct usbdevclass_driver_s *driver,
FAR struct usbdev_s *dev)
{
FAR struct dfu_driver_s *priv = (FAR struct dfu_driver_s *)driver;
if (priv->ctrlreq != NULL)
{
usbclass_freereq(dev->ep0, priv->ctrlreq);
priv->ctrlreq = NULL;
}
}
static void usbclass_disconnect(FAR struct usbdevclass_driver_s *driver,
FAR struct usbdev_s *dev)
{
}
/****************************************************************************
* Name: usbclass_classobject
*
* Description:
* Allocate memory for the RNDIS driver class object
*
* Returned Value:
* 0 on success, negative error code on failure.
*
****************************************************************************/
static int usbclass_classobject(int minor,
FAR struct usbdev_devinfo_s *devinfo,
FAR struct usbdevclass_driver_s **classdev)
{
FAR struct dfu_driver_s *alloc;
alloc = kmm_zalloc(sizeof(struct dfu_driver_s));
if (!alloc)
{
return -ENOMEM;
}
*classdev = &alloc->drvr;
alloc->drvr.speed = USB_SPEED_FULL;
alloc->drvr.ops = &g_dfu_driverops;
return OK;
}
/****************************************************************************
* Name: usbclass_uninitialize
*
* Description:
* Free allocated memory
*
* Returned Value:
* 0 on success, negative error code on failure.
*
****************************************************************************/
static void usbclass_uninitialize(FAR struct usbdevclass_driver_s *classdev)
{
kmm_free(classdev);
}
/****************************************************************************
* Public Functions
****************************************************************************/
void usbdev_dfu_get_composite_devdesc(struct composite_devdesc_s *dev)
{
memset(dev, 0, sizeof(struct composite_devdesc_s));
dev->mkconfdesc = usbclass_mkcfgdesc;
dev->mkstrdesc = usbclass_mkstrdesc;
dev->classobject = usbclass_classobject;
dev->uninitialize = usbclass_uninitialize;
dev->nconfigs = 1;
dev->configid = 0;
dev->cfgdescsize = sizeof(g_dfu_cfgdesc);
dev->devinfo.ninterfaces = 1;
dev->devinfo.nstrings = 1;
dev->devinfo.nendpoints = 0;
#ifdef CONFIG_DFU_MSFT_OS_DESCRIPTORS
memcpy(dev->msft_compatible_id, "WINUSB", 6);
#endif
}

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