2020-03-02 21:15:01 -06:00
/*
* The MIT License ( MIT )
*
* Copyright ( c ) 2019 Ha Thach ( tinyusb . org )
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE .
*
*/
# include "tusb.h"
# include "usb_descriptors.h"
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
* Same VID / PID with different interface e . g MSC ( first ) , then CDC ( later ) will possibly cause system error on PC .
*
* Auto ProductID layout ' s Bitmap :
* [ MSB ] NET1 : NET0 | VENDOR | MIDI | HID | MSC | CDC [ LSB ]
*/
# define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
# define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
_PID_MAP ( MIDI , 3 ) | _PID_MAP ( VENDOR , 4 ) | _PID_MAP ( NET , 5 ) )
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t const desc_device =
{
. bLength = sizeof ( tusb_desc_device_t ) ,
. bDescriptorType = TUSB_DESC_DEVICE ,
. bcdUSB = 0x0200 ,
. bDeviceClass = TUSB_CLASS_UNSPECIFIED ,
. bDeviceSubClass = 0 ,
. bDeviceProtocol = 0 ,
. bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE ,
. idVendor = 0xCafe ,
. idProduct = USB_PID ,
. bcdDevice = 0x0100 ,
. iManufacturer = 0x01 ,
. iProduct = 0x02 ,
. iSerialNumber = 0x03 ,
. bNumConfigurations = 0x01
} ;
// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
uint8_t const * tud_descriptor_device_cb ( void )
{
return ( uint8_t const * ) & desc_device ;
}
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
enum
{
ITF_NUM_CDC = 0 ,
ITF_NUM_CDC_DATA ,
ITF_NUM_TOTAL
} ;
enum
{
STR_LANGID = 0 ,
STR_MANUFACTURER ,
STR_PRODUCT ,
STR_ITFNAME ,
STR_MAC ,
} ;
# if CFG_TUD_NET == OPT_NET_ECM
# define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_ECM_DESC_LEN)
# elif CFG_TUD_NET == OPT_NET_RNDIS
# define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_RNDIS_DESC_LEN)
# elif CFG_TUD_NET == OPT_NET_EEM
# define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_EEM_DESC_LEN)
# endif
# if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...
# define EPNUM_CDC 2
# else
# define EPNUM_CDC 2
# endif
uint8_t const desc_configuration [ ] =
{
// Interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR ( ITF_NUM_TOTAL , 0 , CONFIG_TOTAL_LEN , 0 , 100 ) ,
# if CFG_TUD_NET == OPT_NET_ECM
// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size.
TUD_CDC_ECM_DESCRIPTOR ( ITF_NUM_CDC , STR_ITFNAME , STR_MAC , 0x81 , 8 , EPNUM_CDC , 0x80 | EPNUM_CDC , CFG_TUD_NET_ENDPOINT_SIZE , CFG_TUD_NET_MTU ) ,
# elif CFG_TUD_NET == OPT_NET_RNDIS
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_RNDIS_DESCRIPTOR ( ITF_NUM_CDC , STR_ITFNAME , 0x81 , 8 , EPNUM_CDC , 0x80 | EPNUM_CDC , CFG_TUD_NET_ENDPOINT_SIZE ) ,
# elif CFG_TUD_NET == OPT_NET_EEM
// Interface number, description string index, EP data address (out, in) and size.
TUD_CDC_EEM_DESCRIPTOR ( ITF_NUM_CDC , STR_ITFNAME , EPNUM_CDC , 0x80 | EPNUM_CDC , CFG_TUD_NET_ENDPOINT_SIZE ) ,
# endif
} ;
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_descriptor_configuration_cb ( uint8_t index )
{
( void ) index ; // for multiple configurations
return desc_configuration ;
}
//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+
// array of pointer to string descriptors
char const * string_desc_arr [ ] =
{
[ STR_LANGID ] = ( const char [ ] ) { 0x09 , 0x04 } , // supported language is English (0x0409)
[ STR_MANUFACTURER ] = " TinyUSB " , // Manufacturer
[ STR_PRODUCT ] = " TinyUSB Device " , // Product
[ STR_ITFNAME ] = // CDC-ECM Interface
# if CFG_TUD_NET == OPT_NET_ECM
" TinyUSB CDC-ECM " ,
# elif CFG_TUD_NET == OPT_NET_RNDIS
" TinyUSB RNDIS " ,
# elif CFG_TUD_NET == OPT_NET_EEM
" TinyUSB CDC-EEM " ,
# endif
} ;
static uint16_t _desc_str [ 32 ] ;
// Invoked when received GET STRING DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
uint16_t const * tud_descriptor_string_cb ( uint8_t index , uint16_t langid )
{
( void ) langid ;
unsigned chr_count = 0 ;
if ( STR_LANGID = = index )
{
memcpy ( & _desc_str [ 1 ] , string_desc_arr [ 0 ] , 2 ) ;
chr_count = 1 ;
}
else if ( STR_MAC = = index )
{
// Convert MAC address into UTF-16
2020-03-03 10:31:46 -06:00
for ( unsigned i = 0 ; i < sizeof ( tud_network_mac_address ) ; i + + )
2020-03-02 21:15:01 -06:00
{
2020-03-03 10:31:46 -06:00
_desc_str [ 1 + chr_count + + ] = " 0123456789ABCDEF " [ ( tud_network_mac_address [ i ] > > 4 ) & 0xf ] ;
_desc_str [ 1 + chr_count + + ] = " 0123456789ABCDEF " [ ( tud_network_mac_address [ i ] > > 0 ) & 0xf ] ;
2020-03-02 21:15:01 -06:00
}
}
else
{
// Convert ASCII string into UTF-16
if ( ! ( index < sizeof ( string_desc_arr ) / sizeof ( string_desc_arr [ 0 ] ) ) ) return NULL ;
const char * str = string_desc_arr [ index ] ;
// Cap at max char
chr_count = strlen ( str ) ;
if ( chr_count > ( TU_ARRAY_SIZE ( _desc_str ) - 1 ) ) chr_count = TU_ARRAY_SIZE ( _desc_str ) - 1 ;
for ( unsigned i = 0 ; i < chr_count ; i + + )
{
_desc_str [ 1 + i ] = str [ i ] ;
}
}
// first byte is length (including header), second byte is string type
_desc_str [ 0 ] = ( TUSB_DESC_STRING < < 8 ) | ( 2 * chr_count + 2 ) ;
return _desc_str ;
}