Backport USB driver + UHCI
This commit is contained in:
+8
-2
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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));
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user