diff --git a/src/usb/hid/ctap_hid.h b/src/usb/hid/ctap_hid.h index a74433b..b83b26e 100644 --- a/src/usb/hid/ctap_hid.h +++ b/src/usb/hid/ctap_hid.h @@ -143,6 +143,8 @@ typedef struct { #define CTAP1_ERR_INVALID_CHANNEL 0x0b // CID not valid #define CTAP1_ERR_OTHER 0x7f // Other unspecified error +extern void add_keyboard_buffer(const uint8_t *, size_t); + #ifdef __cplusplus } #endif diff --git a/src/usb/hid/hid.c b/src/usb/hid/hid.c index 69b6f8e..51108ad 100644 --- a/src/usb/hid/hid.c +++ b/src/usb/hid/hid.c @@ -93,9 +93,72 @@ uint32_t hid_write(uint16_t size) { uint16_t send_buffer_size = 0; bool last_write_result = false; +static uint8_t keyboard_buffer[256]; +static uint8_t keyboard_buffer_len = 0; +static const uint8_t conv_table[128][2] = { HID_ASCII_TO_KEYCODE }; +static uint8_t keyboard_w = 0; +static bool sent_key = false; + +void add_keyboard_buffer(const uint8_t *data, size_t data_len) { + keyboard_buffer_len = MIN(sizeof(keyboard_buffer), data_len); + memcpy(keyboard_buffer, data, keyboard_buffer_len); +} + +static void send_hid_report(uint8_t report_id) { + if (!tud_hid_ready()) + return; + + switch(report_id) { + case REPORT_ID_KEYBOARD: { + if (keyboard_w < keyboard_buffer_len) { + if (sent_key == false) { + uint8_t keycode[6] = { 0 }; + uint8_t modifier = 0; + uint8_t chr = keyboard_buffer[keyboard_w]; + if (conv_table[chr][0]) + modifier = KEYBOARD_MODIFIER_LEFTSHIFT; + keycode[0] = conv_table[chr][1]; + if (tud_hid_n_keyboard_report(ITF_KEYBOARD, REPORT_ID_KEYBOARD, modifier, keycode) == true) + sent_key = true; + } + else { + if (tud_hid_n_keyboard_report(ITF_KEYBOARD, REPORT_ID_KEYBOARD, 0, NULL) == true) { + keyboard_w++; + sent_key = false; + } + } + } + else if (keyboard_w == keyboard_buffer_len && keyboard_buffer_len > 0) { + keyboard_w = keyboard_buffer_len = 0; + } + } + break; + + default: break; + } +} + +void hid_task(void) { + // Poll every 10ms + const uint32_t interval_ms = 10; + static uint32_t start_ms = 0; + + if (board_millis() - start_ms < interval_ms) + return; + start_ms += interval_ms; + + // Remote wakeup + if ( tud_suspended() && keyboard_buffer_len > 0) { + tud_remote_wakeup(); + } + else { + send_hid_report(REPORT_ID_KEYBOARD); + } +} + void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, /*uint16_t*/ uint8_t len) { - uint8_t seq = report[4] & TYPE_MASK ? 0 : report[4] + 1; - if (send_buffer_size > 0) { + if (send_buffer_size > 0 && instance == ITF_HID) { + uint8_t seq = report[4] & TYPE_MASK ? 0 : report[4] + 1; if (last_write_result == true) { ctap_resp->cid = ctap_req->cid; ctap_resp->cont.seq = seq; @@ -108,7 +171,7 @@ void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, /*uint1 } int driver_write_hid(const uint8_t *buffer, size_t buffer_size) { - last_write_result = tud_hid_report(0, buffer, buffer_size); + last_write_result = tud_hid_n_report(ITF_HID, 0, buffer, buffer_size); printf("result %d\n", last_write_result); if (last_write_result == false) return 0; @@ -127,7 +190,7 @@ void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t rep (void) report_id; (void) report_type; - usb_rx(ITF_HID, buffer, bufsize); + usb_rx(itf, buffer, bufsize); } uint32_t last_cmd_time = 0, last_packet_time = 0; diff --git a/src/usb/tusb_config.h b/src/usb/tusb_config.h index 8a292ae..8ebdf7a 100644 --- a/src/usb/tusb_config.h +++ b/src/usb/tusb_config.h @@ -106,7 +106,7 @@ #define CFG_TUD_CDC 0 #define CFG_TUD_MSC 0 #ifdef USB_ITF_HID -#define CFG_TUD_HID 1 +#define CFG_TUD_HID 2 #else #define CFG_TUD_HID 0 #endif diff --git a/src/usb/usb.c b/src/usb/usb.c index 7145396..52be3ef 100644 --- a/src/usb/usb.c +++ b/src/usb/usb.c @@ -205,7 +205,7 @@ void card_exit() { led_set_blink(BLINK_SUSPENDED); card_locked_itf = ITF_TOTAL; } - +extern void hid_task(); void usb_task() { bool mounted = false; for (uint8_t itf = 0; itf < ITF_TOTAL; itf++) { @@ -265,6 +265,7 @@ void usb_task() { } } } + hid_task(); } void timeout_stop() { diff --git a/src/usb/usb.h b/src/usb/usb.h index eacbb0b..6413ada 100644 --- a/src/usb/usb.h +++ b/src/usb/usb.h @@ -39,7 +39,8 @@ enum { #ifdef USB_ITF_HID - ITF_HID, + ITF_HID = 0, + ITF_KEYBOARD, #endif #ifdef USB_ITF_CCID ITF_CCID, @@ -47,6 +48,11 @@ enum { ITF_TOTAL }; +enum +{ + REPORT_ID_KEYBOARD = 1, + REPORT_ID_COUNT +}; extern void usb_task(); extern queue_t usb_to_card_q; diff --git a/src/usb/usb_descriptors.c b/src/usb/usb_descriptors.c index eb0978e..0c6f9bf 100644 --- a/src/usb/usb_descriptors.c +++ b/src/usb/usb_descriptors.c @@ -79,7 +79,7 @@ tusb_desc_configuration_t const desc_config = + sizeof(tusb_desc_interface_t) + sizeof(struct ccid_class_descriptor) + 2*sizeof(tusb_desc_endpoint_t) #endif #ifdef USB_ITF_HID - + TUD_HID_INOUT_DESC_LEN + + TUD_HID_INOUT_DESC_LEN + TUD_HID_DESC_LEN #endif ), .bNumInterfaces = ITF_TOTAL, @@ -156,12 +156,13 @@ static uint8_t desc_config_extended[sizeof(tusb_desc_configuration_t) + sizeof(tusb_desc_interface_t) + sizeof(struct ccid_class_descriptor) + 2*sizeof(tusb_desc_endpoint_t) #endif #ifdef USB_ITF_HID -+ TUD_HID_INOUT_DESC_LEN ++ TUD_HID_INOUT_DESC_LEN + TUD_HID_DESC_LEN #endif ]; #ifdef USB_ITF_HID #define HID_USAGE_PAGE_FIDO 0xF1D0 + enum { HID_USAGE_FIDO_U2FHID = 0x01, // U2FHID usage for top-level collection @@ -195,17 +196,28 @@ uint8_t const desc_hid_report[] = { TUD_HID_REPORT_DESC_FIDO_U2F(CFG_TUD_HID_EP_BUFSIZE) }; +uint8_t const desc_hid_report_kb[] = +{ + TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(REPORT_ID_KEYBOARD)) +}; #define EPNUM_HID 0x03 static uint8_t desc_hid[] = { - // Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval - TUD_HID_INOUT_DESCRIPTOR(ITF_HID, ITF_HID+5, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, 0x80 | EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 10) + TUD_HID_INOUT_DESCRIPTOR(ITF_HID, ITF_HID+5, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, 0x80 | EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 10) +}; + +static uint8_t desc_hid_kb[] = { + TUD_HID_DESCRIPTOR(ITF_KEYBOARD, ITF_KEYBOARD+5, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report_kb), 0x80 | (EPNUM_HID+1), 16, 5) }; uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf) { - printf("report_cb %d\n", itf); - return desc_hid_report; + printf("report_cb %d\n", itf); + if (itf == ITF_HID) + return desc_hid_report; + else if (itf == ITF_KEYBOARD) + return desc_hid_report_kb; + return NULL; } #endif @@ -220,6 +232,7 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index) memcpy(p, &desc_config, sizeof(tusb_desc_configuration_t)); p += sizeof(tusb_desc_configuration_t); #ifdef USB_ITF_HID memcpy(p, &desc_hid, sizeof(desc_hid)); p += sizeof(desc_hid); + memcpy(p, &desc_hid_kb, sizeof(desc_hid_kb)); p += sizeof(desc_hid_kb); #endif #ifdef USB_ITF_CCID memcpy(p, &desc_interface, sizeof(tusb_desc_interface_t)); p += sizeof(tusb_desc_interface_t); @@ -261,6 +274,7 @@ char const* string_desc_arr [] = "Pico Key Config" // 4: Vendor Interface #ifdef USB_ITF_HID ,"Pico Key HID Interface" + ,"Pico Key HID Keyboard Interface" #endif #ifdef USB_ITF_CCID ,"Pico Key CCID Interface"