Kernel: Add basic support for USB hubs

This is still buggy and some hubs lead to usb transaction errors. I'll
have to debug this but this shouldn't prevent any already working device
from working
This commit is contained in:
2025-02-10 22:56:25 +02:00
parent 803a4cd163
commit ad143c184f
13 changed files with 780 additions and 13 deletions

View File

@@ -65,6 +65,7 @@
#define DEBUG_XHCI 0
#define DEBUG_USB 0
#define DEBUG_USB_HID 0
#define DEBUG_USB_HUB 0
#define DEBUG_USB_KEYBOARD 0
#define DEBUG_USB_MOUSE 0
#define DEBUG_USB_MASS_STORAGE 0

View File

@@ -1,10 +1,26 @@
#pragma once
#include <BAN/Array.h>
#include <kernel/Lock/SpinLock.h>
namespace Kernel
{
class USBController
{
// NOTE: Tier 0 == Root Hub
public:
USBController();
uint8_t current_hub_init_tier() const;
void register_hub_to_init(uint8_t tier);
void mark_hub_init_done(uint8_t tier);
private:
mutable SpinLock m_hub_init_lock;
uint8_t m_current_hub_init_tier { 0 };
BAN::Array<uint32_t, 7> m_hubs_to_init_per_tier;
};
}

View File

@@ -55,9 +55,18 @@ namespace Kernel
BAN::Vector<ConfigurationDescriptor> configurations;
};
struct HubInfo
{
uint8_t number_of_ports;
bool multi_tt;
uint8_t tt_think_time;
};
public:
USBDevice(USB::SpeedClass speed_class)
: m_speed_class(speed_class)
USBDevice(USBController& controller, USB::SpeedClass speed_class, uint8_t depth)
: m_controller(controller)
, m_speed_class(speed_class)
, m_depth(depth)
{}
virtual ~USBDevice() = default;
@@ -68,13 +77,20 @@ namespace Kernel
const BAN::Vector<ConfigurationDescriptor>& configurations() { return m_descriptor.configurations; }
virtual BAN::ErrorOr<void> configure_endpoint(const USBEndpointDescriptor&) = 0;
virtual BAN::ErrorOr<uint8_t> initialize_device_on_hub_port(uint8_t port_id, USB::SpeedClass) = 0;
virtual void deinitialize_device_slot(uint8_t slot_id) = 0;
virtual BAN::ErrorOr<void> configure_endpoint(const USBEndpointDescriptor&, const HubInfo& = {}) = 0;
virtual BAN::ErrorOr<size_t> send_request(const USBDeviceRequest&, paddr_t buffer) = 0;
virtual void send_data_buffer(uint8_t endpoint_id, paddr_t buffer, size_t buffer_len) = 0;
USB::SpeedClass speed_class() const { return m_speed_class; }
uint8_t depth() const { return m_depth; }
bool can_start_hub_init() const { return m_controller.current_hub_init_tier() >= m_depth + 1; }
void register_hub_to_init() { m_controller.register_hub_to_init(m_depth + 1); };
void mark_hub_init_done() { m_controller.mark_hub_init_done(m_depth + 1); };
protected:
void handle_stall(uint8_t endpoint_id);
void handle_input_data(size_t byte_count, uint8_t endpoint_id);
@@ -83,8 +99,12 @@ namespace Kernel
private:
BAN::ErrorOr<ConfigurationDescriptor> parse_configuration(size_t index);
private:
USBController& m_controller;
protected:
const USB::SpeedClass m_speed_class;
const uint8_t m_depth;
private:
DeviceDescriptor m_descriptor;

View File

@@ -0,0 +1,95 @@
#pragma once
#include <stdint.h>
namespace Kernel::USBHub
{
struct HubDescriptor
{
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bNbrPorts;
uint16_t wHubCharacteristics;
uint8_t bPowerOnGood;
uint8_t bHubContrCurrent;
uint8_t bitmaps[];
} __attribute__((packed));
static_assert(sizeof(HubDescriptor) == 7);
struct PortStatus
{
union
{
uint16_t raw;
struct {
uint16_t connection : 1; // bit 0
uint16_t enable : 1; // bit 1
uint16_t : 1;
uint16_t over_current : 1; // bit 3
uint16_t reset : 1; // bit 4
};
struct {
uint16_t : 2;
uint16_t suspend : 1; // bit 2
uint16_t : 5;
uint16_t power : 1; // bit 8
uint16_t low_speed : 1; // bit 9
uint16_t high_speed : 1; // bit 10
} usb2;
struct {
uint16_t : 5;
uint16_t link_state : 4; // bit 5-8
uint16_t power : 1; // bit 9
uint16_t speed : 3; // bit 10-12
} usb3;
} wPortStatus;
union
{
uint16_t raw;
struct {
uint16_t connection : 1; // bit 0
uint16_t : 2;
uint16_t over_current : 1; // bit 3
uint16_t reset : 1; // bit 4
};
struct {
uint16_t : 1;
uint16_t enable : 1; // bit 1
uint16_t suspend : 1; // bit 2
} usb2;
struct {
uint16_t : 5;
uint16_t bh_reset : 1; // bit 5
uint16_t link_state : 1; // bit 6
uint16_t config_error : 1; // bit 7
} usb3;
} wPortChanged;
};
static_assert(sizeof(PortStatus) == 4);
enum HubSelector
{
C_HUB_LOCAL_POWER = 0,
C_HUB_OVER_CURRENT = 1,
PORT_CONNECTION = 0,
PORT_ENABLE = 1,
PORT_SUSPEND = 2,
PORT_OVER_CURRENT = 3,
PORT_RESET = 4,
PORT_LINK_STATE = 5,
PORT_POWER = 8,
PORT_LOW_SPEED = 9,
C_PORT_CONNECTION = 16,
C_PORT_ENABLE = 17,
C_PORT_SUSPEND = 18,
C_PORT_OVER_CURRENT = 19,
C_PORT_RESET = 20,
PORT_TEST = 21,
PORT_INDICATOR = 22,
C_PORT_LINK_STATE = 25,
C_PORT_CONFIG_ERROR = 26,
C_BH_PORT_RESET = 29,
};
}

