diff --git a/fido2/ctap.c b/fido2/ctap.c
index 3ccb9cbf..7730e563 100644
--- a/fido2/ctap.c
+++ b/fido2/ctap.c
@@ -1738,6 +1738,20 @@ uint8_t ctap_cred_mgmt(CborEncoder * encoder, uint8_t * request, int length)
return 0;
}
+uint8_t ctap_solo_kbd(CborEncoder * encoder, uint8_t * request, int length)
+{
+ CTAP_soloKbd KBD;
+ int ret = ctap_parse_solo_kbd(&KBD, request, length);
+ if (ret != 0)
+ {
+ printf2(TAG_ERR,"error, ctap_parse_solo_kbd failed\n");
+ return ret;
+ }
+ dump_hex1(TAG_CTAP, KBD.sequence, KBD.length);
+ ctap_store_kbd(&KBD);
+ return 0;
+}
+
uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
{
CTAP_getAssertion GA;
@@ -2318,6 +2332,10 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
dump_hex1(TAG_DUMP,buf, resp->length);
break;
+ case CTAP_SOLO_KBD:
+ printf1(TAG_CTAP,"CTAP_SOLO_KBD\n");
+ status = ctap_solo_kbd(&encoder, pkt_raw, length);
+ break;
default:
status = CTAP1_ERR_INVALID_COMMAND;
printf2(TAG_ERR,"error, invalid cmd: 0x%02x\n", cmd);
diff --git a/fido2/ctap.h b/fido2/ctap.h
index db98c27b..79f1190e 100644
--- a/fido2/ctap.h
+++ b/fido2/ctap.h
@@ -19,6 +19,7 @@
#define CTAP_CBOR_CRED_MGMT 0x0A
#define CTAP_VENDOR_FIRST 0x40
#define CTAP_CBOR_CRED_MGMT_PRE 0x41
+#define CTAP_SOLO_KBD 0x51
#define CTAP_VENDOR_LAST 0xBF
#define MC_clientDataHash 0x01
@@ -338,6 +339,11 @@ typedef struct
int pinProtocol;
} CTAP_credMgmt;
+typedef struct
+{
+ uint8_t sequence[64];
+ uint8_t length;
+} CTAP_soloKbd;
typedef struct
{
diff --git a/fido2/ctap_parse.c b/fido2/ctap_parse.c
index a6e53f24..4c15b4e3 100644
--- a/fido2/ctap_parse.c
+++ b/fido2/ctap_parse.c
@@ -713,6 +713,28 @@ uint8_t ctap_parse_extensions(CborValue * val, CTAP_extensions * ext)
return 0;
}
+uint8_t ctap_parse_solo_kbd(CTAP_soloKbd * KBD, uint8_t * request, int length)
+{
+ int ret;
+ CborParser parser;
+ CborValue it;
+
+ memset(KBD, 0, sizeof(CTAP_soloKbd));
+ ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
+ check_retr(ret);
+ CborType type = cbor_value_get_type(&it);
+ if (type != CborByteStringType)
+ {
+ printf2(TAG_ERR,"Error, expecting cbor byte string\n");
+ return CTAP2_ERR_CBOR_UNEXPECTED_TYPE;
+ }
+ size_t len = sizeof(KBD->sequence);
+ ret = cbor_value_copy_byte_string(&it, KBD->sequence, &len, NULL);
+ check_ret(ret);
+ KBD->length = len;
+ return ret;
+}
+
uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encoder, uint8_t * request, int length)
{
int ret;
diff --git a/fido2/ctap_parse.h b/fido2/ctap_parse.h
index e0be8071..ac29bac5 100644
--- a/fido2/ctap_parse.h
+++ b/fido2/ctap_parse.h
@@ -38,6 +38,7 @@ uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int
uint8_t ctap_parse_cred_mgmt(CTAP_credMgmt * CM, uint8_t * request, int length);
uint8_t ctap_parse_client_pin(CTAP_clientPin * CP, uint8_t * request, int length);
uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor * cred);
+uint8_t ctap_parse_solo_kbd(CTAP_soloKbd * KBD, uint8_t * request, int length);
#endif
diff --git a/fido2/device.h b/fido2/device.h
index 0c96c732..cce54e23 100644
--- a/fido2/device.h
+++ b/fido2/device.h
@@ -24,7 +24,6 @@ uint32_t millis();
*/
void usbhid_send(uint8_t * msg);
-
/** Reboot / power reset the device.
* **Optional** this is not used for FIDO2, and simply won't do anything if not implemented.
*/
@@ -163,6 +162,8 @@ void ctap_load_rk(int index,CTAP_residentKey * rk);
*/
void ctap_overwrite_rk(int index,CTAP_residentKey * rk);
+void ctap_load_kbd(CTAP_soloKbd * kbd);
+void ctap_store_kbd(CTAP_soloKbd * kbd);
/** Called by HID layer to indicate that a wink behavior should be performed.
* Should not block, and the wink behavior should occur in parallel to FIDO operations.
diff --git a/pc/device.c b/pc/device.c
index 0536bb2d..bbf21160 100644
--- a/pc/device.c
+++ b/pc/device.c
@@ -449,6 +449,11 @@ void ctap_store_rk(int index, CTAP_residentKey * rk)
}
+void ctap_store_kbd(CTAP_soloKbd * kbd)
+{
+ // nop
+}
+
void ctap_delete_rk(int index)
{
CTAP_residentKey rk;
diff --git a/targets/stm32l432/build/common.mk b/targets/stm32l432/build/common.mk
index cf3fe966..c682a118 100644
--- a/targets/stm32l432/build/common.mk
+++ b/targets/stm32l432/build/common.mk
@@ -14,7 +14,7 @@ DRIVER_LIBS := lib/stm32l4xx_hal_pcd.c lib/stm32l4xx_hal_pcd_ex.c lib/stm32l4xx_
USB_LIB := lib/usbd/usbd_cdc.c lib/usbd/usbd_cdc_if.c lib/usbd/usbd_composite.c \
lib/usbd/usbd_conf.c lib/usbd/usbd_core.c lib/usbd/usbd_ioreq.c \
lib/usbd/usbd_ctlreq.c lib/usbd/usbd_desc.c lib/usbd/usbd_hid.c \
- lib/usbd/usbd_ccid.c
+ lib/usbd/usbd_ccid.c lib/usbd/usbd_kbd.c
VERSION_FULL?=$(SOLO_VERSION_FULL)
VERSION:=$(SOLO_VERSION)
@@ -32,4 +32,4 @@ _all:
echo $(SOLO_VERSION_PAT)
%.o: %.s
- $(AS) -o $@ $^
\ No newline at end of file
+ $(AS) -o $@ $^
diff --git a/targets/stm32l432/lib/usbd/usbd_composite.c b/targets/stm32l432/lib/usbd/usbd_composite.c
index b1de7d27..ca61adc1 100644
--- a/targets/stm32l432/lib/usbd/usbd_composite.c
+++ b/targets/stm32l432/lib/usbd/usbd_composite.c
@@ -36,6 +36,14 @@ static uint8_t *USBD_Composite_GetDeviceQualifierDescriptor (uint16_t *length);
#define CCID_SIZE 0
#endif
+#ifdef ENABLE_KBD
+#define KBD_SIZE 25
+#define KBD_NUM_INTERFACE 1
+#else
+#define KBD_NUM_INTERFACE 0
+#define KBD_SIZE 0
+#endif
+
#if DEBUG_LEVEL > 0
#define CDC_SIZE (49 + 8 + 9 + 4)
#define CDC_NUM_INTERFACE 2
@@ -46,15 +54,16 @@ static uint8_t *USBD_Composite_GetDeviceQualifierDescriptor (uint16_t *length);
#define HID_SIZE 41
-#define COMPOSITE_CDC_HID_DESCRIPTOR_SIZE (HID_SIZE + CDC_SIZE + CCID_SIZE)
-#define NUM_INTERFACES (1 + CDC_NUM_INTERFACE + CCID_NUM_INTERFACE)
-#define NUM_CLASSES 3
+#define COMPOSITE_CDC_HID_DESCRIPTOR_SIZE (HID_SIZE + CDC_SIZE + CCID_SIZE + KBD_SIZE)
+#define NUM_INTERFACES (1 + CDC_NUM_INTERFACE + CCID_NUM_INTERFACE + KBD_NUM_INTERFACE)
+#define NUM_CLASSES 4
#define HID_INTF_NUM 0
#define CDC_MASTER_INTF_NUM 1
#define CDC_SLAVE_INTF_NUM 2
#define CCID_INTF_NUM 3
+#define KBD_INTF_NUM 1
__ALIGN_BEGIN uint8_t COMPOSITE_CDC_HID_DESCRIPTOR[COMPOSITE_CDC_HID_DESCRIPTOR_SIZE] __ALIGN_END =
{
/*Configuration Descriptor*/
@@ -284,7 +293,40 @@ __ALIGN_BEGIN uint8_t COMPOSITE_CDC_HID_DESCRIPTOR[COMPOSITE_CDC_HID_DESCRIPTOR_
#endif
+#ifdef ENABLE_KBD
+ /* */
+ /* KBD */
+ /* */
+ /************** Descriptor of Keyboard interface ****************/
+ 0x09, /*bLength: Interface Descriptor size*/
+ USB_DESC_TYPE_INTERFACE, /*bDescriptorType: Interface descriptor type*/
+ KBD_INTF_NUM, /*bInterfaceNumber: Number of Interface*/
+ 0x00, /*bAlternateSetting: Alternate setting*/
+ 0x01, /*bNumEndpoints*/
+ 0x03, /*bInterfaceClass: HID*/
+ 0x01, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
+ 0x01, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
+ 2, /*iInterface: Index of string descriptor*/
+ /******************** Descriptor of Keyboard HID ********************/
+ 0x09, /*bLength: HID Descriptor size*/
+ HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
+ 0x11, /*bcdHID: HID Class Spec release number*/
+ 0x01,
+ 0x00, /*bCountryCode: Hardware target country*/
+ 0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/
+ 0x22, /*bDescriptorType*/
+ HID_KBD_REPORT_DESC_SIZE, /*wItemLength: Total length of Report descriptor*/
+ 0,
+ /******************** Descriptor of Keyboard endpoint ********************/
+ 0x07, /*bLength: Endpoint Descriptor size*/
+ USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
+ KBD_EPIN_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/
+ 0x03, /*bmAttributes: Interrupt endpoint*/
+ KBD_EPIN_SIZE, /*wMaxPacketSize: 4 Byte max */
+ 0x00,
+ KBD_BINTERVAL, /*bInterval: Polling Interval */
+#endif
};
USBD_ClassTypeDef USBD_Composite =
@@ -311,7 +353,7 @@ int in_endpoint_to_class[MAX_ENDPOINTS];
int out_endpoint_to_class[MAX_ENDPOINTS];
-void USBD_Composite_Set_Classes(USBD_ClassTypeDef *hid_class, USBD_ClassTypeDef *ccid_class, USBD_ClassTypeDef *cdc_class) {
+void USBD_Composite_Set_Classes(USBD_ClassTypeDef *hid_class, USBD_ClassTypeDef *ccid_class, USBD_ClassTypeDef *cdc_class, USBD_ClassTypeDef *kbd_class) {
memset(USBD_Classes, 0 , sizeof(USBD_Classes));
USBD_Classes[0] = hid_class;
#ifdef ENABLE_CCID
@@ -320,6 +362,9 @@ void USBD_Composite_Set_Classes(USBD_ClassTypeDef *hid_class, USBD_ClassTypeDef
#if DEBUG_LEVEL > 0
USBD_Classes[2] = cdc_class;
#endif
+#ifdef ENABLE_KBD
+ USBD_Classes[1] = kbd_class;
+#endif
}
static USBD_ClassTypeDef * getClass(uint8_t index)
@@ -336,6 +381,10 @@ static USBD_ClassTypeDef * getClass(uint8_t index)
case CDC_MASTER_INTF_NUM:
case CDC_SLAVE_INTF_NUM:
return USBD_Classes[2];
+#endif
+#ifdef ENABLE_KBD
+ case KBD_INTF_NUM:
+ return USBD_Classes[1];
#endif
}
return NULL;
@@ -364,7 +413,6 @@ static uint8_t USBD_Composite_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx)
}
static uint8_t USBD_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) {
- int i;
USBD_ClassTypeDef * device_class;
device_class = getClass(req->wIndex);
@@ -380,12 +428,7 @@ static uint8_t USBD_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqType
switch (req->bRequest) {
case USB_REQ_GET_DESCRIPTOR :
- for(i = 0; i < NUM_CLASSES; i++) {
- if (USBD_Classes[i] != NULL && USBD_Classes[i]->Setup(pdev, req) != USBD_OK) {
- return USBD_FAIL;
- }
- }
-
+ return device_class->Setup(pdev, req);
break;
case USB_REQ_GET_INTERFACE :
diff --git a/targets/stm32l432/lib/usbd/usbd_composite.h b/targets/stm32l432/lib/usbd/usbd_composite.h
index 0fdc513d..c54955bd 100644
--- a/targets/stm32l432/lib/usbd/usbd_composite.h
+++ b/targets/stm32l432/lib/usbd/usbd_composite.h
@@ -17,7 +17,7 @@ extern int in_endpoint_to_class[MAX_ENDPOINTS];
extern int out_endpoint_to_class[MAX_ENDPOINTS];
-void USBD_Composite_Set_Classes(USBD_ClassTypeDef *class0, USBD_ClassTypeDef *class1, USBD_ClassTypeDef *class2);
+void USBD_Composite_Set_Classes(USBD_ClassTypeDef *class0, USBD_ClassTypeDef *class1, USBD_ClassTypeDef *class2, USBD_ClassTypeDef *class3);
#ifdef __cplusplus
}
diff --git a/targets/stm32l432/lib/usbd/usbd_conf.c b/targets/stm32l432/lib/usbd/usbd_conf.c
index bd3c442b..a8f71c42 100644
--- a/targets/stm32l432/lib/usbd/usbd_conf.c
+++ b/targets/stm32l432/lib/usbd/usbd_conf.c
@@ -272,6 +272,8 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev)
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_OUT_EP , PCD_SNG_BUF, 0xd8 + 64*5); // data OUT
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_IN_EP , PCD_SNG_BUF, 0xd8 + 64*6); // data IN
+ // KBD
+ HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , KBD_EPIN_ADDR , PCD_SNG_BUF, 0xd8 + 64*7); // data IN
// dump_pma_header("usbd_conf");
return USBD_OK;
diff --git a/targets/stm32l432/lib/usbd/usbd_hid.h b/targets/stm32l432/lib/usbd/usbd_hid.h
index 03dcb893..31902132 100644
--- a/targets/stm32l432/lib/usbd/usbd_hid.h
+++ b/targets/stm32l432/lib/usbd/usbd_hid.h
@@ -60,13 +60,19 @@
#define HID_EPOUT_ADDR 0x01U
#define HID_EPOUT_SIZE HID_PACKET_SIZE
+#define KBD_PACKET_SIZE 8
+#define KBD_EPIN_ADDR 0x82U
+#define KBD_EPIN_SIZE KBD_PACKET_SIZE
+
#define USB_HID_DESC_SIZ 9U
#define HID_FIDO_REPORT_DESC_SIZE 34U
+#define HID_KBD_REPORT_DESC_SIZE 63U
#define HID_DESCRIPTOR_TYPE 0x21U
#define HID_REPORT_DESC 0x22U
#define HID_BINTERVAL 5
+#define KBD_BINTERVAL 10
#define HID_REQ_SET_PROTOCOL 0x0BU
#define HID_REQ_GET_PROTOCOL 0x03U
@@ -94,9 +100,11 @@ typedef struct
USBD_HID_HandleTypeDef;
extern USBD_ClassTypeDef USBD_HID;
+extern USBD_ClassTypeDef USBD_KBD;
void usb_hid_recieve_callback(uint8_t ep);
+void usb_kbd_send(uint8_t *msg, int len);
#ifdef __cplusplus
diff --git a/targets/stm32l432/lib/usbd/usbd_kbd.c b/targets/stm32l432/lib/usbd/usbd_kbd.c
new file mode 100644
index 00000000..9a328c63
--- /dev/null
+++ b/targets/stm32l432/lib/usbd/usbd_kbd.c
@@ -0,0 +1,403 @@
+/**
+ ******************************************************************************
+ * @attention
+ *
+ *
© Copyright (c) 2017 STMicroelectronics International N.V.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted, provided that the following conditions are met:
+ *
+ * 1. Redistribution 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 of STMicroelectronics nor the names of other
+ * contributors to this software may be used to endorse or promote products
+ * derived from this software without specific written permission.
+ * 4. This software, including modifications and/or derivative works of this
+ * software, must execute solely and exclusively on microcontroller or
+ * microprocessor devices manufactured by or for STMicroelectronics.
+ * 5. Redistribution and use of this software other than as permitted under
+ * this license is void and will automatically terminate your rights under
+ * this license.
+ *
+ * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
+ * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
+ * SHALL STMICROELECTRONICS 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.
+ *
+ ******************************************************************************
+ */
+
+ /* BSPDependencies
+ - "stm32xxxxx_{eval}{discovery}{nucleo_144}.c"
+ - "stm32xxxxx_{eval}{discovery}_io.c"
+ EndBSPDependencies */
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_hid.h"
+#include "usbd_ctlreq.h"
+#include "usbd_conf.h"
+#include "usbd_core.h"
+
+#include "log.h"
+
+static uint8_t USBD_KBD_Init (USBD_HandleTypeDef *pdev,
+ uint8_t cfgidx);
+
+static uint8_t USBD_KBD_DeInit (USBD_HandleTypeDef *pdev,
+ uint8_t cfgidx);
+
+static uint8_t USBD_KBD_Setup (USBD_HandleTypeDef *pdev,
+ USBD_SetupReqTypedef *req);
+
+static uint8_t USBD_KBD_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum);
+
+static uint8_t key_map[][3] =
+{
+ {'0', 0, 0x27},
+ {'-', 0, 0x2d},
+ {'=', 0, 0x2e},
+ {'[', 0, 0x2f},
+ {']', 0, 0x30},
+ {'\\', 0, 0x31},
+ {';', 0, 0x33},
+ {'\'', 0, 0x34},
+ {'`', 0, 0x35},
+ {',', 0, 0x36},
+ {'.', 0, 0x37},
+ {'/', 0, 0x38},
+ {' ', 0, 0x2c},
+ {'\n', 0, 0x28},
+
+ {'~', 2, 0x35},
+ {'!', 2, 0x1e},
+ {'@', 2, 0x1f},
+ {'#', 2, 0x20},
+ {'$', 2, 0x21},
+ {'%', 2, 0x22},
+ {'^', 2, 0x23},
+ {'&', 2, 0x24},
+ {'*', 2, 0x25},
+ {'(', 2, 0x26},
+ {')', 2, 0x27},
+ {'_', 2, 0x2d},
+ {'+', 2, 0x2e},
+ {'{', 2, 0x2f},
+ {'}', 2, 0x30},
+ {':', 2, 0x33},
+ {'"', 2, 0x34},
+ {'|', 2, 0x31},
+ {'<', 2, 0x36},
+ {'>', 2, 0x37},
+ {'?', 2, 0x38},
+ {0, 0, 0},
+};
+
+USBD_ClassTypeDef USBD_KBD =
+{
+ USBD_KBD_Init,
+ USBD_KBD_DeInit,
+ USBD_KBD_Setup,
+ NULL, /*EP0_TxSent*/
+ NULL, /*EP0_RxReady*/
+ USBD_KBD_DataIn, /*DataIn*/
+ NULL, /*DataOut*/
+ NULL, /*SOF */
+ NULL,
+ NULL,
+
+
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+/* USB HID device Configuration Descriptor */
+__ALIGN_BEGIN static uint8_t USBD_HID_Desc[USB_HID_DESC_SIZ] __ALIGN_END =
+{
+ /* 18 */
+ 0x09, /*bLength: HID Descriptor size*/
+ HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
+ 0x11, /*bcdHID: HID Class Spec release number*/
+ 0x01,
+ 0x00, /*bCountryCode: Hardware target country*/
+ 0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/
+ 0x22, /*bDescriptorType*/
+ HID_KBD_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
+ 0x00,
+};
+
+__ALIGN_BEGIN static uint8_t HID_KBD_ReportDesc[HID_KBD_REPORT_DESC_SIZE] __ALIGN_END =
+{
+ 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
+ 0x09, 0x06, /* USAGE (Keyboard) */
+ 0xa1, 0x01, /* COLLECTION (Application) */
+ 0x05, 0x07, /* USAGE_PAGE (Keyboard) */
+ 0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */
+ 0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */
+ 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
+ 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
+ 0x75, 0x01, /* REPORT_SIZE (1) */
+ 0x95, 0x08, /* REPORT_COUNT (8) */
+ 0x81, 0x02, /* INPUT (Data,Var,Abs) */
+ 0x95, 0x01, /* REPORT_COUNT (1) */
+ 0x75, 0x08, /* REPORT_SIZE (8) */
+ 0x81, 0x03, /* INPUT (Cnst,Var,Abs) */
+ 0x95, 0x05, /* REPORT_COUNT (5) */
+ 0x75, 0x01, /* REPORT_SIZE (1) */
+ 0x05, 0x08, /* USAGE_PAGE (LEDs) */
+ 0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */
+ 0x29, 0x05, /* USAGE_MAXIMUM (Kana) */
+ 0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
+ 0x95, 0x01, /* REPORT_COUNT (1) */
+ 0x75, 0x03, /* REPORT_SIZE (3) */
+ 0x91, 0x03, /* OUTPUT (Cnst,Var,Abs) */
+ 0x95, 0x06, /* REPORT_COUNT (6) */
+ 0x75, 0x08, /* REPORT_SIZE (8) */
+ 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
+ 0x25, 0x65, /* LOGICAL_MAXIMUM (101) */
+ 0x05, 0x07, /* USAGE_PAGE (Keyboard) */
+ 0x19, 0x00, /* USAGE_MINIMUM (Reserved) */
+ 0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Application) */
+ 0x81, 0x00, /* INPUT (Data,Ary,Abs) */
+ 0xc0 /* END_COLLECTION */
+};
+
+/**
+ * @brief USBD_KBD_Init
+ * Initialize the HID interface
+ * @param pdev: device instance
+ * @param cfgidx: Configuration index
+ * @retval status
+ */
+
+static uint8_t USBD_KBD_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx)
+{
+ /* Open EP IN */
+ USBD_LL_OpenEP(pdev, KBD_EPIN_ADDR, USBD_EP_TYPE_INTR, KBD_EPIN_SIZE);
+ static uint8_t mem[sizeof (USBD_HID_HandleTypeDef)];
+ pdev->ep_in[KBD_EPIN_ADDR & 0xFU].is_used = 1U;
+
+ pdev->pClassData = mem;
+
+ ((USBD_HID_HandleTypeDef *)pdev->pClassData)->state = HID_IDLE;
+
+ return USBD_OK;
+}
+
+/**
+ * @brief USBD_KBD_Init
+ * DeInitialize the HID layer
+ * @param pdev: device instance
+ * @param cfgidx: Configuration index
+ * @retval status
+ */
+static uint8_t USBD_KBD_DeInit (USBD_HandleTypeDef *pdev,
+ uint8_t cfgidx)
+{
+ /* Close HID EPs */
+ USBD_LL_CloseEP(pdev, KBD_EPIN_ADDR);
+ pdev->ep_in[KBD_EPIN_ADDR & 0xFU].is_used = 0U;
+
+ return USBD_OK;
+}
+
+/**
+ * @brief USBD_KBD_Setup
+ * Handle the HID specific requests
+ * @param pdev: instance
+ * @param req: usb requests
+ * @retval status
+ */
+static uint8_t USBD_KBD_Setup (USBD_HandleTypeDef *pdev,
+ USBD_SetupReqTypedef *req)
+{
+ USBD_HID_HandleTypeDef *hhid = (USBD_HID_HandleTypeDef*) pdev->pClassData;
+ uint16_t len = 0U;
+ uint8_t *pbuf = NULL;
+ uint16_t status_info = 0U;
+ USBD_StatusTypeDef ret = USBD_OK;
+ req->wLength = req->wLength & 0x7f;
+
+ switch (req->bmRequest & USB_REQ_TYPE_MASK)
+ {
+ case USB_REQ_TYPE_CLASS :
+ switch (req->bRequest)
+ {
+ case HID_REQ_SET_PROTOCOL:
+ hhid->Protocol = (uint8_t)(req->wValue);
+ break;
+
+ case HID_REQ_GET_PROTOCOL:
+ USBD_CtlSendData (pdev, (uint8_t *)(void *)&hhid->Protocol, 1U);
+ break;
+
+ case HID_REQ_SET_IDLE:
+ hhid->IdleState = (uint8_t)(req->wValue >> 8);
+ break;
+
+ case HID_REQ_GET_IDLE:
+ USBD_CtlSendData (pdev, (uint8_t *)(void *)&hhid->IdleState, 1U);
+ break;
+
+ default:
+ USBD_CtlError (pdev, req);
+ ret = USBD_FAIL;
+ break;
+ }
+ break;
+ case USB_REQ_TYPE_STANDARD:
+ switch (req->bRequest)
+ {
+ case USB_REQ_GET_STATUS:
+ if (pdev->dev_state == USBD_STATE_CONFIGURED)
+ {
+ USBD_CtlSendData (pdev, (uint8_t *)(void *)&status_info, 2U);
+ }
+ else
+ {
+ USBD_CtlError (pdev, req);
+ ret = USBD_FAIL;
+ }
+ break;
+
+ case USB_REQ_GET_DESCRIPTOR:
+ if(req->wValue >> 8 == HID_REPORT_DESC)
+ {
+ len = MIN(HID_KBD_REPORT_DESC_SIZE , req->wLength);
+ pbuf = HID_KBD_ReportDesc;
+ printf1(TAG_GREEN,"get report desc\r\n");
+ }
+ else if(req->wValue >> 8 == HID_DESCRIPTOR_TYPE)
+ {
+ pbuf = USBD_HID_Desc;
+ len = MIN(USB_HID_DESC_SIZ, req->wLength);
+ }
+ else
+ {
+ USBD_CtlError (pdev, req);
+ ret = USBD_FAIL;
+ break;
+ }
+ USBD_CtlSendData (pdev, pbuf, len);
+ break;
+
+ case USB_REQ_GET_INTERFACE :
+ if (pdev->dev_state == USBD_STATE_CONFIGURED)
+ {
+ USBD_CtlSendData (pdev, (uint8_t *)(void *)&hhid->AltSetting, 1U);
+ }
+ else
+ {
+ USBD_CtlError (pdev, req);
+ ret = USBD_FAIL;
+ }
+ break;
+
+ case USB_REQ_SET_INTERFACE :
+ if (pdev->dev_state == USBD_STATE_CONFIGURED)
+ {
+ hhid->AltSetting = (uint8_t)(req->wValue);
+ }
+ else
+ {
+ USBD_CtlError (pdev, req);
+ ret = USBD_FAIL;
+ }
+ break;
+
+ default:
+ USBD_CtlError (pdev, req);
+ ret = USBD_FAIL;
+ break;
+ }
+ break;
+
+ default:
+ USBD_CtlError (pdev, req);
+ ret = USBD_FAIL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * @brief USBD_KBD_DataIn
+ * handle data IN Stage
+ * @param pdev: device instance
+ * @param epnum: endpoint index
+ * @retval status
+ */
+static uint8_t USBD_KBD_DataIn (USBD_HandleTypeDef *pdev,
+ uint8_t epnum)
+{
+ /* Ensure that the FIFO is empty before a new transfer, this condition could
+ be caused by a new transfer before the end of the previous transfer */
+ ((USBD_HID_HandleTypeDef *)pdev->pClassData)->state = HID_IDLE;
+ return USBD_OK;
+}
+
+static void USBD_KBD_Transmit(uint8_t * msg)
+{
+ printf1(TAG_DUMP2,"<< ");
+ dump_hex1(TAG_DUMP2, msg, KBD_PACKET_SIZE);
+
+ Solo_USBD_Device.ep_in[KBD_EPIN_ADDR & 0xFU].total_length = KBD_PACKET_SIZE;
+
+ while (PCD_GET_EP_TX_STATUS(USB, KBD_EPIN_ADDR & 0x0f) == USB_EP_TX_VALID)
+ ;
+ USBD_LL_Transmit(&Solo_USBD_Device, KBD_EPIN_ADDR, msg, KBD_PACKET_SIZE);
+}
+
+void usb_kbd_send(uint8_t *msg, int len)
+{
+ uint8_t report[8];
+ for (int i = 0; i < len; i++)
+ {
+ memset(report, 0, sizeof(report));
+ uint8_t ch = msg[i];
+ if (ch >= 'a' && ch <= 'z')
+ {
+ report[2] = ch - 'a' + 4;
+ USBD_KBD_Transmit(report);
+ }
+ else if (ch >= 'A' && ch <= 'Z')
+ {
+ report[0] = 2; //left shift
+ report[2] = ch - 'A' + 4;
+ USBD_KBD_Transmit(report);
+ }
+ else if (ch >= '1' && ch <= '9')
+ {
+ report[2] = ch - '1' + 0x1e;
+ USBD_KBD_Transmit(report);
+ }
+ else
+ {
+ for (int j=0; key_map[j][0] != 0; j++)
+ {
+ if (ch == key_map[j][0]) {
+ report[0] = key_map[j][1];
+ report[2] = key_map[j][2];
+ USBD_KBD_Transmit(report);
+ break;
+ }
+ }
+ }
+ memset(report, 0, sizeof(report));
+ USBD_KBD_Transmit(report);
+ }
+}
diff --git a/targets/stm32l432/src/app.h b/targets/stm32l432/src/app.h
index fa3d3806..c045c529 100644
--- a/targets/stm32l432/src/app.h
+++ b/targets/stm32l432/src/app.h
@@ -22,6 +22,9 @@
// Enable the CCID USB interface
// #define ENABLE_CCID
+// Enable the KBD USB interface
+// #define ENABLE_KBD
+
#define NON_BLOCK_PRINTING 0
diff --git a/targets/stm32l432/src/device.c b/targets/stm32l432/src/device.c
index c8f487bd..913779cb 100644
--- a/targets/stm32l432/src/device.c
+++ b/targets/stm32l432/src/device.c
@@ -48,6 +48,7 @@ extern PCD_HandleTypeDef hpcd;
static int _NFC_status = 0;
static bool isLowFreq = 0;
static bool _up_disabled = false;
+static bool _up_wait = false;
// #define IS_BUTTON_PRESSED() (0 == (LL_GPIO_ReadInputPort(SOLO_BUTTON_PORT) & SOLO_BUTTON_PIN))
static int is_physical_button_pressed(void)
@@ -134,6 +135,17 @@ void EXTI0_IRQHandler(void)
if ((millis() - __last_button_bounce_time) > 25)
{
__last_button_press_time = millis();
+#ifndef IS_BOOTLOADER
+ if (!_up_wait)
+ {
+ CTAP_soloKbd kbd;
+ ctap_load_kbd(&kbd);
+ if (kbd.length > 0)
+ {
+ usb_kbd_send(kbd.sequence, kbd.length);
+ }
+ }
+#endif
}
__last_button_bounce_time = millis();
}
@@ -742,6 +754,7 @@ int ctap_user_presence_test(uint32_t up_delay)
// Set LED status and wait.
led_rgb(0xff3520);
+ _up_wait = true;
// Block and wait for some time.
ret = wait_for_button_activate(up_delay);
@@ -755,13 +768,14 @@ int ctap_user_presence_test(uint32_t up_delay)
goto done;
}
-
+ _up_wait = false;
return 0;
done:
ret = wait_for_button_release(up_delay);
__last_button_press_time = 0;
+ _up_wait = false;
return 1;
}
@@ -846,6 +860,20 @@ void ctap_overwrite_rk(int index,CTAP_residentKey * rk)
printf1(TAG_GREEN, "4\r\n");
}
+void ctap_store_kbd(CTAP_soloKbd * kbd)
+{
+ uint8_t buf[PAGE_SIZE];
+ memmove(buf, kbd, sizeof(CTAP_soloKbd));
+ flash_erase_page(KEYBOARD_PAGE);
+ flash_write(KEYBOARD_PAGE_ADDR, buf, 2048);
+}
+
+void ctap_load_kbd(CTAP_soloKbd * kbd)
+{
+ uint32_t * ptr = (uint32_t *) flash_addr(KEYBOARD_PAGE);
+ memmove(kbd, ptr, sizeof(CTAP_soloKbd));
+}
+
void boot_st_bootloader(void)
{
__disable_irq();
diff --git a/targets/stm32l432/src/init.c b/targets/stm32l432/src/init.c
index def698d2..1a762be0 100644
--- a/targets/stm32l432/src/init.c
+++ b/targets/stm32l432/src/init.c
@@ -709,10 +709,12 @@ void init_usb(void)
// Enable USB Clock
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_USBFSEN);
#ifndef IS_BOOTLOADER
- USBD_Composite_Set_Classes(&USBD_HID, &USBD_CCID, &USBD_CDC);
+ USBD_Composite_Set_Classes(&USBD_HID, &USBD_CCID, &USBD_CDC, &USBD_KBD);
in_endpoint_to_class[HID_EPIN_ADDR & 0x7F] = 0;
out_endpoint_to_class[HID_EPOUT_ADDR & 0x7F] = 0;
+ in_endpoint_to_class[KBD_EPIN_ADDR & 0x7F] = 1;
+
in_endpoint_to_class[CCID_IN_EP & 0x7F] = 1;
out_endpoint_to_class[CCID_OUT_EP & 0x7F] = 1;
diff --git a/targets/stm32l432/src/memory_layout.h b/targets/stm32l432/src/memory_layout.h
index d9682c86..4ef8295e 100644
--- a/targets/stm32l432/src/memory_layout.h
+++ b/targets/stm32l432/src/memory_layout.h
@@ -38,6 +38,10 @@
#define ATTESTATION_PAGE (PAGES - 15)
#define ATTESTATION_PAGE_ADDR (0x08000000 + ATTESTATION_PAGE*PAGE_SIZE)
+// keyboard stuff
+#define KEYBOARD_PAGE (PAGES - 16)
+#define KEYBOARD_PAGE_ADDR (0x08000000 + KEYBOARD_PAGE*PAGE_SIZE)
+
// End of application code. Leave some extra room for future data storage.
// NOT included in application
#define APPLICATION_END_PAGE ((PAGES - 20))