diff --git a/system/ehci.c b/system/ehci.c index df2dc40..7af1f8f 100644 --- a/system/ehci.c +++ b/system/ehci.c @@ -138,7 +138,6 @@ #define WS_QHD_SIZE (1 + MAX_KEYBOARDS) // Queue Head Descriptors #define WS_QTD_SIZE (3 + MAX_KEYBOARDS) // Queue Transfer Descriptors -#define WS_KC_BUFFER_SIZE 8 // keycodes #define MILLISEC 1000 // in microseconds @@ -205,22 +204,20 @@ typedef struct { hcd_workspace_t base_ws; // System memory data structures used by the host controller. - ehci_qhd_t qhd[WS_QHD_SIZE]; - ehci_qtd_t qtd[WS_QTD_SIZE]; + ehci_qhd_t qhd[WS_QHD_SIZE] __attribute__ ((aligned (32))); + ehci_qtd_t qtd[WS_QTD_SIZE] __attribute__ ((aligned (32))); // Keyboard data transfer buffers. hid_kbd_rpt_t kbd_rpt[MAX_KEYBOARDS]; + // Saved keyboard reports. + hid_kbd_rpt_t prev_kbd_rpt[MAX_KEYBOARDS]; + // Pointer to the host controller registers. ehci_op_regs_t *op_regs; // Number of keyboards detected. int num_keyboards; - - // Circular buffer for received keycodes. - uint8_t kc_buffer[WS_KC_BUFFER_SIZE]; - int kc_index_i; - int kc_index_o; } workspace_t __attribute__ ((aligned (256))); //------------------------------------------------------------------------------ @@ -444,7 +441,7 @@ static bool get_data_request(const usb_hcd_t *hcd, const usb_ep_t *ep, const usb return do_async_transfer(ws, 3); } -static uint8_t get_keycode(const usb_hcd_t *hcd) +static void poll_keyboards(const usb_hcd_t *hcd) { workspace_t *ws = (workspace_t *)hcd->ws; @@ -456,32 +453,18 @@ static uint8_t get_keycode(const usb_hcd_t *hcd) hid_kbd_rpt_t *kbd_rpt = &ws->kbd_rpt[kbd_idx]; - uint32_t error_mask = EHCI_QTD_HALTED | EHCI_QTD_DB_ERR | EHCI_QTD_BABBLE | EHCI_QTD_TR_ERR | EHCI_QTD_MMF | EHCI_QTD_PS; + uint8_t error_mask = EHCI_QTD_HALTED | EHCI_QTD_DB_ERR | EHCI_QTD_BABBLE | EHCI_QTD_TR_ERR | EHCI_QTD_MMF | EHCI_QTD_PS; if (~status & error_mask) { - uint8_t keycode = kbd_rpt->key_code[0]; - if (keycode != 0) { - int kc_index_i = ws->kc_index_i; - int kc_index_n = (kc_index_i + 1) % WS_KC_BUFFER_SIZE; - if (kc_index_n != ws->kc_index_o) { - ws->kc_buffer[kc_index_i] = keycode; - ws->kc_index_i = kc_index_n; - } - } + hid_kbd_rpt_t *prev_kbd_rpt = &ws->prev_kbd_rpt[kbd_idx]; + process_usb_keyboard_report(hcd, kbd_rpt, prev_kbd_rpt); + *prev_kbd_rpt = *kbd_rpt; } - build_ehci_qtd(kbd_qtd, kbd_qtd, EHCI_QTD_PID_IN, EHCI_QTD_DT(0), kbd_rpt, sizeof(hid_kbd_rpt_t)); + build_ehci_qtd(kbd_qtd, kbd_qtd, EHCI_QTD_PID_IN, EHCI_QTD_DT(1), kbd_rpt, sizeof(hid_kbd_rpt_t)); ehci_qhd_t *kbd_qhd = &ws->qhd[1 + kbd_idx]; kbd_qhd->next_qtd_ptr = (uintptr_t)kbd_qtd; } - - int kc_index_o = ws->kc_index_o; - if (kc_index_o != ws->kc_index_i) { - ws->kc_index_o = (kc_index_o + 1) % WS_KC_BUFFER_SIZE; - return ws->kc_buffer[kc_index_o]; - } - - return 0; } //------------------------------------------------------------------------------ @@ -497,7 +480,7 @@ static const hcd_methods_t methods = { .configure_kbd_ep = NULL, .setup_request = setup_request, .get_data_request = get_data_request, - .get_keycode = get_keycode + .poll_keyboards = poll_keyboards }; //------------------------------------------------------------------------------ diff --git a/system/ohci.c b/system/ohci.c index 91b405f..ba55b64 100644 --- a/system/ohci.c +++ b/system/ohci.c @@ -161,7 +161,6 @@ #define WS_ED_SIZE (1 + MAX_KEYBOARDS) // Endpoint Descriptors #define WS_TD_SIZE (3 + MAX_KEYBOARDS) // Transfer Descriptors -#define WS_KC_BUFFER_SIZE 8 // keycodes #define MILLISEC 1000 // in microseconds @@ -226,20 +225,18 @@ typedef struct { hcd_workspace_t base_ws; // System memory data structures used by the host controller. - ohci_hcca_t hcca; - ohci_ed_t ed[WS_ED_SIZE]; - ohci_td_t td[WS_TD_SIZE]; + ohci_hcca_t hcca __attribute__ ((aligned (256))); + ohci_ed_t ed[WS_ED_SIZE] __attribute__ ((aligned (16))); + ohci_td_t td[WS_TD_SIZE] __attribute__ ((aligned (16))); - // Keyboad data transfer buffers. + // Keyboard data transfer buffers. hid_kbd_rpt_t kbd_rpt[MAX_KEYBOARDS]; + // Saved keyboard reports. + hid_kbd_rpt_t prev_kbd_rpt[MAX_KEYBOARDS]; + // Pointer to the host controller registers. ohci_op_regs_t *op_regs; - - // Circular buffer for received keycodes. - uint8_t kc_buffer[WS_KC_BUFFER_SIZE]; - int kc_index_i; - int kc_index_o; } workspace_t __attribute__ ((aligned (256))); //------------------------------------------------------------------------------ @@ -367,7 +364,7 @@ static bool get_data_request(const usb_hcd_t *hcd, const usb_ep_t *ep, const usb return wait_for_ohci_done(ws, 3); } -static uint8_t get_keycode(const usb_hcd_t *hcd) +static void poll_keyboards(const usb_hcd_t *hcd) { workspace_t *ws = (workspace_t *)hcd->ws; @@ -378,15 +375,9 @@ static uint8_t get_keycode(const usb_hcd_t *hcd) hid_kbd_rpt_t *kbd_rpt = &ws->kbd_rpt[kbd_idx]; if ((td->control & OHCI_TD_CC) == OHCI_TD_CC_NO_ERR) { - uint8_t keycode = kbd_rpt->key_code[0]; - if (keycode != 0) { - int kc_index_i = ws->kc_index_i; - int kc_index_n = (kc_index_i + 1) % WS_KC_BUFFER_SIZE; - if (kc_index_n != ws->kc_index_o) { - ws->kc_buffer[kc_index_i] = keycode; - ws->kc_index_i = kc_index_n; - } - } + hid_kbd_rpt_t *prev_kbd_rpt = &ws->prev_kbd_rpt[kbd_idx]; + process_usb_keyboard_report(hcd, kbd_rpt, prev_kbd_rpt); + *prev_kbd_rpt = *kbd_rpt; } ohci_td_t *next_td = (ohci_td_t *)((uintptr_t)td->next_td); @@ -397,14 +388,6 @@ static uint8_t get_keycode(const usb_hcd_t *hcd) td = next_td; } - - int kc_index_o = ws->kc_index_o; - if (kc_index_o != ws->kc_index_i) { - ws->kc_index_o = (kc_index_o + 1) % WS_KC_BUFFER_SIZE; - return ws->kc_buffer[kc_index_o]; - } - - return 0; } //------------------------------------------------------------------------------ @@ -420,7 +403,7 @@ static const hcd_methods_t methods = { .configure_kbd_ep = NULL, .setup_request = setup_request, .get_data_request = get_data_request, - .get_keycode = get_keycode + .poll_keyboards = poll_keyboards }; //------------------------------------------------------------------------------ diff --git a/system/uhci.c b/system/uhci.c index 79eacfa..dd68998 100644 --- a/system/uhci.c +++ b/system/uhci.c @@ -146,7 +146,6 @@ #define WS_QH_SIZE (1 + MAX_KEYBOARDS) // Queue Head Descriptors #define WS_TD_SIZE (2 + MAX_PACKETS) // Queue Transfer Descriptors -#define WS_KC_BUFFER_SIZE 8 // keycodes #define MILLISEC 1000 // in microseconds @@ -176,22 +175,20 @@ typedef struct { hcd_workspace_t base_ws; // System memory data structures used by the host controller. - uhci_qh_t qh[WS_QH_SIZE]; - uhci_td_t td[WS_TD_SIZE]; + uhci_qh_t qh[WS_QH_SIZE] __attribute__ ((aligned (16))); + uhci_td_t td[WS_TD_SIZE] __attribute__ ((aligned (16))); // Keyboard data transfer buffers. hid_kbd_rpt_t kbd_rpt[MAX_KEYBOARDS]; + // Saved keyboard reports. + hid_kbd_rpt_t prev_kbd_rpt[MAX_KEYBOARDS]; + // I/O base address of the host controller registers. uint16_t io_base; // Number of keyboards detected. int num_keyboards; - - // Circular buffer for received keycodes. - uint8_t kc_buffer[WS_KC_BUFFER_SIZE]; - int kc_index_i; - int kc_index_o; } workspace_t __attribute__ ((aligned (256))); //------------------------------------------------------------------------------ @@ -373,7 +370,7 @@ static bool get_data_request(const usb_hcd_t *hcd, const usb_ep_t *ep, const usb return wait_for_uhci_done(ws); } -static uint8_t get_keycode(const usb_hcd_t *hcd) +static void poll_keyboards(const usb_hcd_t *hcd) { workspace_t *ws = (workspace_t *)hcd->ws; uint16_t io_base = ws->io_base; @@ -393,15 +390,9 @@ static uint8_t get_keycode(const usb_hcd_t *hcd) uint32_t error_mask = UHCI_TD_STALLED | UHCI_TD_DB_ERR | UHCI_TD_BABBLE | UHCI_TD_NAK_RX | UHCI_TD_CRC_TO | UHCI_TD_BS_ERR; if (~status & error_mask) { - uint8_t keycode = kbd_rpt->key_code[0]; - if (keycode != 0) { - int kc_index_i = ws->kc_index_i; - int kc_index_n = (kc_index_i + 1) % WS_KC_BUFFER_SIZE; - if (kc_index_n != ws->kc_index_o) { - ws->kc_buffer[kc_index_i] = keycode; - ws->kc_index_i = kc_index_n; - } - } + hid_kbd_rpt_t *prev_kbd_rpt = &ws->prev_kbd_rpt[kbd_idx]; + process_usb_keyboard_report(hcd, kbd_rpt, prev_kbd_rpt); + *prev_kbd_rpt = *kbd_rpt; } // Reenable the TD. @@ -409,14 +400,6 @@ static uint8_t get_keycode(const usb_hcd_t *hcd) write32(&kbd_qh->qe_link_ptr, (uintptr_t)kbd_td | UHCI_LP_TYPE_TD); } } - - int kc_index_o = ws->kc_index_o; - if (kc_index_o != ws->kc_index_i) { - ws->kc_index_o = (kc_index_o + 1) % WS_KC_BUFFER_SIZE; - return ws->kc_buffer[kc_index_o]; - } - - return 0; } //------------------------------------------------------------------------------ @@ -432,7 +415,7 @@ static const hcd_methods_t methods = { .configure_kbd_ep = NULL, .setup_request = setup_request, .get_data_request = get_data_request, - .get_keycode = get_keycode + .poll_keyboards = poll_keyboards }; //------------------------------------------------------------------------------ diff --git a/system/usbhcd.c b/system/usbhcd.c index 5e35855..5195403 100644 --- a/system/usbhcd.c +++ b/system/usbhcd.c @@ -56,7 +56,7 @@ static const hcd_methods_t methods = { .configure_kbd_ep = NULL, .setup_request = NULL, .get_data_request = NULL, - .get_keycode = NULL + .poll_keyboards = NULL }; // All entries in this array must be initialised in order to generate the necessary relocation records. @@ -587,6 +587,33 @@ bool find_attached_usb_keyboards(const usb_hcd_t *hcd, const usb_hub_t *hub, int return keyboard_found; } +void process_usb_keyboard_report(const usb_hcd_t *hcd, hid_kbd_rpt_t *report, hid_kbd_rpt_t *prev_report) +{ + hcd_workspace_t *ws = hcd->ws; + + for (int i = 0; i < 6; i++) { + uint8_t key_code = report->key_code[i]; + if (key_code != 0) { + // Check if we've already seen this key press. + for (int j = 0; j < 6; j++) { + if (prev_report->key_code[j] == key_code) { + key_code = 0; + break; + } + } + // If not, put it in the key code buffer. + if (key_code != 0) { + int kc_index_i = ws->kc_index_i; + int kc_index_n = (kc_index_i + 1) % HCD_KC_BUFFER_SIZE; + if (kc_index_n != ws->kc_index_o) { + ws->kc_buffer[kc_index_i] = key_code; + ws->kc_index_i = kc_index_n; + } + } + } + } +} + static void probe_usb_controller(int bus, int dev, int func, hci_type_t controller_type) { uint16_t vendor_id = pci_config_read16(bus, dev, func, 0x00); @@ -755,8 +782,15 @@ void find_usb_keyboards(bool pause_if_none) uint8_t get_usb_keycode(void) { for (int i = 0; i < num_usb_controllers; i++) { - uint8_t keycode = usb_controllers[i].methods->get_keycode(&usb_controllers[i]); - if (keycode != 0) return keycode; + const usb_hcd_t *hcd = &usb_controllers[i]; + + usb_controllers[i].methods->poll_keyboards(hcd); + + int kc_index_o = hcd->ws->kc_index_o; + if (kc_index_o != hcd->ws->kc_index_i) { + hcd->ws->kc_index_o = (kc_index_o + 1) % HCD_KC_BUFFER_SIZE; + return hcd->ws->kc_buffer[kc_index_o]; + } } return 0; } diff --git a/system/usbhcd.h b/system/usbhcd.h index cd7441c..e9a4d1c 100644 --- a/system/usbhcd.h +++ b/system/usbhcd.h @@ -30,9 +30,13 @@ /** * The size of the data transfer buffer in a host controller driver workspace. - * This aligns the start of the driver private data to a 1024 byte boundary. */ -#define HCD_DATA_BUFFER_SIZE (1024 - sizeof(size_t)) +#define HCD_DATA_BUFFER_SIZE 512 // bytes + +/** + * The size of the key code buffer in a host controller driver workspace. + */ +#define HCD_KC_BUFFER_SIZE 8 // keycodes /** * A USB device speed (used internally by the various HCI drivers). @@ -87,7 +91,7 @@ typedef struct { bool (*configure_kbd_ep) (usb_hcd_r, const usb_ep_t *, int); bool (*setup_request) (usb_hcd_r, const usb_ep_t *, const usb_setup_pkt_t *); bool (*get_data_request) (usb_hcd_r, const usb_ep_t *, const usb_setup_pkt_t *, const void *, size_t); - uint8_t (*get_keycode) (usb_hcd_r); + void (*poll_keyboards) (usb_hcd_r); } hcd_methods_t; /** @@ -97,6 +101,9 @@ typedef struct { typedef struct __attribute__((packed)) { uint8_t data_buffer[HCD_DATA_BUFFER_SIZE]; size_t data_length; + uint8_t kc_buffer[HCD_KC_BUFFER_SIZE]; + int8_t kc_index_i; + int8_t kc_index_o; } hcd_workspace_t; /** @@ -259,6 +266,15 @@ bool find_attached_usb_keyboards(const usb_hcd_t *hcd, const usb_hub_t *hub, int usb_speed_t device_speed, int device_id, int *num_devices, usb_ep_t keyboards[], int max_keyboards, int *num_keyboards); +/** + * Scans the latest keyboard report from a HID keyboard for key presses that + * weren't present in the previous report from that keyboard. Appends the HID + * key code for each new key press to the driver's key code buffer. + * + * Used internally by the various HCI drivers. + */ +void process_usb_keyboard_report(const usb_hcd_t *hcd, hid_kbd_rpt_t *report, hid_kbd_rpt_t *prev_report); + /** * Scans the attached USB devices and initialises all HID keyboard devices * it finds (subject to implementation limits on the number of devices). diff --git a/system/xhci.c b/system/xhci.c index bb1ce37..e437d3a 100644 --- a/system/xhci.c +++ b/system/xhci.c @@ -138,7 +138,6 @@ #define WS_CR_SIZE 8 // TRBs (multiple of 4 to maintain 64 byte alignment) #define WS_ER_SIZE 16 // TRBs (multiple of 4 to maintain 64 byte alignment) #define WS_ERST_SIZE 4 // entries (multiple of 4 to maintain 64 byte alignment) -#define WS_KC_BUFFER_SIZE 8 // keycodes #define EP_TR_SIZE 8 // TRBs (multiple of 4 to maintain 64 byte alignment) @@ -304,9 +303,9 @@ typedef struct { hcd_workspace_t base_ws; // System memory data structures used by the host controller. - xhci_trb_t cr [WS_CR_SIZE]; // command ring - xhci_trb_t er [WS_ER_SIZE]; // event ring - xhci_erst_entry_t erst [WS_ERST_SIZE]; // event ring segment table + xhci_trb_t cr [WS_CR_SIZE] __attribute__ ((aligned (64))); // command ring + xhci_trb_t er [WS_ER_SIZE] __attribute__ ((aligned (64))); // event ring + xhci_erst_entry_t erst [WS_ERST_SIZE] __attribute__ ((aligned (64))); // event ring segment table // Keyboard data transfer rings ep_tr_t kbd_tr [MAX_KEYBOARDS]; @@ -314,6 +313,9 @@ typedef struct { // Keyboard data transfer buffers. hid_kbd_rpt_t kbd_rpt [MAX_KEYBOARDS]; + // Saved keyboard reports. + hid_kbd_rpt_t prev_kbd_rpt[MAX_KEYBOARDS]; + // Pointers to the host controller registers. xhci_op_regs_t *op_regs; xhci_rt_regs_t *rt_regs; @@ -338,11 +340,6 @@ typedef struct { // Keyboard endpoint ID lookup table uint8_t kbd_ep_id [MAX_KEYBOARDS]; - - // Circular buffer for received keycodes. - uint8_t kc_buffer[WS_KC_BUFFER_SIZE]; - int32_t kc_index_i; - int32_t kc_index_o; } workspace_t __attribute__ ((aligned (64))); //------------------------------------------------------------------------------ @@ -881,7 +878,7 @@ static int identify_keyboard(workspace_t *ws, int slot_id, int ep_id) return -1; } -static uint8_t get_keycode(const usb_hcd_t *hcd) +static void poll_keyboards(const usb_hcd_t *hcd) { workspace_t *ws = (workspace_t *)hcd->ws; @@ -894,28 +891,15 @@ static uint8_t get_keycode(const usb_hcd_t *hcd) if (kbd_idx < 0) continue; hid_kbd_rpt_t *kbd_rpt = &ws->kbd_rpt[kbd_idx]; - uint8_t keycode = kbd_rpt->key_code[0]; - if (keycode != 0) { - int kc_index_i = ws->kc_index_i; - int kc_index_n = (kc_index_i + 1) % WS_KC_BUFFER_SIZE; - if (kc_index_n != ws->kc_index_o) { - ws->kc_buffer[kc_index_i] = keycode; - ws->kc_index_i = kc_index_n; - } - } + + hid_kbd_rpt_t *prev_kbd_rpt = &ws->prev_kbd_rpt[kbd_idx]; + process_usb_keyboard_report(hcd, kbd_rpt, prev_kbd_rpt); + *prev_kbd_rpt = *kbd_rpt; ep_tr_t *kbd_tr = &ws->kbd_tr[kbd_idx]; issue_normal_trb(kbd_tr, kbd_rpt, XHCI_TRB_DIR_IN, sizeof(hid_kbd_rpt_t)); ring_device_doorbell(ws->db_regs, ws->kbd_slot_id[kbd_idx], ws->kbd_ep_id[kbd_idx]); } - - int kc_index_o = ws->kc_index_o; - if (kc_index_o != ws->kc_index_i) { - ws->kc_index_o = (kc_index_o + 1) % WS_KC_BUFFER_SIZE; - return ws->kc_buffer[kc_index_o]; - } - - return 0; } static bool set_heap_segment(void) @@ -945,7 +929,7 @@ static const hcd_methods_t methods = { .configure_kbd_ep = configure_kbd_ep, .setup_request = setup_request, .get_data_request = get_data_request, - .get_keycode = get_keycode + .poll_keyboards = poll_keyboards }; //------------------------------------------------------------------------------