View File

@@ -0,0 +1,57 @@
#pragma once
#include <kernel/Process.h>
#include <kernel/USB/Device.h>
namespace Kernel
{
class USBHubDriver final : public USBClassDriver
{
public:
BAN::ErrorOr<void> initialize() override;
void handle_stall(uint8_t endpoint_id) override;
void handle_input_data(size_t byte_count, uint8_t endpoint_id) override;
private:
USBHubDriver(USBDevice&, const USBDevice::DeviceDescriptor&);
~USBHubDriver();
void port_updater_task();
BAN::ErrorOr<void> clear_port_feature(uint8_t port, uint8_t feature);
BAN::ErrorOr<void> set_port_feature(uint8_t port, uint8_t feature);
private:
USBDevice& m_device;
const USBDevice::DeviceDescriptor& m_descriptor;
BAN::UniqPtr<DMARegion> m_data_region;
uint8_t m_endpoint_id { 0 };
uint8_t m_port_count { 0 };
BAN::Atomic<uint32_t> m_changed_ports { 0 };
ThreadBlocker m_changed_port_blocker;
BAN::Atomic<Process*> m_port_updater { nullptr };
struct PortInfo
{
uint8_t slot { 0 };
bool failed { false };
};
BAN::Vector<PortInfo> m_ports;
BAN::Atomic<bool> m_running { true };
bool m_is_usb2 { false };
bool m_is_usb3 { false };
bool m_is_multi_tt { false };
bool m_is_init_done { false };
friend class BAN::UniqPtr<USBHubDriver>;
};
}

View File

@@ -46,7 +46,7 @@ namespace Kernel
void port_updater_task();
BAN::ErrorOr<uint8_t> initialize_device(uint32_t route_string, USB::SpeedClass speed_class);
BAN::ErrorOr<uint8_t> initialize_device(uint32_t route_string, uint8_t depth, USB::SpeedClass speed_class, XHCIDevice* parent_hub, uint8_t parent_port_id);
void deinitialize_slot(uint8_t slot_id);
BAN::ErrorOr<XHCI::TRB> send_command(const XHCI::TRB&);
@@ -77,6 +77,8 @@ namespace Kernel
ThreadBlocker m_port_thread_blocker;
BAN::Atomic<bool> m_port_changed { false };
bool m_ports_initialized { false };
PCI::Device& m_pci_device;
BAN::UniqPtr<PCI::BarRegion> m_configuration_bar;
BAN::UniqPtr<DMARegion> m_dcbaa_region;

View File

@@ -32,15 +32,21 @@ namespace Kernel
struct Info
{
XHCIDevice* parent_hub;
uint8_t parent_port_id;
USB::SpeedClass speed_class;
uint8_t slot_id;
uint32_t route_string;
uint8_t depth;
};
public:
static BAN::ErrorOr<BAN::UniqPtr<XHCIDevice>> create(XHCIController&, const Info& info);
BAN::ErrorOr<void> configure_endpoint(const USBEndpointDescriptor&) override;
BAN::ErrorOr<uint8_t> initialize_device_on_hub_port(uint8_t port_id, USB::SpeedClass) override;
void deinitialize_device_slot(uint8_t slot_id) override;
BAN::ErrorOr<void> configure_endpoint(const USBEndpointDescriptor&, const HubInfo&) override;
BAN::ErrorOr<size_t> send_request(const USBDeviceRequest&, paddr_t buffer) override;
void send_data_buffer(uint8_t endpoint_id, paddr_t buffer, size_t buffer_size) override;
@@ -55,6 +61,8 @@ namespace Kernel
BAN::ErrorOr<void> update_actual_max_packet_size();
bool is_multi_tt() const;
void on_interrupt_or_bulk_endpoint_event(XHCI::TRB);
void advance_endpoint_enqueue(Endpoint&, bool chain);