Backport USB driver + UHCI

This commit is contained in:
Mark
2020-02-03 13:40:03 +02:00
parent e342c62882
commit 32f51f53f0
14 changed files with 795 additions and 39 deletions
+8 -2
View File
@@ -67,14 +67,20 @@ OBJS+=$(O)/sys/debug.o \
OBJS+=$(O)/sys/driver/pci/pci.o \
$(O)/sys/driver/pci/pcidb.o \
$(O)/sys/driver/ata/ahci.o
$(O)/sys/driver/ata/ahci.o \
$(O)/sys/driver/usb/usb_uhci.o \
$(O)/sys/driver/usb/usb.o \
$(O)/sys/driver/usb/driver.o \
$(O)/sys/driver/usb/device.o \
$(O)/sys/driver/usb/usbkbd.o
DIRS+=$(O)/sys/fs \
$(O)/sys/fs/ext2 \
$(O)/sys/char \
$(O)/sys/block \
$(O)/sys/driver/pci \
$(O)/sys/driver/ata
$(O)/sys/driver/ata \
$(O)/sys/driver/usb
ifeq ($(DEBUG_COUNTERS),1)
CFLAGS+=-DDEBUG_COUNTERS
+10
View File
@@ -0,0 +1,10 @@
#pragma once
// Classes
#define USB_CLASS_HID 0x03
// HID subclasses
#define USB_SUBCLASS_BOOT 0x01
// HID protocols
#define USB_PROTOCOL_KEYBOARD 0x01
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#include "sys/driver/usb/request.h"
#include "sys/types.h"
struct usb_transfer;
struct usb_request;
struct usb_device {
void *hc;
uint16_t address;
uint8_t speed;
uint32_t max_packet;
uint8_t endpoint_toggle;
struct usb_desc_interface desc_interface;
struct usb_desc_endpoint desc_endpoint;
struct usb_driver *driver;
void *driver_data;
void (*hc_control)(struct usb_device *, struct usb_transfer *);
void (*hc_interrupt)(struct usb_device *, struct usb_transfer *);
struct usb_device *next;
};
struct usb_device *usb_device_create(void);
int usb_device_init(struct usb_device *dev);
int usb_device_request(struct usb_device *dev, uint8_t type, uint8_t request, uint16_t index, uint16_t value, uint16_t len, void *data);
+13
View File
@@ -0,0 +1,13 @@
#pragma once
struct usb_device;
struct usb_driver {
int (*usb_init)(struct usb_device *dev);
void (*usb_poll)(struct usb_device *dev);
struct usb_driver *next;
};
int usb_select_driver(struct usb_device *dev);
void usb_add_driver(struct usb_driver *drv);
+97
View File
@@ -0,0 +1,97 @@
#pragma once
#include "sys/types.h"
#define USB_REQUEST_TYPE_D2H (1 << 7)
#define USB_REQUEST_TYPE_CLASS (1 << 5)
#define USB_REQUEST_TO_INTERFACE (1 << 0)
// General
#define USB_REQUEST_GET_STATUS 0
#define USB_REQUEST_SET_ADDRESS 5
#define USB_REQUEST_GET_DESCRIPTOR 6
#define USB_REQUEST_SET_CONFIGURATION 9
// USB HID
#define USB_REQUEST_SET_IDLE 0x0A
#define USB_DESCRIPTOR_DEVICE 1
#define USB_DESCRIPTOR_CONFIGURATION 2
#define USB_DESCRIPTOR_STRING 3
#define USB_DESCRIPTOR_INTERFACE 4
#define USB_DESCRIPTOR_ENDPOINT 5
struct usb_request {
uint8_t type;
uint8_t request;
uint16_t value;
uint16_t index;
uint16_t length;
};
#define USB_TRANSFER_COMPLETE (1 << 0)
#define USB_TRANSFER_SUCCESS (1 << 1)
struct usb_transfer {
struct usb_request *request;
uint8_t endp;
void *data;
size_t length;
uint32_t flags;
};
struct usb_desc_configuration {
uint8_t length;
uint8_t type;
uint16_t total_length;
uint8_t num_interfaces;
uint8_t configuration_value;
uint8_t idx_configuration;
uint8_t attributes;
uint8_t max_power;
} __attribute__((packed));
struct usb_desc_interface {
uint8_t length;
uint8_t type;
uint8_t interface_number;
uint8_t alternate_setting;
uint8_t num_endpoints;
uint8_t interface_class;
uint8_t interface_subclass;
uint8_t interface_protocol;
uint8_t idx_interface;
} __attribute__((packed));
struct usb_desc_endpoint {
uint8_t length;
uint8_t type;
uint8_t address;
uint8_t attributes;
uint16_t max_packet_size;
uint8_t interval;
} __attribute__((packed));
struct usb_desc_string {
uint8_t len;
uint8_t type;
uint16_t data[0];
} __attribute__((packed));
struct usb_desc_device {
uint8_t length;
uint8_t type;
uint16_t bcd_usb;
uint8_t dev_class;
uint8_t dev_subclass;
uint8_t dev_protocol;
uint8_t max_packet_zero;
// After 8 bytes
uint16_t id_vendor;
uint16_t id_product;
uint16_t bcd_device;
uint8_t idx_manufacturer;
uint8_t idx_product;
uint8_t idx_serial_number;
uint8_t num_configurations;
} __attribute__((packed));
+19
View File
@@ -0,0 +1,19 @@
#pragma once
#include "sys/types.h"
#define USB_SPEC_UHCI 0x00
#define USB_SPEED_LOW 0x00
#define USB_SPEED_FULL 0x01
#define USB_SPEED_HIGH 0x02
struct usb_controller {
uint8_t spec;
void (*hc_poll)(struct usb_controller *hc);
struct usb_controller *next;
};
void usb_controller_add(struct usb_controller *hc);
void usb_daemon_start(void);
void usb_poll(void);
+2
View File
@@ -8,5 +8,7 @@ void sched_unqueue(struct thread *thr, enum thread_state new_state);
void sched_debug_cycle(uint64_t delta_ms);
void sched_reboot(unsigned int cmd);
void yield(void);
void sched_init(void);
void sched_enter(void);
+2
View File
@@ -1,5 +1,6 @@
#include "sys/amd64/hw/rs232.h"
#include "sys/driver/pci/pci.h"
#include "sys/driver/usb/usb.h"
#include "sys/amd64/hw/apic.h"
#include "sys/amd64/hw/acpi.h"
#include "sys/amd64/mm/phys.h"
@@ -88,6 +89,7 @@ void kernel_main(struct amd64_loader_data *data) {
sched_init();
sysfs_populate();
usb_daemon_start();
user_init_start();
sched_enter();
+335
View File
@@ -0,0 +1,335 @@
#include "sys/driver/usb/request.h"
#include "sys/driver/usb/device.h"
#include "sys/driver/usb/driver.h"
#include "sys/string.h"
#include "sys/assert.h"
#include "sys/debug.h"
#include "sys/heap.h"
static uint32_t g_device_address = 0;
int usb_device_request(struct usb_device *dev, uint8_t type, uint8_t request, uint16_t index, uint16_t value, uint16_t len, void *data) {
_assert(dev);
struct usb_request req;
req.request = request;
req.type = type;
req.value = value;
req.index = index;
req.length = len;
struct usb_transfer t;
t.request = &req;
t.data = data;
t.length = len;
t.flags = 0;
_assert(dev->hc_control);
dev->hc_control(dev, &t);
return !(t.flags & USB_TRANSFER_SUCCESS);
}
static int usb_device_get_langs(struct usb_device *dev, uint16_t *langs, uint16_t lim) {
char buf[256];
struct usb_desc_string *desc;
int res;
langs[0] = 0;
desc = (struct usb_desc_string *) buf;
// Get string length
if ((res = usb_device_request(dev,
USB_REQUEST_TYPE_D2H,
USB_REQUEST_GET_DESCRIPTOR,
0,
USB_DESCRIPTOR_STRING << 8,
1, desc)) != 0) {
kwarn("Failed to get string descriptor length\n");
return res;
}
if (((desc->len - 2) / 2) >= lim) {
kwarn("Not enough buffer space to store device language data\n");
return -1;
}
// Get lang data
if ((res = usb_device_request(dev,
USB_REQUEST_TYPE_D2H,
USB_REQUEST_GET_DESCRIPTOR,
0,
USB_DESCRIPTOR_STRING << 8,
desc->len, desc))) {
kwarn("Failed to get string descriptor\n");
return res;
}
uint16_t lang_len = (desc->len - 2) / 2;
uint16_t i;
for (i = 0; i < lang_len; ++i) {
langs[i] = desc->data[i];
}
langs[i] = 0;
return 0;
}
static int usb_device_get_string(struct usb_device *dev, char *buf, size_t lim, uint16_t lang, uint16_t index) {
buf[0] = 0;
if (!index) {
return 0;
}
char _buf[256];
struct usb_desc_string *desc = (struct usb_desc_string *) _buf;
int res;
if ((res = usb_device_request(dev,
USB_REQUEST_TYPE_D2H,
USB_REQUEST_GET_DESCRIPTOR,
lang,
(USB_DESCRIPTOR_STRING << 8) | index,
1, desc)) != 0) {
kwarn("Failed to get string length\n");
return res;
}
size_t len = (desc->len - 2) / 2;
// Check that buffer has enough space to fit the string
if (lim <= len) {
return -1;
}
if ((res = usb_device_request(dev,
USB_REQUEST_TYPE_D2H,
USB_REQUEST_GET_DESCRIPTOR,
lang,
(USB_DESCRIPTOR_STRING << 8) | index,
desc->len, desc)) != 0) {
kwarn("Failed to get string length\n");
return res;
}
// Fuck unicode, we're only doing ASCII here
for (size_t i = 0; i < len; ++i) {
buf[i] = (char) desc->data[i];
}
buf[len] = 0;
return len;
}
int usb_device_init(struct usb_device *dev) {
struct usb_desc_device device_desc;
char string_buffer[256];
uint16_t langs[32];
uint32_t dev_addr;
int res;
kinfo("Getting partial descriptor\n");
if ((res = usb_device_request(dev,
USB_REQUEST_TYPE_D2H,
USB_REQUEST_GET_DESCRIPTOR,
0,
USB_DESCRIPTOR_DEVICE << 8,
8, &device_desc)) != 0) {
kwarn("Failed to get device descriptor\n");
return res;
}
dev->max_packet = device_desc.max_packet_zero;
// Allocate a new address for the device
dev_addr = ++g_device_address;
kinfo("Assigning new address\n");
if ((res = usb_device_request(dev,
0,
USB_REQUEST_SET_ADDRESS,
0,
dev_addr,
0, 0))) {
kwarn("Failed to set device address\n");
return res;
}
dev->address = dev_addr;
// Wait a bit
for (size_t _ = 0; _ < 100000; ++_);
kinfo("Reading full descriptor\n");
memset(&device_desc, 0, sizeof(struct usb_desc_device));
// Read full device descriptor
if ((res = usb_device_request(dev,
USB_REQUEST_TYPE_D2H,
USB_REQUEST_GET_DESCRIPTOR,
0,
USB_DESCRIPTOR_DEVICE << 8,
sizeof(struct usb_desc_device), &device_desc)) != 0) {
kwarn("Failed to get full device descriptor\n");
return res;
}
kinfo("Specification version: %04x\n", device_desc.bcd_usb);
kinfo("Device class: %02x:%02x\n", device_desc.dev_class, device_desc.dev_subclass);
kinfo("Protocol: %02x\n", device_desc.dev_protocol);
kinfo("Device ID: %04x:%04x\n", device_desc.id_vendor, device_desc.id_product);
// Dump detailed info
if ((res = usb_device_get_langs(dev, langs, sizeof(langs) / sizeof(langs[0]))) != 0) {
return res;
}
uint16_t lang = langs[0];
if (langs[0]) {
if ((res = usb_device_get_string(dev, string_buffer, sizeof(string_buffer), lang, device_desc.idx_manufacturer)) <= 0) {
kwarn("Failed to get device vendor name\n");
} else {
kinfo("Vendor name: %s\n", string_buffer);
}
if ((res = usb_device_get_string(dev, string_buffer, sizeof(string_buffer), lang, device_desc.idx_product)) <= 0) {
kwarn("Failed to get device product name\n");
} else {
kinfo("Product name: %s\n", string_buffer);
}
} else {
kwarn("No language data for device\n");
}
// Get device configuration
char config_buf[256];
struct usb_desc_configuration *configuration_desc = (struct usb_desc_configuration *) config_buf;
struct usb_desc_interface *interface_desc = NULL;
struct usb_desc_endpoint *endpoint_desc = NULL;
// This stores first valid configuration
uint8_t picked_config_value = 0;
struct usb_desc_interface *picked_interface_desc = NULL;
struct usb_desc_endpoint *picked_endpoint_desc = NULL;
for (uint32_t conf_index = 0; conf_index < device_desc.num_configurations; ++conf_index) {
// Get configuration size
if ((res = usb_device_request(dev,
USB_REQUEST_TYPE_D2H,
USB_REQUEST_GET_DESCRIPTOR,
0,
(USB_DESCRIPTOR_CONFIGURATION << 8) | conf_index,
4, config_buf)) != 0) {
kwarn("Failed to get configuration header\n");
continue;
}
if (configuration_desc->total_length > sizeof(config_buf)) {
kwarn("Configuration buffer too small\n");
continue;
}
// Read the rest of data
if ((res = usb_device_request(dev,
USB_REQUEST_TYPE_D2H,
USB_REQUEST_GET_DESCRIPTOR,
0,
(USB_DESCRIPTOR_CONFIGURATION << 8) | conf_index,
configuration_desc->total_length, config_buf)) != 0) {
kwarn("Failed to get device configuration\n");
continue;
}
// Dump configuration info
kinfo("Device %04x, configuration %u:\n", dev->address, conf_index);
kinfo("Interface count: %u, value: %u\n",
configuration_desc->num_interfaces, configuration_desc->configuration_value);
if (usb_device_get_string(dev, string_buffer, sizeof(string_buffer), lang, configuration_desc->idx_configuration) > 0) {
kinfo("Configuration name: \"%s\"\n", string_buffer);
}
// Select a configuration
void *data = config_buf + configuration_desc->length;
void *end = config_buf + configuration_desc->total_length;
kinfo("Configuration data:\n");
picked_interface_desc = NULL;
picked_endpoint_desc = NULL;
while (data < end) {
uint8_t len = ((uint8_t *) data)[0];
uint8_t type = ((uint8_t *) data)[1];
switch (type) {
case USB_DESCRIPTOR_INTERFACE:
interface_desc = (struct usb_desc_interface *) data;
if (!picked_interface_desc) {
picked_interface_desc = interface_desc;
}
kinfo("* Interface descriptor\n");
kinfo("Number %02x, %u endpoints\n",
interface_desc->interface_number,
interface_desc->num_endpoints);
kinfo("Class: %02x:%02x, Protocol %02x\n",
interface_desc->interface_class,
interface_desc->interface_subclass,
interface_desc->interface_protocol);
if (usb_device_get_string(dev, string_buffer, sizeof(string_buffer), lang, interface_desc->idx_interface) > 0) {
kinfo("Interface name: \"%s\"\n", string_buffer);
}
break;
case USB_DESCRIPTOR_ENDPOINT:
endpoint_desc = (struct usb_desc_endpoint *) data;
if (!picked_endpoint_desc) {
picked_endpoint_desc = endpoint_desc;
}
kinfo("* Endpoint descriptor\n");
kinfo("Address: %02x\n", endpoint_desc->address);
switch (endpoint_desc->attributes & 0x3) {
case 0:
kinfo("Control transfers\n");
break;
case 1:
kinfo("Isochronous transfers\n");
break;
case 2:
kinfo("Bulk transfers\n");
break;
case 3:
kinfo("Interrupt transfers\n");
break;
}
break;
}
data += len;
}
if (picked_interface_desc && picked_endpoint_desc) {
picked_config_value = configuration_desc->configuration_value;
break;
}
}
if (picked_interface_desc && picked_endpoint_desc) {
kinfo("Configuring device with value %02x\n", picked_config_value);
if ((res = usb_device_request(dev,
0,
USB_REQUEST_SET_CONFIGURATION,
0,
picked_config_value,
0, 0)) != 0) {
return res;
}
memcpy(&dev->desc_interface, picked_interface_desc, sizeof(struct usb_desc_interface));
memcpy(&dev->desc_endpoint, picked_endpoint_desc, sizeof(struct usb_desc_endpoint));
if ((res = usb_select_driver(dev)) != 0) {
kwarn("Failed to pick driver for the device\n");
}
}
return 0;
}
+19
View File
@@ -0,0 +1,19 @@
#include "sys/driver/usb/driver.h"
#include "sys/types.h"
static struct usb_driver *g_driver_head = NULL;
int usb_select_driver(struct usb_device *dev) {
for (struct usb_driver *drv = g_driver_head; drv; drv = drv->next) {
if (drv->usb_init && drv->usb_init(dev) == 0) {
return 0;
}
}
return -1;
}
void usb_add_driver(struct usb_driver *drv) {
drv->next = g_driver_head;
g_driver_head = drv;
}
+68
View File
@@ -0,0 +1,68 @@
#include "sys/driver/usb/device.h"
#include "sys/driver/usb/driver.h"
#include "sys/driver/usb/usb.h"
#include "sys/amd64/cpu.h"
#include "sys/thread.h"
#include "sys/assert.h"
#include "sys/sched.h"
#include "sys/debug.h"
#include "sys/heap.h"
static struct usb_controller *g_hc_list = NULL;
static struct usb_device *g_usb_devices = NULL;
struct usb_device *usb_device_create(void) {
struct usb_device *res = kmalloc(sizeof(struct usb_device));
_assert(res);
res->hc_control = NULL;
res->next = g_usb_devices;
res->driver = NULL;
g_usb_devices = res;
return res;
}
void usb_poll(void) {
for (struct usb_controller *hc = g_hc_list; hc; hc = hc->next) {
if (hc->hc_poll) {
hc->hc_poll(hc);
}
}
for (struct usb_device *dev = g_usb_devices; dev; dev = dev->next) {
if (dev->driver && dev->driver->usb_poll) {
dev->driver->usb_poll(dev);
}
}
}
static void *usb_daemon(void *arg) {
kinfo("USB daemon started\n");
while (1) {
usb_poll();
// Sleep for 10ms
thread_sleep(thread_self, system_time + 10000000ULL, NULL);
}
panic("This code should not run\n");
}
void usb_daemon_start(void) {
static struct thread usbd_thread;
if (!g_hc_list) {
kinfo("Not starting USB daemon - no HCs\n");
// No controllers to poll
return;
}
_assert(thread_init(&usbd_thread, (uintptr_t) usb_daemon, NULL, 0) == 0);
usbd_thread.pid = thread_alloc_pid(0);
sched_queue(&usbd_thread);
}
void usb_controller_add(struct usb_controller *hc) {
hc->next = g_hc_list;
g_hc_list = hc;
}
+38 -36
View File
@@ -1,13 +1,14 @@
#include "sys/amd64/hw/pci/usb_uhci.h"
#include "sys/driver/usb/request.h"
#include "sys/driver/usb/device.h"
#include "sys/driver/pci/pci.h"
#include "sys/driver/usb/usb.h"
#include "sys/amd64/mm/phys.h"
#include "sys/amd64/hw/io.h"
#include "sys/usb/request.h"
#include "sys/usb/device.h"
#include "sys/usb/usb.h"
#include "sys/string.h"
#include "sys/assert.h"
#include "sys/debug.h"
#include "sys/heap.h"
#include "sys/attr.h"
#include "sys/mm.h"
#define IO_USBCMD 0x00
@@ -444,7 +445,7 @@ static void uhci_device_control(struct usb_device *dev, struct usb_transfer *t)
}
}
/* static */ void uhci_poll(struct usb_controller *_hc) {
static void uhci_poll(struct usb_controller *_hc) {
struct uhci *hc = (struct uhci *) _hc;
struct uhci_qh *qh = hc->qh_async;
@@ -461,34 +462,35 @@ static void uhci_device_control(struct usb_device *dev, struct usb_transfer *t)
}
}
//void pci_usb_uhci_init(pci_addr_t addr) {
//}
// uint32_t bar4;
// struct uhci *hc = kmalloc(sizeof(struct uhci));
// _assert(hc);
//
// kdebug("Initializing USB UHCI at " PCI_FMTADDR "\n", PCI_VAADDR(addr));
//
// bar4 = pci_config_read_dword(addr, PCI_CONFIG_BAR(4));
// _assert(bar4 & 1);
// uhci_data_init(hc, bar4);
// kdebug("Base addr %p\n", hc->frame_list);
//
// // Disable IRQs
// outw(hc->iobase + IO_USBINTR, 0);
// // Setup frame lists
// outl(hc->iobase + IO_FRBASEADD, (uint32_t) MM_PHYS(hc->frame_list));
// outw(hc->iobase + IO_FRNUM, 0);
// outw(hc->iobase + IO_SOFMOD, 0x40);
// // Clear status
// outw(hc->iobase + IO_USBSTS, 0xFFFF);
// // Enable controller
// outw(hc->iobase + IO_USBCMD, USBCMD_RUN);
//
// uhci_probe(hc);
//
// hc->hc.spec = USB_SPEC_UHCI;
// hc->hc.hc_poll = uhci_poll;
//
// usb_controller_add((struct usb_controller *) hc);
//}
void pci_usb_uhci_init(struct pci_device *pci_dev) {
uint32_t bar4;
struct uhci *hc = kmalloc(sizeof(struct uhci));
_assert(hc);
bar4 = pci_config_read_dword(pci_dev, PCI_CONFIG_BAR(4));
_assert(bar4 & 1);
uhci_data_init(hc, bar4);
kdebug("Base addr %p\n", hc->frame_list);
// Disable IRQs
outw(hc->iobase + IO_USBINTR, 0);
// Setup frame lists
outl(hc->iobase + IO_FRBASEADD, (uint32_t) MM_PHYS(hc->frame_list));
outw(hc->iobase + IO_FRNUM, 0);
outw(hc->iobase + IO_SOFMOD, 0x40);
// Clear status
outw(hc->iobase + IO_USBSTS, 0xFFFF);
// Enable controller
outw(hc->iobase + IO_USBCMD, USBCMD_RUN);
uhci_probe(hc);
hc->hc.spec = USB_SPEC_UHCI;
hc->hc.hc_poll = uhci_poll;
usb_controller_add((struct usb_controller *) hc);
}
static __init void pci_usb_uhci_register(void) {
pci_add_class_driver(0x0C0300, pci_usb_uhci_init);
}
+154
View File
@@ -0,0 +1,154 @@
#include "sys/driver/usb/driver.h"
#include "sys/driver/usb/device.h"
#include "sys/driver/usb/const.h"
#include "sys/char/input.h"
#include "sys/char/tty.h"
#include "sys/string.h"
#include "sys/assert.h"
#include "sys/debug.h"
#include "sys/attr.h"
#include "sys/heap.h"
#define USB_KBD_MOD_SHIFT ((1 << 1) | (1 << 5))
#define USB_KBD_MOD_CONTROL ((1 << 0) | (1 << 4))
#define USB_KBD_CAPS 0x39
static int usb_kbd_init(struct usb_device *dev);
static void usb_kbd_poll(struct usb_device *dev);
static const char usb_kbd_ascii_0[256] = {
0,
[0x04] = 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
[0x0C] = 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
[0x14] = 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
[0x1C] = 'y', 'z', '1', '2', '3', '4', '5', '6',
[0x24] = '7', '8', '9', '0',
[0x28] = '\n', '\033', '\b', '\t',
[0x2C] = ' ', '-', '=', '[', ']', '\\', '.', ';',
[0x34] = '\'', '`', ',', '.', '/',
// ...
[0x4F] = INPUT_KEY_RIGHT,
[0x50] = INPUT_KEY_LEFT,
[0x51] = INPUT_KEY_DOWN,
[0x52] = INPUT_KEY_UP,
};
static const char usb_kbd_ascii_1[256] = {
0,
[0x04] = 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
[0x0C] = 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
[0x14] = 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
[0x1C] = 'Y', 'Z', '!', '@', '#', '$', '%', '^',
[0x24] = '&', '*', '(', ')',
[0x28] = '\n', '\033', '\b', '\t',
[0x2C] = ' ', '_', '+', '{', '}', '|', '.', ':',
[0x34] = '"', '~', '<', '>', '?',
// ...
[0x4F] = INPUT_KEY_RIGHT,
[0x50] = INPUT_KEY_LEFT,
[0x51] = INPUT_KEY_DOWN,
[0x52] = INPUT_KEY_UP,
};
struct usb_kbd_data {
struct usb_transfer transfer;
uint8_t mods;
char buf[8];
char keys_down[6];
};
static struct usb_driver g_usbkbd = {
.usb_init = usb_kbd_init,
.usb_poll = usb_kbd_poll
};
static void usb_kbd_handle_data(struct usb_kbd_data *data) {
data->mods &= ~(INPUT_MOD_CONTROL | INPUT_MOD_SHIFT);
if (data->buf[0] & USB_KBD_MOD_SHIFT) {
data->mods |= INPUT_MOD_SHIFT;
}
if (data->buf[0] & USB_KBD_MOD_CONTROL) {
data->mods |= INPUT_MOD_CONTROL;
}
for (size_t i = 2; i < 8; ++i) {
uint8_t key = data->buf[i];
if (key >= 4) {
if (!memchr(data->keys_down, data->buf[i], 6)) {
if (key == 0x39) {
data->mods ^= INPUT_MOD_CAPS;
} else {
// Key press detected
input_key(data->buf[i], data->mods, usb_kbd_ascii_0, usb_kbd_ascii_1);
}
}
} else if (key) {
kinfo("Invalid key: %02x\n", key);
}
}
memcpy(data->keys_down, &data->buf[2], 6);
}
static void usb_kbd_poll(struct usb_device *dev) {
struct usb_kbd_data *data = dev->driver_data;
_assert(data);
struct usb_transfer *t = &data->transfer;
if (t->flags & USB_TRANSFER_COMPLETE) {
if (t->flags & USB_TRANSFER_SUCCESS) {
usb_kbd_handle_data(data);
}
t->flags = 0;
t->data = data->buf;
t->length = 8;
dev->endpoint_toggle ^= 1;
_assert(dev->hc_interrupt);
dev->hc_interrupt(dev, t);
}
}
static int usb_kbd_init(struct usb_device *dev) {
int res;
if (dev->desc_interface.interface_class == USB_CLASS_HID &&
dev->desc_interface.interface_subclass == USB_SUBCLASS_BOOT &&
dev->desc_interface.interface_protocol == USB_PROTOCOL_KEYBOARD) {
kinfo("Found keyboard!\n");
uint8_t interface_index = dev->desc_interface.idx_interface;
if ((res = usb_device_request(dev,
USB_REQUEST_TYPE_CLASS | USB_REQUEST_TO_INTERFACE,
0x0A,
interface_index,
0,
0, 0)) != 0) {
kwarn("USB_REQUEST_SET_IDLE failed\n");
}
dev->driver = &g_usbkbd;
struct usb_kbd_data *data = kmalloc(sizeof(struct usb_kbd_data));
_assert(data);
struct usb_transfer *t = &data->transfer;
t->endp = dev->desc_endpoint.address & 0xF;
t->request = 0;
t->data = data->buf;
t->length = 8;
t->flags = 0;
dev->driver_data = data;
_assert(dev->hc_interrupt);
dev->hc_interrupt(dev, t);
return 0;
}
return -1;
}
static __init void usb_kbd_register_driver(void) {
usb_add_driver(&g_usbkbd);
}
+1 -1
View File
@@ -212,7 +212,7 @@ void sched_reboot(unsigned int cmd) {
void sched_init(void) {
thread_init(&thread_idle, (uintptr_t) idle, 0, 0);
thread_idle.pid = -1;
thread_idle.pid = 0;
}
void sched_enter(void) {