/** ****************************************************************************** * @file usbd_hid.c * @author MCD Application Team * @version V2.2.0 * @date 13-June-2014 * @brief This file provides the HID core functions. * * @verbatim * * =================================================================== * HID Class Description * =================================================================== * This module manages the HID class V1.11 following the "Device Class Definition * for Human Interface Devices (HID) Version 1.11 Jun 27, 2001". * This driver implements the following aspects of the specification: * - The Boot Interface Subclass * - Usage Page : Generic Desktop * - Usage : Vendor * - Collection : Application * * @note In HS mode and when the DMA is used, all variables and data structures * dealing with the DMA during the transaction process should be 32-bit aligned. * * * @endverbatim * ****************************************************************************** * @attention * *

© COPYRIGHT 2014 STMicroelectronics

* * Licensed under MCD-ST Liberty SW License Agreement V2, (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.st.com/software_license_agreement_liberty_v2 * * 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. * ****************************************************************************** */ #include #include "os_io.h" #include "os_helpers.h" #include "os_io_usb.h" /* Includes ------------------------------------------------------------------*/ #include "usbd_hid.h" #include "usbd_hid_impl.h" #include "usbd_ctlreq.h" #include "usbd_core.h" #include "usbd_conf.h" #include "usbd_def.h" #include "os_io_seproxyhal.h" #ifdef HAVE_IO_U2F #include "u2f_transport.h" #include "u2f_impl.h" #endif // HAVE_IO_U2F #ifdef HAVE_USB_CLASS_CCID #include "usbd_ccid_core.h" #endif // HAVE_USB_CLASS_CCID /** @addtogroup STM32_USB_DEVICE_LIBRARY * @{ */ /** @defgroup USBD_HID * @brief usbd core module * @{ */ /** @defgroup USBD_HID_Private_TypesDefinitions * @{ */ /** * @} */ /** @defgroup USBD_HID_Private_Defines * @{ */ /** * @} */ /** @defgroup USBD_HID_Private_Macros * @{ */ /** * @} */ /** @defgroup USBD_HID_Private_FunctionPrototypes * @{ */ /** * @} */ /** @defgroup USBD_HID_Private_Variables * @{ */ #define USBD_LANGID_STRING 0x409 #ifdef HAVE_VID_PID_PROBER #define USBD_VID 0x2581 #define USBD_PID 0xf1d1 static uint8_t const USBD_PRODUCT_FS_STRING[] = { 10*2+2, USB_DESC_TYPE_STRING, 'N', 0, 'a', 0, 'n', 0, 'o', 0, '-', 0, 'U', 0, '2', 0, 'F', 0, '-', 0, 'P', 0, }; #else #define USBD_VID 0x2C97 #if defined(TARGET_BLUE) #define USBD_PID 0x0000 static uint8_t const USBD_PRODUCT_FS_STRING[] = { 4*2+2, USB_DESC_TYPE_STRING, 'B', 0, 'l', 0, 'u', 0, 'e', 0, }; #elif defined(TARGET_NANOS) #ifndef HAVE_LEGACY_PID #define USBD_PID 0x1000 #else // HAVE_LEGACY_PID #define USBD_PID 0x0001 #endif // HAVE_LEGACY_PID static uint8_t const USBD_PRODUCT_FS_STRING[] = { 6*2+2, USB_DESC_TYPE_STRING, 'N', 0, 'a', 0, 'n', 0, 'o', 0, ' ', 0, 'S', 0, }; #elif defined(TARGET_HW2) #ifndef HAVE_LEGACY_PID #define USBD_PID 0x3000 #else // HAVE_LEGACY_PID #define USBD_PID 0x0003 #endif // HAVE_LEGACY_PID static uint8_t const USBD_PRODUCT_FS_STRING[] = { 3*2+2, USB_DESC_TYPE_STRING, 'H', 0, 'W', 0, '2', 0, }; #elif defined(TARGET_NANOX) #ifndef HAVE_LEGACY_PID #define USBD_PID 0x4000 #else // HAVE_LEGACY_PID #define USBD_PID 0x0004 #endif // HAVE_LEGACY_PID static uint8_t const USBD_PRODUCT_FS_STRING[] = { 6*2+2, USB_DESC_TYPE_STRING, 'N', 0, 'a', 0, 'n', 0, 'o', 0, ' ', 0, 'X', 0, }; #elif defined(TARGET_NANOS2) #ifndef HAVE_LEGACY_PID #define USBD_PID 0x5000 #else // HAVE_LEGACY_PID #define USBD_PID 0x0005 #endif // HAVE_LEGACY_PID static uint8_t const USBD_PRODUCT_FS_STRING[] = { 11*2+2, USB_DESC_TYPE_STRING, 'N', 0, 'a', 0, 'n', 0, 'o', 0, ' ', 0, 'S', 0, ' ', 0, 'P', 0, 'l', 0, 'u', 0, 's', 0, }; #else #error unknown TARGET_ID #endif #endif /* USB Standard Device Descriptor */ static uint8_t const USBD_LangIDDesc[]= { USB_LEN_LANGID_STR_DESC, USB_DESC_TYPE_STRING, LOBYTE(USBD_LANGID_STRING), HIBYTE(USBD_LANGID_STRING), }; static uint8_t const USB_SERIAL_STRING[] = { 4*2+2, USB_DESC_TYPE_STRING, '0', 0, '0', 0, '0', 0, '1', 0, }; static uint8_t const USBD_MANUFACTURER_STRING[] = { 6*2+2, USB_DESC_TYPE_STRING, 'L', 0, 'e', 0, 'd', 0, 'g', 0, 'e', 0, 'r', 0, }; #define USBD_INTERFACE_FS_STRING USBD_PRODUCT_FS_STRING #define USBD_CONFIGURATION_FS_STRING USBD_PRODUCT_FS_STRING #ifndef HAVE_USB_HIDKBD static uint8_t const HID_ReportDesc[] = { 0x06, 0xA0, 0xFF, // Usage page (vendor defined) 0x09, 0x01, // Usage ID (vendor defined) 0xA1, 0x01, // Collection (application) // The Input report 0x09, 0x03, // Usage ID - vendor defined 0x15, 0x00, // Logical Minimum (0) 0x26, 0xFF, 0x00, // Logical Maximum (255) 0x75, 0x08, // Report Size (8 bits) 0x95, HID_EPIN_SIZE, // Report Count (64 fields) 0x81, 0x08, // Input (Data, Variable, Absolute) // The Output report 0x09, 0x04, // Usage ID - vendor defined 0x15, 0x00, // Logical Minimum (0) 0x26, 0xFF, 0x00, // Logical Maximum (255) 0x75, 0x08, // Report Size (8 bits) 0x95, HID_EPOUT_SIZE, // Report Count (64 fields) 0x91, 0x08, // Output (Data, Variable, Absolute) 0xC0 }; #else static uint8_t const HID_ReportDesc_kbd[] = { 0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x05, 0x07, 0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01, 0x75, 0x08, 0x81, 0x01, 0x95, 0x05, 0x75, 0x01, 0x05, 0x08, 0x19, 0x01, 0x29, 0x05, 0x91, 0x02, 0x95, 0x01, 0x75, 0x03, 0x91, 0x01, 0x95, 0x06, 0x75, 0x08, 0x15, 0x00, 0x25, 0x65, 0x05, 0x07, 0x19, 0x00, 0x29, 0x65, 0x81, 0x00, 0xC0 }; #endif // HAVE_USB_HIDKBD #ifdef HAVE_IO_U2F static uint8_t const HID_ReportDesc_fido[] = { 0x06, 0xD0, 0xF1, // Usage page (vendor defined) 0x09, 0x01, // Usage ID (vendor defined) 0xA1, 0x01, // Collection (application) // The Input report 0x09, 0x03, // Usage ID - vendor defined 0x15, 0x00, // Logical Minimum (0) 0x26, 0xFF, 0x00, // Logical Maximum (255) 0x75, 0x08, // Report Size (8 bits) 0x95, U2F_EPIN_SIZE, // Report Count (64 fields) 0x81, 0x08, // Input (Data, Variable, Absolute) // The Output report 0x09, 0x04, // Usage ID - vendor defined 0x15, 0x00, // Logical Minimum (0) 0x26, 0xFF, 0x00, // Logical Maximum (255) 0x75, 0x08, // Report Size (8 bits) 0x95, U2F_EPOUT_SIZE, // Report Count (64 fields) 0x91, 0x08, // Output (Data, Variable, Absolute) 0xC0 }; #endif // HAVE_IO_U2F #define ARRAY_U2LE(l) (l)&0xFF, (l)>>8 /* USB HID device Configuration Descriptor */ static __ALIGN_BEGIN uint8_t const USBD_CfgDesc[] __ALIGN_END = { 0x09, /* bLength: Configuration Descriptor size */ USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */ ARRAY_U2LE(0x9 /* wTotalLength: Bytes returned */ +0x9+0x9+0x7+0x7 #ifdef HAVE_IO_U2F +0x9+0x9+0x7+0x7 #endif // HAVE_IO_U2F #ifdef HAVE_USB_CLASS_CCID +0x9+0x36+0x7+0x7 #endif // HAVE_USB_CLASS_CCID #ifdef HAVE_WEBUSB +0x9+0x7+0x7 #endif // HAVE_WEBUSB ), 1 #ifdef HAVE_IO_U2F +1 #endif // HAVE_IO_U2F #ifdef HAVE_USB_CLASS_CCID +1 #endif // HAVE_USB_CLASS_CCID #ifdef HAVE_WEBUSB +1 #endif // HAVE_WEBUSB , /*bNumInterfaces */ 0x01, /*bConfigurationValue: Configuration value*/ USBD_IDX_PRODUCT_STR, /*iConfiguration: Index of string descriptor describing the configuration*/ 0xC0, /*bmAttributes: bus powered */ 0x32, /*MaxPower 100 mA: this current is used for detecting Vbus*/ #ifndef HAVE_USB_HIDKBD /* HIDGEN ################################################################################################ */ /************** Descriptor of KBD HID interface ****************/ 0x09, /*bLength: Interface Descriptor size*/ USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/ HID_INTF, /*bInterfaceNumber: Number of Interface*/ 0x00, /*bAlternateSetting: Alternate setting*/ 0x02, /*bNumEndpoints*/ 0x03, /*bInterfaceClass: HID*/ 0x00, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/ 0x00, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/ USBD_IDX_PRODUCT_STR, /*iInterface: Index of string descriptor*/ /******************** Descriptor of HID *************************/ 0x09, /*bLength: HID Descriptor size*/ HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/ 0x11, /*bHIDUSTOM_HID: HID Class Spec release number*/ 0x01, 0x00, /*bCountryCode: Hardware target country*/ 0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/ 0x22, /*bDescriptorType*/ sizeof(HID_ReportDesc),/*wItemLength: Total length of Report descriptor*/ 0x00, /******************** Descriptor of Custom HID endpoints ********************/ 0x07, /*bLength: Endpoint Descriptor size*/ USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/ HID_EPIN_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/ 0x03, /*bmAttributes: Interrupt endpoint*/ HID_EPIN_SIZE, /*wMaxPacketSize: 2 Byte max */ 0x00, 0x01, /*bInterval: Polling Interval (20 ms)*/ 0x07, /* bLength: Endpoint Descriptor size */ USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: */ HID_EPOUT_ADDR, /*bEndpointAddress: Endpoint Address (OUT)*/ 0x03, /* bmAttributes: Interrupt endpoint */ HID_EPOUT_SIZE, /* wMaxPacketSize: 2 Bytes max */ 0x00, 0x01, /* bInterval: Polling Interval (20 ms) */ #else /* HIDKBD ################################################################################################ */ /************** Descriptor of KBD HID interface ****************/ 0x09, /*bLength: Interface Descriptor size*/ USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/ 0x00, /*bInterfaceNumber: Number of Interface*/ 0x00, /*bAlternateSetting: Alternate setting*/ 0x02, /*bNumEndpoints*/ 0x03, /*bInterfaceClass: HID*/ 0x01, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/ 0x01, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/ USBD_IDX_PRODUCT_STR, /*iInterface: Index of string descriptor*/ /******************** Descriptor of HID *************************/ 0x09, /*bLength: HID Descriptor size*/ HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/ 0x11, /*bHIDUSTOM_HID: HID Class Spec release number*/ 0x01, 0x21, /*bCountryCode: Hardware target country*/ // 0x21: US, 0x08: FR, 0x0D: ISO Intl 0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/ 0x22, /*bDescriptorType*/ sizeof(HID_ReportDesc_kbd),/*wItemLength: Total length of Report descriptor*/ 0x00, /******************** Descriptor of Custom HID endpoints ********************/ 0x07, /*bLength: Endpoint Descriptor size*/ USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/ HID_EPIN_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/ 0x03, /*bmAttributes: Interrupt endpoint*/ 8, /*wMaxPacketSize: */ 0x00, 0x01, /*bInterval: Polling Interval */ 0x07, /* bLength: Endpoint Descriptor size */ USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: */ HID_EPOUT_ADDR, /*bEndpointAddress: Endpoint Address (OUT)*/ 0x03, /* bmAttributes: Interrupt endpoint */ 8, /* wMaxPacketSize: */ 0x00, 0x01, /* bInterval: Polling Interval */ #endif // HAVE_USB_HIDKBD #ifdef HAVE_IO_U2F /* HID FIDO ################################################################################################ */ /************** Descriptor of HID FIDO interface ****************/ 0x09, /*bLength: Interface Descriptor size*/ USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/ U2F_INTF, /*bInterfaceNumber: Number of Interface*/ 0x00, /*bAlternateSetting: Alternate setting*/ 0x02, /*bNumEndpoints*/ 0x03, /*bInterfaceClass: HID*/ 0x01, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/ 0x01, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/ USBD_IDX_PRODUCT_STR, /*iInterface: Index of string descriptor*/ /******************** Descriptor of HID *************************/ 0x09, /*bLength: HID Descriptor size*/ HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/ 0x11, /*bHIDUSTOM_HID: HID Class Spec release number*/ 0x01, 0x21, /*bCountryCode: Hardware target country*/ // 0x21: US, 0x08: FR, 0x0D: ISO Intl 0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/ 0x22, /*bDescriptorType*/ sizeof(HID_ReportDesc_fido),/*wItemLength: Total length of Report descriptor*/ 0x00, /******************** Descriptor of Custom HID endpoints ********************/ 0x07, /*bLength: Endpoint Descriptor size*/ USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/ U2F_EPIN_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/ 0x03, /*bmAttributes: Interrupt endpoint*/ U2F_EPIN_SIZE, /*wMaxPacketSize: */ 0x00, 0x01, /*bInterval: Polling Interval */ 0x07, /* bLength: Endpoint Descriptor size */ USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: */ U2F_EPOUT_ADDR, /*bEndpointAddress: Endpoint Address (OUT)*/ 0x03, /* bmAttributes: Interrupt endpoint */ U2F_EPOUT_SIZE, /* wMaxPacketSize: */ 0x00, 0x01,/* bInterval: Polling Interval */ #endif // HAVE_IO_U2F #ifdef HAVE_USB_CLASS_CCID /* CCID ################################################################################################ */ /******************** CCID **** interface ********************/ 0x09, /* bLength: Interface Descriptor size */ 0x04, /* bDescriptorType: */ CCID_INTF, /* bInterfaceNumber: Number of Interface */ 0x00, /* bAlternateSetting: Alternate setting */ 0x02, /* bNumEndpoints: endpoints used */ 0x0B, /* bInterfaceClass: user's interface for CCID */ 0x00, /* bInterfaceSubClass : */ 0x00, /* nInterfaceProtocol : None */ 0x05, /* iInterface: */ /******************* CCID class descriptor ********************/ 0x36, /* bLength: CCID Descriptor size */ 0x21, /* bDescriptorType: Functional Descriptor type. */ 0x10, /* bcdCCID(LSB): CCID Class Spec release number (1.00) */ 0x01, /* bcdCCID(MSB) */ 0x00, /* bMaxSlotIndex :highest available slot on this device */ 0x03, /* bVoltageSupport: bit Wise OR for 01h-5.0V 02h-3.0V 04h 1.8V*/ 0x01,0x00,0x00,0x00, /* dwProtocols: 0001h = Protocol T=0 */ 0x10,0x0E,0x00,0x00, /* dwDefaultClock: 3.6Mhz = 3600kHz = 0x0E10, for 4 Mhz the value is (0x00000FA0) : This is used in ETU and waiting time calculations*/ 0x10,0x0E,0x00,0x00, /* dwMaximumClock: Maximum supported ICC clock frequency in KHz. So, 3.6Mhz = 3600kHz = 0x0E10, 4 Mhz (0x00000FA0) : */ 0x00, /* bNumClockSupported : no setting from PC If the value is 00h, the supported clock frequencies are assumed to be the default clock frequency defined by dwDefaultClock and the maximum clock frequency defined by dwMaximumClock */ 0xCD,0x25,0x00,0x00, /* dwDataRate: Default ICC I/O data rate in bps 9677 bps = 0x25CD for example 10752 bps (0x00002A00) */ 0xCD,0x25,0x00,0x00, /* dwMaxDataRate: Maximum supported ICC I/O data rate in bps */ 0x00, /* bNumDataRatesSupported : The number of data rates that are supported by the CCID If the value is 00h, all data rates between the default data rate dwDataRate and the maximum data rate dwMaxDataRate are supported. Dont support GET_CLOCK_FREQUENCIES */ //46 0x00,0x00,0x00,0x00, /* dwMaxIFSD: 0 (T=0 only) */ 0x00,0x00,0x00,0x00, /* dwSynchProtocols */ 0x00,0x00,0x00,0x00, /* dwMechanical: no special characteristics */ 0xBA, 0x06, 0x02, 0x00, //0x38,0x00,EXCHANGE_LEVEL_FEATURE,0x00, /* dwFeatures: clk, baud rate, voltage : automatic */ /* 00000008h Automatic ICC voltage selection 00000010h Automatic ICC clock frequency change 00000020h Automatic baud rate change according to active parameters provided by the Host or self determined 00000100h CCID can set ICC in clock stop mode Only one of the following values may be present to select a level of exchange: 00010000h TPDU level exchanges with CCID 00020000h Short APDU level exchange with CCID 00040000h Short and Extended APDU level exchange If none of those values : character level of exchange*/ 0x0F,0x01,0x00,0x00, /* dwMaxCCIDMessageLength: Maximum block size + header*/ /* 261 + 10 */ 0x00, /* bClassGetResponse*/ 0x00, /* bClassEnvelope */ 0x00,0x00, /* wLcdLayout : 0000h no LCD. */ 0x00, /* bPINSupport : no PIN verif and modif */ 0x01, /* bMaxCCIDBusySlots */ /******************** CCID Endpoints ********************/ 0x07, /*Endpoint descriptor length = 7*/ 0x05, /*Endpoint descriptor type */ CCID_BULK_IN_EP, /*Endpoint address (IN, address 1) */ 0x02, /*Bulk endpoint type */ LOBYTE(CCID_BULK_EPIN_SIZE), HIBYTE(CCID_BULK_EPIN_SIZE), 0x00, /*Polling interval in milliseconds */ 0x07, /*Endpoint descriptor length = 7 */ 0x05, /*Endpoint descriptor type */ CCID_BULK_OUT_EP, /*Endpoint address (OUT, address 1) */ 0x02, /*Bulk endpoint type */ LOBYTE(CCID_BULK_EPOUT_SIZE), HIBYTE(CCID_BULK_EPOUT_SIZE), 0x00, /*Polling interval in milliseconds*/ #endif // HAVE_USB_CLASS_CCID #ifdef HAVE_WEBUSB /* WEBUSB ################################################################################################ */ /************** Descriptor of WEBUSB interface ****************/ 0x09, /*bLength: Interface Descriptor size*/ USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/ WEBUSB_INTF, /*bInterfaceNumber: Number of Interface*/ 0x00, /*bAlternateSetting: Alternate setting*/ 0x02, /*bNumEndpoints*/ 0xFF, /*bInterfaceClass: WINUSB*/ 0xFF, /*bInterfaceSubClass : WINUSB*/ 0xFF, /*nInterfaceProtocol : WINUSB*/ USBD_IDX_PRODUCT_STR, /*iInterface: Index of string descriptor*/ /******************** Descriptor of endpoints ********************/ 0x07, /*bLength: Endpoint Descriptor size*/ USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/ WEBUSB_EPIN_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/ 0x03, /*bmAttributes: Interrupt endpoint*/ WEBUSB_EPIN_SIZE, /*wMaxPacketSize: */ 0x00, 0x01, /*bInterval: Polling Interval */ 0x07, /* bLength: Endpoint Descriptor size */ USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: */ WEBUSB_EPOUT_ADDR, /*bEndpointAddress: Endpoint Address (OUT)*/ 0x03, /* bmAttributes: Interrupt endpoint */ WEBUSB_EPOUT_SIZE, /* wMaxPacketSize: */ 0x00, 0x01,/* bInterval: Polling Interval */ #endif // HAVE_WEBUSB } ; #ifdef HAVE_IO_U2F /* USB HID device Configuration Descriptor */ __ALIGN_BEGIN uint8_t const USBD_HID_Desc_fido[] __ALIGN_END = { /******************** Descriptor of HID *************************/ 0x09, /*bLength: HID Descriptor size*/ HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/ 0x11, /*bHIDUSTOM_HID: HID Class Spec release number*/ 0x01, 0x21, /*bCountryCode: Hardware target country*/ // 0x21: US, 0x08: FR, 0x0D: ISO Intl 0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/ 0x22, /*bDescriptorType*/ sizeof(HID_ReportDesc_fido),/*wItemLength: Total length of Report descriptor*/ 0x00, }; #endif // HAVE_IO_U2F #ifndef HAVE_USB_HIDKBD /* USB HID device Configuration Descriptor */ __ALIGN_BEGIN uint8_t const USBD_HID_Desc[] __ALIGN_END = { /* 18 */ 0x09, /*bLength: HID Descriptor size*/ HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/ 0x11, /*bHIDUSTOM_HID: HID Class Spec release number*/ 0x01, 0x00, /*bCountryCode: Hardware target country*/ 0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/ 0x22, /*bDescriptorType*/ sizeof(HID_ReportDesc),/*wItemLength: Total length of Report descriptor*/ 0x00, }; #else /* USB HID device Configuration Descriptor */ __ALIGN_BEGIN uint8_t const USBD_HID_Desc_kbd[] __ALIGN_END = { /******************** Descriptor of HID *************************/ 0x09, /*bLength: HID Descriptor size*/ HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/ 0x11, /*bHIDUSTOM_HID: HID Class Spec release number*/ 0x01, 0x21, /*bCountryCode: Hardware target country*/ // 0x21: US, 0x08: FR, 0x0D: ISO Intl 0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/ 0x22, /*bDescriptorType*/ sizeof(HID_ReportDesc_kbd),/*wItemLength: Total length of Report descriptor*/ 0x00, }; #endif // HAVE_USB_HIDKBD /* USB Standard Device Descriptor */ static __ALIGN_BEGIN uint8_t const USBD_DeviceQualifierDesc[] __ALIGN_END = { USB_LEN_DEV_QUALIFIER_DESC, USB_DESC_TYPE_DEVICE_QUALIFIER, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, }; /* USB Standard Device Descriptor */ static uint8_t const USBD_DeviceDesc[]= { 0x12, /* bLength */ USB_DESC_TYPE_DEVICE, /* bDescriptorType */ #ifdef HAVE_WEBUSB 0x10, /* bcdUSB */ #else // HAVE_WEBUSB 0x00, /* bcdUSB */ #endif // HAVE_WEBUSB 0x02, 0x00, /* bDeviceClass */ 0x00, /* bDeviceSubClass */ 0x00, /* bDeviceProtocol */ USB_MAX_EP0_SIZE, /* bMaxPacketSize */ LOBYTE(USBD_VID), /* idVendor */ HIBYTE(USBD_VID), /* idVendor */ #if defined(HAVE_VID_PID_PROBER) || defined(HAVE_LEGACY_PID) LOBYTE(USBD_PID), /* idProduct */ #else // HAVE_VID_PID_PROBER || defined(HAVE_LEGACY_PID) LOBYTE(USBD_PID #ifndef HAVE_USB_HIDKBD | 0x01 #else | 0x02 #endif #ifdef HAVE_IO_U2F | 0x04 #endif // HAVE_IO_U2F #ifdef HAVE_USB_CLASS_CCID | 0x08 #endif // HAVE_USB_CLASS_CCID #ifdef HAVE_WEBUSB | 0x10 #endif // HAVE_WEBUSB ), #endif // HAVE_VID_PID_PROBER || HAVE_LEGACY_PID HIBYTE(USBD_PID), /* idProduct */ // Change this ID to make windows WINUSB/WEBUSB reenumerate when the // descriptor changes and the PID/VID are not changed. 0x01, /* bcdDevice rel. 2.01 */ 0x02, USBD_IDX_MFC_STR, /* Index of manufacturer string */ USBD_IDX_PRODUCT_STR, /* Index of product string */ USBD_IDX_SERIAL_STR, /* Index of serial number string */ 1 /* bNumConfigurations */ }; /* USB_DeviceDescriptor */ /** * @brief Returns the device descriptor. * @param speed: Current device speed * @param length: Pointer to data length variable * @retval Pointer to descriptor buffer */ static uint8_t *USBD_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) { UNUSED(speed); *length = sizeof(USBD_DeviceDesc); return (uint8_t*)USBD_DeviceDesc; } /** * @brief Returns the LangID string descriptor. * @param speed: Current device speed * @param length: Pointer to data length variable * @retval Pointer to descriptor buffer */ static uint8_t *USBD_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) { UNUSED(speed); *length = sizeof(USBD_LangIDDesc); return (uint8_t*)USBD_LangIDDesc; } /** * @brief Returns the product string descriptor. * @param speed: Current device speed * @param length: Pointer to data length variable * @retval Pointer to descriptor buffer */ static uint8_t *USBD_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) { UNUSED(speed); *length = sizeof(USBD_PRODUCT_FS_STRING); return (uint8_t*)USBD_PRODUCT_FS_STRING; } /** * @brief Returns the manufacturer string descriptor. * @param speed: Current device speed * @param length: Pointer to data length variable * @retval Pointer to descriptor buffer */ static uint8_t *USBD_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) { UNUSED(speed); *length = sizeof(USBD_MANUFACTURER_STRING); return (uint8_t*)USBD_MANUFACTURER_STRING; } /** * @brief Returns the serial number string descriptor. * @param speed: Current device speed * @param length: Pointer to data length variable * @retval Pointer to descriptor buffer */ static uint8_t *USBD_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) { UNUSED(speed); *length = sizeof(USB_SERIAL_STRING); return (uint8_t*)USB_SERIAL_STRING; } /** * @brief Returns the configuration string descriptor. * @param speed: Current device speed * @param length: Pointer to data length variable * @retval Pointer to descriptor buffer */ static uint8_t *USBD_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) { UNUSED(speed); *length = sizeof(USBD_CONFIGURATION_FS_STRING); return (uint8_t*)USBD_CONFIGURATION_FS_STRING; } /** * @brief Returns the interface string descriptor. * @param speed: Current device speed * @param length: Pointer to data length variable * @retval Pointer to descriptor buffer */ static uint8_t *USBD_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) { UNUSED(speed); *length = sizeof(USBD_INTERFACE_FS_STRING); return (uint8_t*)USBD_INTERFACE_FS_STRING; } /** * @brief DeviceQualifierDescriptor * return Device Qualifier descriptor * @param length : pointer data length * @retval pointer to descriptor buffer */ static uint8_t *USBD_GetDeviceQualifierDesc_impl (uint16_t *length) { *length = sizeof (USBD_DeviceQualifierDesc); return (uint8_t*)USBD_DeviceQualifierDesc; } /** * @brief USBD_CUSTOM_HID_GetCfgDesc * return configuration descriptor * @param speed : current device speed * @param length : pointer data length * @retval pointer to descriptor buffer */ static uint8_t *USBD_GetCfgDesc_impl (uint16_t *length) { *length = sizeof (USBD_CfgDesc); return (uint8_t*)USBD_CfgDesc; } uint8_t* USBD_HID_GetHidDescriptor_impl(uint16_t* len) { switch (USBD_Device.request.wIndex&0xFF) { #ifdef HAVE_IO_U2F case U2F_INTF: *len = sizeof(USBD_HID_Desc_fido); return (uint8_t*)USBD_HID_Desc_fido; #endif // HAVE_IO_U2F #ifndef HAVE_USB_HIDKBD case HID_INTF: *len = sizeof(USBD_HID_Desc); return (uint8_t*)USBD_HID_Desc; #else case HID_INTF: *len = sizeof(USBD_HID_Desc_kbd); return (uint8_t*)USBD_HID_Desc_kbd; #endif // HAVE_USB_HIDKBD } *len = 0; return 0; } uint8_t* USBD_HID_GetReportDescriptor_impl(uint16_t* len) { switch (USBD_Device.request.wIndex&0xFF) { #ifdef HAVE_IO_U2F case U2F_INTF: // very dirty work due to lack of callback when USB_HID_Init is called USBD_LL_OpenEP(&USBD_Device, U2F_EPIN_ADDR, USBD_EP_TYPE_INTR, U2F_EPIN_SIZE); USBD_LL_OpenEP(&USBD_Device, U2F_EPOUT_ADDR, USBD_EP_TYPE_INTR, U2F_EPOUT_SIZE); /* Prepare Out endpoint to receive 1st packet */ USBD_LL_PrepareReceive(&USBD_Device, U2F_EPOUT_ADDR, U2F_EPOUT_SIZE); *len = sizeof(HID_ReportDesc_fido); return (uint8_t*)HID_ReportDesc_fido; #endif // HAVE_IO_U2F #ifndef HAVE_USB_HIDKBD case HID_INTF: *len = sizeof(HID_ReportDesc); return (uint8_t*)HID_ReportDesc; #else case HID_INTF: *len = sizeof(HID_ReportDesc_kbd); return (uint8_t*)HID_ReportDesc_kbd; #endif // HAVE_USB_HIDKBD } *len = 0; return 0; } /** * @} */ /** * @brief USBD_HID_DataOut * handle data OUT Stage * @param pdev: device instance * @param epnum: endpoint index * @retval status * * This function is the default behavior for our implementation when data are sent over the out hid endpoint */ #ifdef HAVE_IO_U2F /** * @brief USBD_HID_Init * Initialize the HID interface * @param pdev: device instance * @param cfgidx: Configuration index * @retval status */ uint8_t USBD_U2F_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx) { UNUSED(cfgidx); /* Open EP IN */ USBD_LL_OpenEP(pdev, U2F_EPIN_ADDR, USBD_EP_TYPE_INTR, U2F_EPIN_SIZE); /* Open EP OUT */ USBD_LL_OpenEP(pdev, U2F_EPOUT_ADDR, USBD_EP_TYPE_INTR, U2F_EPOUT_SIZE); /* Prepare Out endpoint to receive 1st packet */ USBD_LL_PrepareReceive(pdev, U2F_EPOUT_ADDR, U2F_EPOUT_SIZE); return USBD_OK; } uint8_t USBD_U2F_DataIn_impl (USBD_HandleTypeDef *pdev, uint8_t epnum) { UNUSED(pdev); // only the data hid endpoint will receive data switch (epnum) { // FIDO endpoint case (U2F_EPIN_ADDR&0x7F): // advance the u2f sending machine state u2f_transport_sent(&G_io_u2f, U2F_MEDIA_USB); break; } return USBD_OK; } uint8_t USBD_U2F_DataOut_impl (USBD_HandleTypeDef *pdev, uint8_t epnum, uint8_t* buffer) { switch (epnum) { // FIDO endpoint case (U2F_EPOUT_ADDR&0x7F): USBD_LL_PrepareReceive(pdev, U2F_EPOUT_ADDR , U2F_EPOUT_SIZE); u2f_transport_received(&G_io_u2f, buffer, io_seproxyhal_get_ep_rx_size(U2F_EPOUT_ADDR), U2F_MEDIA_USB); break; } return USBD_OK; } #endif // HAVE_IO_U2F uint8_t USBD_HID_DataIn_impl (USBD_HandleTypeDef *pdev, uint8_t epnum) { UNUSED(pdev); switch (epnum) { // HID gen endpoint case (HID_EPIN_ADDR&0x7F): io_usb_hid_sent(io_usb_send_apdu_data); break; } return USBD_OK; } uint8_t USBD_HID_DataOut_impl (USBD_HandleTypeDef *pdev, uint8_t epnum, uint8_t* buffer, apdu_buffer_t * apdu_buf) { // only the data hid endpoint will receive data switch (epnum) { // HID gen endpoint case (HID_EPOUT_ADDR&0x7F): // prepare receiving the next chunk (masked time) USBD_LL_PrepareReceive(pdev, HID_EPOUT_ADDR , HID_EPOUT_SIZE); #ifndef HAVE_USB_HIDKBD // avoid troubles when an apdu has not been replied yet if (G_io_app.apdu_media == IO_APDU_MEDIA_NONE) { // add to the hid transport switch(io_usb_hid_receive(io_usb_send_apdu_data, buffer, io_seproxyhal_get_ep_rx_size(HID_EPOUT_ADDR), apdu_buf)) { default: break; case IO_USB_APDU_RECEIVED: G_io_app.apdu_media = IO_APDU_MEDIA_USB_HID; // for application code G_io_app.apdu_state = APDU_USB_HID; // for next call to io_exchange G_io_app.apdu_length = G_io_usb_hid_total_length; break; } } #endif // HAVE_USB_HIDKBD break; } return USBD_OK; } #ifdef HAVE_WEBUSB uint8_t USBD_WEBUSB_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx) { UNUSED(cfgidx); /* Open EP IN */ USBD_LL_OpenEP(pdev, WEBUSB_EPIN_ADDR, USBD_EP_TYPE_INTR, WEBUSB_EPIN_SIZE); /* Open EP OUT */ USBD_LL_OpenEP(pdev, WEBUSB_EPOUT_ADDR, USBD_EP_TYPE_INTR, WEBUSB_EPOUT_SIZE); /* Prepare Out endpoint to receive 1st packet */ USBD_LL_PrepareReceive(pdev, WEBUSB_EPOUT_ADDR, WEBUSB_EPOUT_SIZE); return USBD_OK; } uint8_t USBD_WEBUSB_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx) { UNUSED(pdev); UNUSED(cfgidx); return USBD_OK; } uint8_t USBD_WEBUSB_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) { UNUSED(pdev); UNUSED(req); return USBD_OK; } uint8_t USBD_WEBUSB_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum) { UNUSED(pdev); switch (epnum) { // HID gen endpoint case (WEBUSB_EPIN_ADDR&0x7F): io_usb_hid_sent(io_usb_send_apdu_data_ep0x83); break; } return USBD_OK; } uint8_t USBD_WEBUSB_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum, uint8_t* buffer) { // only the data hid endpoint will receive data switch (epnum) { // HID gen endpoint case (WEBUSB_EPOUT_ADDR&0x7F): // prepare receiving the next chunk (masked time) USBD_LL_PrepareReceive(pdev, WEBUSB_EPOUT_ADDR, WEBUSB_EPOUT_SIZE); // avoid troubles when an apdu has not been replied yet if (G_io_app.apdu_media == IO_APDU_MEDIA_NONE) { // add to the hid transport switch(io_usb_hid_receive(io_usb_send_apdu_data_ep0x83, buffer, io_seproxyhal_get_ep_rx_size(WEBUSB_EPOUT_ADDR))) { default: break; case IO_USB_APDU_RECEIVED: G_io_app.apdu_media = IO_APDU_MEDIA_USB_WEBUSB; // for application code G_io_app.apdu_state = APDU_USB_WEBUSB; // for next call to io_exchange G_io_app.apdu_length = G_io_usb_hid_total_length; break; } } break; } return USBD_OK; } // arbitrary vendor choosen #define WEBUSB_VENDOR_CODE 0x1E // from https://wicg.github.io/webusb/#webusb-platform-capability-descriptor // see also this (for endianness explanation) // https://github.com/WICG/webusb/issues/115#issuecomment-352206549 #define WEBUSB_UUID 0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47,0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65 #define WEBUSB_REQ_GET_URL 0x02 #define WEBUSB_DT_DESCRIPTOR_SET_HEADER 0 #define WEBUSB_DT_CONFIGURATION_SUBSET_HEADER 1 #define WEBUSB_DT_FUNCTION_SUBSET_HEADER 2 #define WEBUSB_DT_URL 3 #define WEBUSB_URL_SCHEME_HTTP 0 #define WEBUSB_URL_SCHEME_HTTPS 1 #define WEBUSB_URL_SCHEME_CUSTOM 255 unsigned char const C_webusb_url_descriptor[] = { // bLength 3 + WEBUSB_URL_SIZE_B, // bDescriptorType WEBUSB_DT_URL, // bScheme WEBUSB_URL_SCHEME_HTTPS, // URL WEBUSB_URL }; /* USB 3.1 Descriptor Types - Table 9-6 */ #define USB_DT_BOS 15 #define USB_DT_DEVICE_CAPABILITY 16 #define USB_DT_BOS_SIZE 5 /* USB Device Capability Types - USB 3.1 Table 9-14 */ #define USB_DC_PLATFORM 5 #define MS_OS_20_DESCRIPTOR_LENGTH (0xb2) #define WINUSB_VENDOR_CODE 0x77 unsigned char const C_usb_bos[] = { USB_DT_BOS_SIZE, // bLength (5) USB_DT_BOS, // bDescriptorType 0x39, 0x00, // wTotalLength 2, //bNumberDeviceCapabilities // capability descriptor 8+16, // bLength USB_DT_DEVICE_CAPABILITY, // bDescriptorType USB_DC_PLATFORM, // bDevCapability 0, // bReserved WEBUSB_UUID, // UUID[16] 0x00, // bcdVersion 0x01, WEBUSB_VENDOR_CODE, // bVencordCode #if WEBUSB_URL_SIZE_B > 0 1, // iLandingPage #else // WEBUSB_URL_SIZE_B 0, // iLandingPage, no url to retrieve #endif // WEBUSB_URL_SIZE_B // Microsoft OS 2.0 Platform Capability Descriptor 0x1C, // Descriptor size (28 bytes) 0x10, // Descriptor type (Device Capability) 0x05, // Capability type (Platform) 0x00, // Reserved // MS OS 2.0 Platform Capability ID (D8DD60DF-4589-4CC7-9CD2-659D9E648A9F) 0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, 0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F, 0x00, 0x00, 0x03, 0x06, // Windows version (8.1) (0x06030000) MS_OS_20_DESCRIPTOR_LENGTH, 0x00, WINUSB_VENDOR_CODE, // Vendor-assigned bMS_VendorCode 0x00 // Doesn’t support alternate enumeration }; #endif // HAVE_WEBUSB static uint8_t *USBD_BOSDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) { UNUSED(speed); #ifdef HAVE_WEBUSB *length = sizeof(C_usb_bos); return (uint8_t*)C_usb_bos; #else *length = 0; return NULL; #endif } /** @defgroup USBD_HID_Private_Functions * @{ */ // note: how core lib usb calls the hid class USBD_DescriptorsTypeDef const HID_Desc = { USBD_DeviceDescriptor, USBD_LangIDStrDescriptor, USBD_ManufacturerStrDescriptor, USBD_ProductStrDescriptor, USBD_SerialStrDescriptor, USBD_ConfigStrDescriptor, USBD_InterfaceStrDescriptor, USBD_BOSDescriptor, }; #ifdef HAVE_IO_U2F static USBD_ClassTypeDef const USBD_U2F = { USBD_U2F_Init, USBD_HID_DeInit, USBD_HID_Setup, NULL, /*EP0_TxSent*/ NULL, /*EP0_RxReady*/ /* STATUS STAGE IN */ USBD_U2F_DataIn_impl, /*DataIn*/ USBD_U2F_DataOut_impl, /*DataOut*/ NULL, /*SOF */ NULL, NULL, USBD_GetCfgDesc_impl, USBD_GetCfgDesc_impl, USBD_GetCfgDesc_impl, USBD_GetDeviceQualifierDesc_impl, }; #endif // HAVE_IO_U2F static USBD_ClassTypeDef const USBD_HID = { USBD_HID_Init, USBD_HID_DeInit, USBD_HID_Setup, NULL, /*EP0_TxSent*/ NULL, /*EP0_RxReady*/ /* STATUS STAGE IN */ USBD_HID_DataIn_impl, /*DataIn*/ USBD_HID_DataOut_impl, /*DataOut*/ NULL, /*SOF */ NULL, NULL, USBD_GetCfgDesc_impl, USBD_GetCfgDesc_impl, USBD_GetCfgDesc_impl, USBD_GetDeviceQualifierDesc_impl, }; #ifdef HAVE_WEBUSB static const unsigned char C_winusb_string_descriptor[] = { // bLength 0x12, // bDescriptorType USB_DESC_TYPE_STRING, // wData 'M', 0x00, 'S', 0x00, 'F', 0x00, 'T', 0x00, '1', 0x00, '0', 0x00, '0', 0x00, WINUSB_VENDOR_CODE, 0x00, // MSFT100 }; // Microsoft OS 2.0 descriptor wIndex values #define MS_OS_20_DESCRIPTOR_INDEX 0x07 // Microsoft OS 2.0 descriptor types #define MS_OS_20_SUBSET_HEADER_CONFIGURATION 0x01 #define MS_OS_20_SUBSET_HEADER_FUNCTION 0x02 #define MS_OS_20_FEATURE_COMPATIBLE_ID 0x03 #define MS_OS_20_FEATURE_REG_PROPERTY 0x04 static const unsigned char C_winusb_request_descriptor[] = { // Microsoft OS 2.0 descriptor set header (table 10) 0x0A, 0x00, // Descriptor size (10 bytes) 0x00, 0x00, // MS OS 2.0 descriptor set header 0x00, 0x00, 0x03, 0x06, // Windows version (8.1) (0x06030000) MS_OS_20_DESCRIPTOR_LENGTH, 0x00, // Size, MS OS 2.0 descriptor set // Microsoft OS 2.0 configuration subset header 0x08, 0x00, // Descriptor size (8 bytes) MS_OS_20_SUBSET_HEADER_CONFIGURATION, 0x00, // MS OS 2.0 configuration subset header 0x00, // bConfigurationValue 0x00, // Reserved 0xA8, 0x00, // Size, MS OS 2.0 configuration subset // Microsoft OS 2.0 function subset header 0x08, 0x00, // Descriptor size (8 bytes) MS_OS_20_SUBSET_HEADER_FUNCTION, 0x00, // MS OS 2.0 function subset header WEBUSB_INTF, // first Interface impacted by this function 0x00, // Reserved 0xA0, 0x00, // Size, MS OS 2.0 function subset // Microsoft OS 2.0 compatible ID descriptor (table 13) 0x14, 0x00, // wLength MS_OS_20_FEATURE_COMPATIBLE_ID, 0x00, // MS_OS_20_FEATURE_COMPATIBLE_ID 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, //wLength: MS_OS_20_FEATURE_REG_PROPERTY, 0x00, // wDescriptorType: MS_OS_20_FEATURE_REG_PROPERTY: 0x04 (Table 9) 0x07, 0x00, //wPropertyDataType: REG_MULTI_SZ (Table 15) 0x2a, 0x00, //wPropertyNameLength: //bPropertyName: “DeviceInterfaceGUID” 'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00, 'r', 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00, 0x00, 0x00, 0x50, 0x00, // wPropertyDataLength //bPropertyData: “{CE809264-4B24-4E81-A8B2-57ED01D580E1}”. '{', 0x00, 'C', 0x00, 'E', 0x00, '8', 0x00, '0', 0x00, '9', 0x00, '2', 0x00, '6', 0x00, '4', 0x00, '-', 0x00, '4', 0x00, 'B', 0x00, '2', 0x00, '4', 0x00, '-', 0x00, '4', 0x00, 'E', 0x00, '8', 0x00, '1', 0x00, '-', 0x00, 'A', 0x00, '8', 0x00, 'B', 0x00, '2', 0x00, '-', 0x00, '5', 0x00, '7', 0x00, 'E', 0x00, 'D', 0x00, '0', 0x00, '1', 0x00, 'D', 0x00, '5', 0x00, '8', 0x00, '0', 0x00, 'E', 0x00, '1', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00 }; #define WINUSB_GET_COMPATIBLE_ID_FEATURE 0x04 static const unsigned char C_winusb_wcid[] = { // header 0x28, 0x00, 0x00, 0x00, // dwLength 0x00, 0x01, // bcdVersion 0x04, 0x00, // wIndex 0x01, // bNumSections 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved // functions WEBUSB_INTF, // bInterfaceNumber 0x01, // reserved 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, // compatibleId 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // subCompatibleId 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved }; #define WINUSB_GET_EXTENDED_PROPERTIES_OS_FEATURE 0x05 static const unsigned char C_winusb_guid[] = { // header 0x92, 0x00, 0x00, 0x00, // dwLength 0x00, 0x01, // bcdVersion 0x05, 0x00, // wIndex 0x01, 0x00, // wNumFeatures // features 0x88, 0x00, 0x00, 0x00, // dwLength 0x07, 0x00, 0x00, 0x00, // dwPropertyDataType 0x2A, 0x00, // wNameLength 'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00, 'r', 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00, 0x00, 0x00, // .name, unicode nul terminated 0x50, 0x00, 0x00, 0x00, // dwPropertyDataLength // Same as BLE char: 13d63400-2C97-0004-0000-4c6564676572 '{', 0x00, '1', 0x00, '3', 0x00, 'd', 0x00, '6', 0x00, '3', 0x00, '4', 0x00, '0', 0x00, '0', 0x00, '-', 0x00, '2', 0x00, 'C', 0x00, '9', 0x00, '7', 0x00, '-', 0x00, '0', 0x00, '0', 0x00, '0', 0x00, '4', 0x00, '-', 0x00, '0', 0x00, '0', 0x00, '0', 0x00, '0', 0x00, '-', 0x00, '4', 0x00, 'c', 0x00, '6', 0x00, '5', 0x00, '6', 0x00, '4', 0x00, '6', 0x00, '7', 0x00, '6', 0x00, '5', 0x00, '7', 0x00, '2', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00 // propertyData, double unicode nul terminated }; // upon unsupported request, check for webusb request void USBD_CtlError( USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req) { #if WEBUSB_URL_SIZE_B > 0 if ((req->bmRequest & 0x80) && req->bRequest == WEBUSB_VENDOR_CODE && req->wIndex == WEBUSB_REQ_GET_URL // HTTPS url && req->wValue == 1) { // return the URL descriptor USBD_CtlSendData (pdev, (unsigned char*)C_webusb_url_descriptor, MIN(req->wLength, sizeof(C_webusb_url_descriptor))); } else #endif // WEBUSB_URL_SIZE_B // SETUP (LE): 0x80 0x06 0x03 0x77 0x00 0x00 0xXX 0xXX if ((req->bmRequest & 0x80) && req->bRequest == USB_REQ_GET_DESCRIPTOR && (req->wValue>>8) == USB_DESC_TYPE_STRING && (req->wValue & 0xFF) == 0xEE) { USBD_CtlSendData(pdev, (unsigned char*)C_winusb_string_descriptor, MIN(req->wLength, sizeof(C_winusb_string_descriptor))); } // SETUP (LE): 0x80 0x77 0x04 0x00 0x00 0x00 0xXX 0xXX else if ((req->bmRequest & 0x80) && req->bRequest == WINUSB_VENDOR_CODE && req->wIndex == WINUSB_GET_COMPATIBLE_ID_FEATURE) { USBD_CtlSendData(pdev, (unsigned char*)C_winusb_wcid, MIN(req->wLength, sizeof(C_winusb_wcid))); } // SETUP (LE): 0x80 0x77 0x05 0x00 0x00 0x00 0xXX 0xXX else if ((req->bmRequest & 0x80) && req->bRequest == WINUSB_VENDOR_CODE && req->wIndex == WINUSB_GET_EXTENDED_PROPERTIES_OS_FEATURE ) { USBD_CtlSendData(pdev, (unsigned char*)C_winusb_guid, MIN(req->wLength, sizeof(C_winusb_guid))); } // Microsoft OS 2.0 Descriptors for Windows 8.1 and Windows 10 else if ((req->bmRequest & 0x80) && req->bRequest == WINUSB_VENDOR_CODE && req->wIndex == MS_OS_20_DESCRIPTOR_INDEX) { USBD_CtlSendData(pdev, (unsigned char*)C_winusb_request_descriptor, MIN(req->wLength, sizeof(C_winusb_request_descriptor))); } else { USBD_CtlStall(pdev); } } static const USBD_ClassTypeDef USBD_WEBUSB = { USBD_WEBUSB_Init, USBD_WEBUSB_DeInit, USBD_WEBUSB_Setup, NULL, /*EP0_TxSent*/ NULL, /*EP0_RxReady*/ USBD_WEBUSB_DataIn, USBD_WEBUSB_DataOut, NULL, /*SOF */ NULL, /*ISOIn*/ NULL, /*ISOOut*/ USBD_GetCfgDesc_impl, USBD_GetCfgDesc_impl, USBD_GetCfgDesc_impl, USBD_GetDeviceQualifierDesc_impl, }; #endif // HAVE_WEBUSB #ifdef HAVE_USB_CLASS_CCID static const USBD_ClassTypeDef USBD_CCID = { USBD_CCID_Init, USBD_CCID_DeInit, USBD_CCID_Setup, NULL, /*EP0_TxSent*/ NULL, /*EP0_RxReady*/ USBD_CCID_DataIn, USBD_CCID_DataOut, NULL, /*SOF */ NULL, /*ISOIn*/ NULL, /*ISOOut*/ USBD_GetCfgDesc_impl, USBD_GetCfgDesc_impl, USBD_GetCfgDesc_impl, USBD_GetDeviceQualifierDesc_impl, }; uint8_t SC_AnswerToReset (uint8_t voltage, uint8_t* atr_buffer) { UNUSED(voltage); // return the atr length atr_buffer[0] = 0x3B; atr_buffer[1] = 0; return 2; } void SC_Poweroff(void) { // nothing to do ? } uint8_t SC_ExecuteEscape (uint8_t* escapePtr, uint32_t escapeLen, uint8_t* responseBuff, uint16_t* responseLen) { UNUSED(escapePtr); UNUSED(escapeLen); UNUSED(responseBuff); UNUSED(responseLen); // nothing to do ? return 0; } #endif // HAVE_USB_CLASS_CCID void USB_power(unsigned char enabled) { memset(&USBD_Device, 0, sizeof(USBD_Device)); // init timeouts and other global fields memset(G_io_app.usb_ep_xfer_len, 0, sizeof(G_io_app.usb_ep_xfer_len)); memset(G_io_app.usb_ep_timeouts, 0, sizeof(G_io_app.usb_ep_timeouts)); if (enabled) { memset(&USBD_Device, 0, sizeof(USBD_Device)); /* Init Device Library */ USBD_Init(&USBD_Device, (USBD_DescriptorsTypeDef*)&HID_Desc, 0); /* Register the HID class */ USBD_RegisterClassForInterface(HID_INTF, &USBD_Device, (USBD_ClassTypeDef*)&USBD_HID); #ifdef HAVE_IO_U2F USBD_RegisterClassForInterface(U2F_INTF, &USBD_Device, (USBD_ClassTypeDef*)&USBD_U2F); // initialize the U2F tunnel transport u2f_transport_init(&G_io_u2f, G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); #endif // HAVE_IO_U2F #ifdef HAVE_USB_CLASS_CCID USBD_RegisterClassForInterface(CCID_INTF, &USBD_Device, (USBD_ClassTypeDef*)&USBD_CCID); #endif // HAVE_USB_CLASS_CCID #ifdef HAVE_WEBUSB USBD_RegisterClassForInterface(WEBUSB_INTF, &USBD_Device, (USBD_ClassTypeDef*)&USBD_WEBUSB); #endif // HAVE_WEBUSB /* Start Device Process */ USBD_Start(&USBD_Device); } else { USBD_DeInit(&USBD_Device); } } /** * @} */ /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/