nuttx/drivers/usbdev/composite_desc.c
SPRESENSE 021a58d71a usbdev: Add board unique serial string support
iSerialNumber field in the device descriptor can be used to determining the
board when multiple boards connected to the same host. So add feature to change
serial string by board unique ID dynamically.
To use this feature, user must be implement the board_usbdev_serialstr() logic.

refs #13909
2022-01-19 09:25:48 +01:00

280 lines
8.6 KiB
C

/****************************************************************************
* drivers/usbdev/composite_desc.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <debug.h>
#ifdef CONFIG_COMPOSITE_BOARD_SERIALSTR
#include <nuttx/board.h>
#endif
#include <nuttx/usb/usbdev_trace.h>
#include "composite.h"
#ifdef CONFIG_USBDEV_COMPOSITE
/****************************************************************************
* Private Data
****************************************************************************/
/* Device Descriptor */
static const struct usb_devdesc_s g_devdesc =
{
USB_SIZEOF_DEVDESC, /* len */
USB_DESC_TYPE_DEVICE, /* type */
{ /* usb */
LSBYTE(0x0200),
MSBYTE(0x0200)
},
#ifndef CONFIG_COMPOSITE_IAD
USB_CLASS_MISC, /* classid */
2, /* subclass */
1, /* protocol */
#else
USB_CLASS_PER_INTERFACE, /* classid */
0, /* subclass */
0, /* protocol */
#endif
CONFIG_COMPOSITE_EP0MAXPACKET, /* maxpacketsize */
{
LSBYTE(CONFIG_COMPOSITE_VENDORID), /* vendor */
MSBYTE(CONFIG_COMPOSITE_VENDORID)
},
{
LSBYTE(CONFIG_COMPOSITE_PRODUCTID), /* product */
MSBYTE(CONFIG_COMPOSITE_PRODUCTID)
},
{
LSBYTE(CONFIG_COMPOSITE_VERSIONNO), /* device */
MSBYTE(CONFIG_COMPOSITE_VERSIONNO)
},
COMPOSITE_MANUFACTURERSTRID, /* imfgr */
COMPOSITE_PRODUCTSTRID, /* iproduct */
COMPOSITE_SERIALSTRID, /* serno */
COMPOSITE_NCONFIGS /* nconfigs */
};
#ifdef CONFIG_USBDEV_DUALSPEED
static const struct usb_qualdesc_s g_qualdesc =
{
USB_SIZEOF_QUALDESC, /* len */
USB_DESC_TYPE_DEVICEQUALIFIER, /* type */
{ /* usb */
LSBYTE(0x0200),
MSBYTE(0x0200)
},
USB_CLASS_VENDOR_SPEC, /* classid */
0, /* subclass */
0, /* protocol */
CONFIG_COMPOSITE_EP0MAXPACKET, /* mxpacketsize */
COMPOSITE_NCONFIGS, /* nconfigs */
0, /* reserved */
};
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: composite_mkstrdesc
*
* Description:
* Construct a string descriptor
*
****************************************************************************/
int composite_mkstrdesc(uint8_t id, struct usb_strdesc_s *strdesc)
{
const char *str;
int len;
int ndata;
int i;
switch (id)
{
case 0:
{
/* Descriptor 0 is the language id */
strdesc->len = 4;
strdesc->type = USB_DESC_TYPE_STRING;
strdesc->data[0] = LSBYTE(COMPOSITE_STR_LANGUAGE);
strdesc->data[1] = MSBYTE(COMPOSITE_STR_LANGUAGE);
return 4;
}
case COMPOSITE_MANUFACTURERSTRID:
str = g_compvendorstr;
break;
case COMPOSITE_PRODUCTSTRID:
str = g_compproductstr;
break;
case COMPOSITE_SERIALSTRID:
#ifdef CONFIG_COMPOSITE_BOARD_SERIALSTR
str = board_usbdev_serialstr();
#else
str = g_compserialstr;
#endif
break;
case COMPOSITE_CONFIGSTRID:
str = CONFIG_COMPOSITE_CONFIGSTR;
break;
default:
return -EINVAL;
}
/* The string is utf16-le. The poor man's utf-8 to utf16-le
* conversion below will only handle 7-bit en-us ascii
*/
len = strlen(str);
for (i = 0, ndata = 0; i < len; i++, ndata += 2)
{
strdesc->data[ndata] = str[i];
strdesc->data[ndata + 1] = 0;
}
strdesc->len = ndata + 2;
strdesc->type = USB_DESC_TYPE_STRING;
return strdesc->len;
}
/****************************************************************************
* Name: composite_getepdesc
*
* Description:
* Return a pointer to the raw device descriptor
*
****************************************************************************/
FAR const struct usb_devdesc_s *composite_getdevdesc(void)
{
return &g_devdesc;
}
/****************************************************************************
* Name: composite_mkcfgdesc
*
* Description:
* Construct the configuration descriptor
*
****************************************************************************/
#ifdef CONFIG_USBDEV_DUALSPEED
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(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 for the composite device */
/* Fill in the values directly into the buf */
cfgdesc->len = USB_SIZEOF_CFGDESC; /* Descriptor length */
#ifdef CONFIG_USBDEV_DUALSPEED
cfgdesc->type = type; /* Descriptor type */
#else
cfgdesc->type = USB_DESC_TYPE_CONFIG; /* Descriptor type */
#endif
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
*/
total = USB_SIZEOF_CFGDESC;
buf += USB_SIZEOF_CFGDESC;
/* Copy all contained interface descriptors into the buffer too */
for (i = 0; i < priv->ndevices; i++)
{
#ifdef CONFIG_USBDEV_DUALSPEED
len = priv->device[i].compdesc.mkconfdesc(buf,
&priv->device[i].compdesc.devinfo,
speed, type);
total += len;
buf += len;
#else
len = priv->device[i].compdesc.mkconfdesc(buf,
&priv->device[i].compdesc.devinfo);
total += len;
buf += len;
#endif
}
return total;
}
/****************************************************************************
* Name: composite_getqualdesc
*
* Description:
* Return a pointer to the raw qual descriptor
*
****************************************************************************/
#ifdef CONFIG_USBDEV_DUALSPEED
FAR const struct usb_qualdesc_s *composite_getqualdesc(void)
{
return &g_qualdesc;
}
#endif
#endif /* CONFIG_USBDEV_COMPOSITE */