summaryrefslogtreecommitdiff
path: root/cmd/harness/usb_keyboard.c
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/harness/usb_keyboard.c')
-rw-r--r--cmd/harness/usb_keyboard.c113
1 files changed, 113 insertions, 0 deletions
diff --git a/cmd/harness/usb_keyboard.c b/cmd/harness/usb_keyboard.c
new file mode 100644
index 0000000..1989b35
--- /dev/null
+++ b/cmd/harness/usb_keyboard.c
@@ -0,0 +1,113 @@
+/* usb_keyboard.c - Implementation of a USB keyboard device
+ *
+ * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-Licence-Identifier: AGPL-3.0-or-later
+ */
+
+#include "tusb.h"
+
+#include "tusb_helpers.h" /* for TUD_ENDPOINT_IN */
+#include "usb_common.h"
+#include "usb_keyboard.h"
+
+/**
+ * A USB-HID "Report Descriptor" (see USB-HID 1.11 §6.2.2 "Report
+ * Descriptor") describing a keyboard.
+ */
+static uint8_t const hid_report_descriptor_keyboard[] = { TUD_HID_REPORT_DESC_KEYBOARD() };
+
+static uint8_t kbd_ifc = 0;
+
+void usb_keyboard_init() {
+ if (kbd_ifc)
+ return;
+ usb_common_earlyinit();
+
+ kbd_ifc = usb_add_interface(cfgnum_std, TUD_HID_DESC_LEN, (uint8_t[]){
+ /* USB-HID input-only descriptor for inclusion in the config descriptor; consisting of 3 parts:
+ * 1. an interface descriptor (USB 2.0 §9.6.5 "Interface"),
+ * 2. a class-specific (class=HID) descriptor of type HID (USB-HID 1.11 §6.2.1 "HID Descriptor"),
+ * 3. an endpoint descriptor for inputs (USB 2.0 §9.6.6 "Endpoint").
+ * The TUD_HID_DESCRIPTOR() macro takes care of this for us. */
+ TUD_HID_DESCRIPTOR(
+ 0, /* interface : bInterfaceNumber ; Number of this interface (0-indexed) */
+ STRID_KBD_IFC, /* interface : iInterface ; Index of string descriptor describing this interface */
+ HID_ITF_PROTOCOL_KEYBOARD, /* interface : bInterfaceProtocol ; see USB-HID 1.11 §4.3 "Protocols" */
+ sizeof(hid_report_descriptor_keyboard), /* hid : wDescriptorLength ; Total size of report descriptor */
+ TUD_ENDPOINT_IN | 1, /* endpoint : bEndpointAddress ; Direction | endpoint number (arbitrary?) */
+ CFG_TUD_HID_EP_BUFSIZE, /* endpoint : wMaxPacketSize ; Maximum packet size this endpoint is capable of sending or receiving */
+ 10), /* endpoint : bInterval ; poll interval (in milliseconds?) */
+ });
+}
+
+static uint8_t ascii2keycode[128][2] = { HID_ASCII_TO_KEYCODE };
+
+COROUTINE usb_keyboard_cr(void *_chan) {
+ usb_keyboard_rpc_t *chan = _chan;
+ cr_begin();
+
+ uint8_t report_id = 0;
+ uint8_t modifier = 0;
+ uint8_t keycodes[6] = {0};
+ for (;;) {
+ while (!tud_hid_n_ready(kbd_ifc))
+ cr_yield();
+
+ if (cr_rpc_have_req(chan)) {
+ uint32_t rune;
+ cr_rpc_recv_req(chan, &rune);
+
+ modifier = ascii2keycode[rune][0] ? KEYBOARD_MODIFIER_LEFTSHIFT : 0;
+ keycodes[0] = ascii2keycode[rune][1];
+ tud_hid_n_keyboard_report(kbd_ifc, report_id, modifier, keycodes);
+
+ while (!tud_hid_n_ready(kbd_ifc))
+ cr_yield();
+
+ modifier = 0;
+ keycodes[0] = 0;
+ tud_hid_n_keyboard_report(kbd_ifc, report_id, modifier, keycodes);
+
+ cr_rpc_send_resp(chan, 1);
+ } else {
+ modifier = 0;
+ keycodes[0] = 0;
+ tud_hid_n_keyboard_report(kbd_ifc, report_id, modifier, keycodes);
+ }
+ }
+
+ cr_end();
+}
+
+/**
+ * Return a pointer to the HID "Report Descriptor" (see USB-HID 1.11
+ * §6.2.2 "Report Descriptor") for the given index.
+ */
+uint8_t const *tud_hid_descriptor_report_cb(uint8_t index) {
+ static uint8_t const *reports[] = {
+ hid_report_descriptor_keyboard,
+ };
+ if (index >= TU_ARRAY_SIZE(reports))
+ return NULL;
+ return reports[index];
+}
+
+uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
+{
+ // TODO not Implemented
+ (void) instance;
+ (void) report_id;
+ (void) report_type;
+ (void) buffer;
+ (void) reqlen;
+
+ return 0;
+}
+
+// Invoked when received SET_REPORT control request or
+// received data on OUT endpoint ( Report ID = 0, Type = 0 )
+void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
+{
+ // TODO not implemented
+ (void) report_id;
+}