1#include <console/printf.h>
2#include <drivers/usb/hid.h>
3#include <drivers/usb/kb.h>
4#include <drivers/usb/usb.h>
5#include <drivers/usb/xhci.h>
6#include <log.h>
7#include <mem/alloc.h>
8#include <mem/page.h>
9#include <mem/pmm.h>
10#include <mem/vmm.h>
11#include <sch/sched.h>
12#include <string.h>
13#include <thread/thread.h>
14#include <time/spin_sleep.h>
15
16static const char keycode_to_ascii[256] = {
17 [0x04] = 'a', [0x05] = 'b', [0x06] = 'c', [0x07] = 'd', [0x08] = 'e',
18 [0x09] = 'f', [0x0A] = 'g', [0x0B] = 'h', [0x0C] = 'i', [0x0D] = 'j',
19 [0x0E] = 'k', [0x0F] = 'l', [0x10] = 'm', [0x11] = 'n', [0x12] = 'o',
20 [0x13] = 'p', [0x14] = 'q', [0x15] = 'r', [0x16] = 's', [0x17] = 't',
21 [0x18] = 'u', [0x19] = 'v', [0x1A] = 'w', [0x1B] = 'x', [0x1C] = 'y',
22 [0x1D] = 'z', [0x1E] = '1', [0x1F] = '2', [0x20] = '3', [0x21] = '4',
23 [0x22] = '5', [0x23] = '6', [0x24] = '7', [0x25] = '8', [0x26] = '9',
24 [0x27] = '0', [0x28] = '\n', [0x29] = 27, // ESC
25 [0x2A] = '\b', // Backspace
26 [0x2B] = '\t', // Tab
27 [0x2C] = ' ', [0x2D] = '-', [0x2E] = '=', [0x2F] = '[', [0x30] = ']',
28 [0x31] = '\\', [0x33] = ';', [0x34] = '\'', [0x35] = '`', [0x36] = ',',
29 [0x37] = '.', [0x38] = '/'};
30
31static const char keycode_to_ascii_shifted[256] = {
32 [0x04] = 'A', [0x05] = 'B', [0x06] = 'C', [0x07] = 'D', [0x08] = 'E',
33 [0x09] = 'F', [0x0A] = 'G', [0x0B] = 'H', [0x0C] = 'I', [0x0D] = 'J',
34 [0x0E] = 'K', [0x0F] = 'L', [0x10] = 'M', [0x11] = 'N', [0x12] = 'O',
35 [0x13] = 'P', [0x14] = 'Q', [0x15] = 'R', [0x16] = 'S', [0x17] = 'T',
36 [0x18] = 'U', [0x19] = 'V', [0x1A] = 'W', [0x1B] = 'X', [0x1C] = 'Y',
37 [0x1D] = 'Z', [0x1E] = '!', [0x1F] = '@', [0x20] = '#', [0x21] = '$',
38 [0x22] = '%', [0x23] = '^', [0x24] = '&', [0x25] = '*', [0x26] = '(',
39 [0x27] = ')', [0x2D] = '_', [0x2E] = '+', [0x2F] = '{', [0x30] = '}',
40 [0x31] = '|', [0x33] = ':', [0x34] = '"', [0x35] = '~', [0x36] = '<',
41 [0x37] = '>', [0x38] = '?'};
42
43static inline bool generic_keyboard_is_modifier(uint32_t keycode) {
44 return keycode >= USB_HID_MODIFIER_BASE &&
45 keycode < USB_HID_MODIFIER_BASE + 8;
46}
47
48static void generic_keyboard_dispatch(struct generic_keyboard *kbd,
49 uint32_t keycode, bool pressed) {
50 if (generic_keyboard_is_modifier(keycode)) {
51 uint8_t bit = keycode - USB_HID_MODIFIER_BASE;
52 if (pressed)
53 kbd->modifiers |= (1 << bit);
54 else
55 kbd->modifiers &= ~(1 << bit);
56 return;
57 }
58
59 kbd->emit(kbd, keycode, pressed);
60}
61
62static inline bool usb_kbd_shift_active(const struct generic_keyboard *kbd) {
63 const uint8_t shift_mask = (1 << 1) | /* Left Shift */
64 (1 << 5); /* Right Shift */
65
66 return (kbd->modifiers & shift_mask) != 0;
67}
68
69static void tty_keyboard_emit(struct generic_keyboard *kbd, uint32_t keycode,
70 bool pressed) {
71 if (!pressed)
72 return;
73
74 bool shift = usb_kbd_shift_active(kbd);
75 char ch =
76 shift ? keycode_to_ascii_shifted[keycode] : keycode_to_ascii[keycode];
77
78 printf(format: "%c", ch);
79}
80
81static bool key_in_report(uint8_t key, const struct usb_kbd_report *r) {
82 for (int i = 0; i < 6; i++)
83 if (r->keys[i] == key)
84 return true;
85 return false;
86}
87
88void usb_kbd_process_report(struct usb_hid_keyboard *kbd,
89 const struct usb_kbd_report *cur) {
90 const struct usb_kbd_report *prev = &kbd->last;
91
92 uint8_t changed = prev->modifiers ^ cur->modifiers;
93 if (changed) {
94 for (int bit = 0; bit < 8; bit++) {
95 if (!(changed & (1 << bit)))
96 continue;
97
98 uint32_t keycode = USB_HID_MODIFIER_BASE + bit;
99 bool pressed = cur->modifiers & (1 << bit);
100
101 kbd->gkbd.emit(&kbd->gkbd, keycode, pressed);
102 }
103 }
104
105 for (int i = 0; i < 6; i++) {
106 uint8_t key = prev->keys[i];
107 if (!key)
108 continue;
109
110 if (!key_in_report(key, r: cur)) {
111 kbd->gkbd.emit(&kbd->gkbd, key, false);
112 }
113 }
114
115 for (int i = 0; i < 6; i++) {
116 uint8_t key = cur->keys[i];
117 if (!key)
118 continue;
119
120 if (!key_in_report(key, r: prev)) {
121 kbd->gkbd.emit(&kbd->gkbd, key, true);
122 }
123 }
124}
125
126enum usb_error usb_keyboard_get_descriptor(struct usb_device *dev,
127 uint8_t interface_number,
128 uint16_t len, void *buf) {
129 uint8_t bm = usb_construct_rq_bitmap(USB_REQUEST_TRANS_DTH,
130 USB_REQUEST_TYPE_STANDARD,
131 USB_REQUEST_RECIPIENT_INTERFACE);
132
133 struct usb_setup_packet setup = {
134 .bitmap_request_type = bm,
135 .request = USB_RQ_CODE_GET_DESCRIPTOR,
136 .value = USB_HID_DESC_TYPE_REPORT << 8,
137 .length = len,
138 .index = interface_number,
139 };
140
141 struct usb_request req = {
142 .setup = &setup,
143 .buffer = buf,
144 .dev = dev,
145 };
146
147 return usb_transfer_sync(fn: dev->host->ops->submit_control_transfer, request: &req,
148 NULL);
149}
150
151static void usb_kbd_worker(void *arg) {
152 struct usb_hid_keyboard *kbd = arg;
153
154 while (true) {
155 enum usb_error ret = usb_transfer_sync(
156 fn: kbd->dev->host->ops->submit_interrupt_transfer, request: &kbd->req, NULL);
157 if (ret != USB_OK)
158 break;
159
160 usb_kbd_process_report(kbd, cur: &kbd->cur);
161 kbd->last = kbd->cur;
162 }
163 atomic_store(&kbd->worker_here, false);
164}
165
166struct usb_hid_keyboard *usb_keyboard_create(struct usb_device *dev,
167 struct usb_endpoint *ep) {
168 struct usb_hid_keyboard *kbd = kmalloc(sizeof(*kbd), ALLOC_FLAGS_ZERO);
169
170 kbd->dev = dev;
171 kbd->ep = ep;
172
173 kbd->gkbd.emit = tty_keyboard_emit;
174 kbd->gkbd.priv = kbd;
175
176 kbd->req = (struct usb_request){
177 .buffer = &kbd->cur,
178 .length = sizeof(kbd->cur),
179 .ep = kbd->ep,
180 .dev = dev,
181 };
182
183 thread_spawn(name: "usb_kbd_worker", entry: usb_kbd_worker, arg: kbd);
184 atomic_store(&kbd->worker_here, true);
185 return kbd;
186}
187
188LOG_HANDLE_DECLARE_DEFAULT(usbkb);
189LOG_SITE_DECLARE_DEFAULT(usbkb);
190#define usbkb_log(log_level, fmt, ...) \
191 log(LOG_SITE(usbkb), LOG_HANDLE(usbkb), log_level, fmt, ##__VA_ARGS__)
192
193enum usb_error usb_keyboard_bringup(struct usb_device *dev) {
194 struct usb_interface_descriptor *intf =
195 usb_find_interface(dev, USB_CLASS_HID, USB_SUBCLASS_HID_BOOT_INTERFACE,
196 USB_PROTOCOL_HID_KEYBOARD);
197 if (!intf)
198 return USB_ERR_NO_DEVICE;
199
200 usbkb_log(LOG_INFO, "Keyboard connected");
201
202 uint8_t iface_num = intf->interface_number;
203
204 uint8_t *report_buf = kmalloc_aligned(256, PAGE_SIZE, ALLOC_FLAGS_ZERO);
205
206 enum usb_error err = USB_OK;
207 if ((err = usb_keyboard_get_descriptor(dev, interface_number: iface_num, len: 256, buf: report_buf)) !=
208 USB_OK) {
209 kfree_aligned(report_buf);
210 return err;
211 }
212
213 kfree_aligned(report_buf);
214
215 for (uint8_t i = 0; i < dev->num_endpoints; i++) {
216 struct usb_endpoint *ep = dev->endpoints[i];
217 if ((ep->address & 0x80) &&
218 ep->type == USB_ENDPOINT_ATTR_TRANS_TYPE_INTERRUPT) {
219
220 dev->driver_private = usb_keyboard_create(dev, ep);
221 return USB_OK;
222 }
223 }
224
225 usbkb_log(LOG_WARN, "No interrupt IN endpoint found");
226 return USB_ERR_NO_ENDPOINT;
227}
228
229void usb_keyboard_teardown(struct usb_device *dev) {
230 struct usb_hid_keyboard *kb = dev->driver_private;
231 while (atomic_load(&kb->worker_here))
232 scheduler_yield();
233
234 (void) dev;
235}
236
237void usb_keyboard_free(struct usb_device *dev) {
238 kfree(dev->driver_private);
239 usbkb_log(LOG_INFO, "Keyboard disconnected");
240}
241
242USB_DRIVER_REGISTER(keyboard, USB_CLASS_HID, USB_SUBCLASS_HID_BOOT_INTERFACE,
243 USB_PROTOCOL_HID_KEYBOARD, usb_keyboard_bringup,
244 usb_keyboard_teardown, usb_keyboard_free);
245