Compare commits

...

17 Commits

Author SHA1 Message Date
Bananymous d0452a3510 Kernel: Fix xHCI controller destruction
Port updater task was not actually able to exit without a kernel panic.
This patch makes controller wait until port updater exits itself :D
2025-02-10 22:58:57 +02:00
Bananymous 11310e7615 Kernel: Don't manually clear xHCI interrupt flag if using MSI 2025-02-10 22:58:14 +02:00
Bananymous 22b32a0fe5 Kernel: Expose PCI interrupt mechanism from PCIDevice 2025-02-10 22:57:25 +02:00
Bananymous ad143c184f 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
2025-02-10 22:56:25 +02:00
Bananymous 803a4cd163 Kernel: Don't enable ACPI devices when ACPI is disabled
This really didn't make any sense. There are no ACPI device to be
initialized when AML is not parsed :D
2025-02-07 21:35:25 +02:00
Bananymous 267fdf9fa1 Kernel: Remove storage devices after unplugging them 2025-02-07 18:04:54 +02:00
Bananymous 26d2a4420e Kernel: Don't limit xHCI TRB transfer length to max packet size
This made no sense and just used a ton of TRBs.

This patch also fixes some incorrectly set flags in data/status stage
TRBs.
2025-02-06 23:18:14 +02:00
Bananymous c623ad7da0 Kernel: Use correct USB endpoint field to determine interval
I was using the wrong endpoint descriptor field which caused intervals
to be messed up.
2025-02-06 23:18:14 +02:00
Bananymous 7de689055c Kernel: Pass xHCI device information in structs
This makes code more readable and extendable
2025-02-06 23:18:14 +02:00
Bananymous 63b15a8855 Kernel: Rename USB initialize_endpoint -> configure_endpoint
This makes more sense as the USB command is CONFIGURE_ENDPOINT

Also configure_endpoint can be called multiple times on the same
endpoint. There was no reason to limit this to only one call.
2025-02-06 22:10:00 +02:00
Bananymous a2a7302964 Kernel: Make sure USB class driver is deinitialized before xhci device 2025-02-06 22:00:26 +02:00
Bananymous 6a5367dbe3 Kernel: Don't initialize USB alternate interfaces 2025-02-06 21:43:15 +02:00
Bananymous 6768a18475 Kernel: Don't parse xHCI custom slot_types
xHCI spec mandates that slot_type for USB protocol is 0.
2025-02-06 21:41:44 +02:00
Bananymous 242ed4a3c2 Kernel: Remove support for custom xHCI speed_ids
This gets really weird with hubs and I don't think even linux handles
them.
2025-02-06 21:38:30 +02:00
Bananymous f9b70d1b5b Kernel: Don't enter infinite loop on unexpected serial behaviour 2025-02-06 20:59:17 +02:00
Bananymous faa5252191 Kernel: Fix TTY ANSI CSI m and prevent crash :) 2025-02-06 20:58:03 +02:00
Bananymous 4212f48d7a bootloader: Cleanup memcpy and memset
There isn't really any reason to do 32 bit moves
2025-02-06 20:56:35 +02:00
26 changed files with 1061 additions and 245 deletions

View File

@ -306,20 +306,8 @@ memset32:
movw $GDT_DATA32, %dx movw $GDT_DATA32, %dx
movw %dx, %es movw %dx, %es
movl %ecx, %edx
andl $3, %ecx
rep stosb %es:(%edi) rep stosb %es:(%edi)
movl %edx, %ecx
shrl $2, %ecx
movb %al, %ah
movw %ax, %dx
shll $16, %eax
movw %dx, %ax
rep stosl %es:(%edi)
ljmpl $GDT_CODE16, $.memset32_pmode16 ljmpl $GDT_CODE16, $.memset32_pmode16
.code16 .code16
@ -370,14 +358,8 @@ memcpy32:
movw %dx, %ds movw %dx, %ds
movw %dx, %es movw %dx, %es
movl %ecx, %edx
andl $3, %ecx
rep movsb %ds:(%esi), %es:(%edi) rep movsb %ds:(%esi), %es:(%edi)
movl %edx, %ecx
shrl $2, %ecx
rep movsl %ds:(%esi), %es:(%edi)
ljmpl $GDT_CODE16, $.memcpy32_pmode16 ljmpl $GDT_CODE16, $.memcpy32_pmode16
.code16 .code16

View File

@ -96,10 +96,12 @@ set(KERNEL_SOURCES
kernel/Timer/PIT.cpp kernel/Timer/PIT.cpp
kernel/Timer/RTC.cpp kernel/Timer/RTC.cpp
kernel/Timer/Timer.cpp kernel/Timer/Timer.cpp
kernel/USB/Controller.cpp
kernel/USB/Device.cpp kernel/USB/Device.cpp
kernel/USB/HID/HIDDriver.cpp kernel/USB/HID/HIDDriver.cpp
kernel/USB/HID/Keyboard.cpp kernel/USB/HID/Keyboard.cpp
kernel/USB/HID/Mouse.cpp kernel/USB/HID/Mouse.cpp
kernel/USB/Hub/HubDriver.cpp
kernel/USB/MassStorage/MassStorageDriver.cpp kernel/USB/MassStorage/MassStorageDriver.cpp
kernel/USB/MassStorage/SCSIDevice.cpp kernel/USB/MassStorage/SCSIDevice.cpp
kernel/USB/USBManager.cpp kernel/USB/USBManager.cpp

View File

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

View File

@ -28,7 +28,7 @@ namespace Kernel
virtual BAN::ErrorOr<void> fsync_impl() final override { return BAN::Error::from_errno(EINVAL); } virtual BAN::ErrorOr<void> fsync_impl() final override { return BAN::Error::from_errno(EINVAL); }
}; };
class BlockDevice : public Device class BlockDevice : public Device, public BAN::Weakable<BlockDevice>
{ {
public: public:
virtual BAN::ErrorOr<void> read_blocks(uint64_t first_block, size_t block_count, BAN::ByteSpan) = 0; virtual BAN::ErrorOr<void> read_blocks(uint64_t first_block, size_t block_count, BAN::ByteSpan) = 0;

View File

@ -97,6 +97,8 @@ namespace Kernel::PCI
BAN::ErrorOr<void> reserve_interrupts(uint8_t count); BAN::ErrorOr<void> reserve_interrupts(uint8_t count);
void enable_interrupt(uint8_t index, Interruptable&); void enable_interrupt(uint8_t index, Interruptable&);
InterruptMechanism interrupt_mechanism() const { return m_interrupt_mechanism; }
BAN::ErrorOr<BAN::UniqPtr<BarRegion>> allocate_bar_region(uint8_t bar_num); BAN::ErrorOr<BAN::UniqPtr<BarRegion>> allocate_bar_region(uint8_t bar_num);
void enable_bus_mastering(); void enable_bus_mastering();

View File

@ -13,9 +13,8 @@ namespace Kernel
const BAN::GUID& partition_type() const { return m_type; } const BAN::GUID& partition_type() const { return m_type; }
const BAN::GUID& partition_guid() const { return m_guid; } const BAN::GUID& partition_guid() const { return m_guid; }
const BAN::RefPtr<BlockDevice> device() const { return m_device; }
virtual blksize_t blksize() const override { return m_device->blksize(); } virtual blksize_t blksize() const override { return m_block_size; }
BAN::ErrorOr<void> read_sectors(uint64_t first_block, size_t block_count, BAN::ByteSpan buffer) { return read_blocks(first_block, block_count, buffer); } BAN::ErrorOr<void> read_sectors(uint64_t first_block, size_t block_count, BAN::ByteSpan buffer) { return read_blocks(first_block, block_count, buffer); }
BAN::ErrorOr<void> write_sectors(uint64_t first_block, size_t block_count, BAN::ConstByteSpan buffer) { return write_blocks(first_block, block_count, buffer); } BAN::ErrorOr<void> write_sectors(uint64_t first_block, size_t block_count, BAN::ConstByteSpan buffer) { return write_blocks(first_block, block_count, buffer); }
@ -32,7 +31,8 @@ namespace Kernel
Partition(BAN::RefPtr<BlockDevice>, const BAN::GUID&, const BAN::GUID&, uint64_t, uint64_t, uint64_t, const char*, uint32_t, BAN::StringView); Partition(BAN::RefPtr<BlockDevice>, const BAN::GUID&, const BAN::GUID&, uint64_t, uint64_t, uint64_t, const char*, uint32_t, BAN::StringView);
private: private:
BAN::RefPtr<BlockDevice> m_device; mutable BAN::WeakPtr<BlockDevice> m_device;
const uint64_t m_block_size;
const BAN::GUID m_type; const BAN::GUID m_type;
const BAN::GUID m_guid; const BAN::GUID m_guid;
const BAN::String m_guid_string; const BAN::String m_guid_string;

View File

@ -2,6 +2,7 @@
#include <BAN/CircularQueue.h> #include <BAN/CircularQueue.h>
#include <BAN/Errors.h> #include <BAN/Errors.h>
#include <BAN/Optional.h>
#include <kernel/Interruptable.h> #include <kernel/Interruptable.h>
#include <kernel/Terminal/TTY.h> #include <kernel/Terminal/TTY.h>
@ -13,12 +14,12 @@ namespace Kernel
public: public:
static void initialize(); static void initialize();
static bool has_devices(); static bool has_devices();
static void putchar_any(char); static void putchar_any(uint8_t);
static void initialize_devices(); static void initialize_devices();
void putchar(char); void putchar(uint8_t);
char getchar(); BAN::Optional<uint8_t> getchar();
bool is_valid() const { return m_port != 0; } bool is_valid() const { return m_port != 0; }

View File

@ -30,7 +30,7 @@ namespace Kernel
void reset_ansi(); void reset_ansi();
void handle_ansi_csi(uint8_t ch); void handle_ansi_csi(uint8_t ch);
void handle_ansi_csi_color(); void handle_ansi_csi_color(uint8_t ch);
void putchar_at(uint32_t codepoint, uint32_t x, uint32_t y); void putchar_at(uint32_t codepoint, uint32_t x, uint32_t y);
void render_from_buffer(uint32_t x, uint32_t y); void render_from_buffer(uint32_t x, uint32_t y);
void set_cursor_position(uint32_t x, uint32_t y); void set_cursor_position(uint32_t x, uint32_t y);

View File

@ -1,10 +1,26 @@
#pragma once #pragma once
#include <BAN/Array.h>
#include <kernel/Lock/SpinLock.h>
namespace Kernel namespace Kernel
{ {
class USBController 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

@ -4,8 +4,8 @@
#include <BAN/NoCopyMove.h> #include <BAN/NoCopyMove.h>
#include <kernel/Memory/DMARegion.h> #include <kernel/Memory/DMARegion.h>
#include <kernel/USB/USBManager.h>
#include <kernel/USB/Controller.h> #include <kernel/USB/Controller.h>
#include <kernel/USB/USBManager.h>
namespace Kernel namespace Kernel
{ {
@ -55,21 +55,41 @@ namespace Kernel
BAN::Vector<ConfigurationDescriptor> configurations; BAN::Vector<ConfigurationDescriptor> configurations;
}; };
struct HubInfo
{
uint8_t number_of_ports;
bool multi_tt;
uint8_t tt_think_time;
};
public: public:
USBDevice(USB::SpeedClass speed_class) USBDevice(USBController& controller, USB::SpeedClass speed_class, uint8_t depth)
: m_speed_class(speed_class) : m_controller(controller)
, m_speed_class(speed_class)
, m_depth(depth)
{} {}
virtual ~USBDevice() = default; virtual ~USBDevice() = default;
// Class drivers have to be destroyed before derived class destructor is called
void destroy() { m_class_drivers.clear(); }
BAN::ErrorOr<void> initialize(); BAN::ErrorOr<void> initialize();
const BAN::Vector<ConfigurationDescriptor>& configurations() { return m_descriptor.configurations; } const BAN::Vector<ConfigurationDescriptor>& configurations() { return m_descriptor.configurations; }
virtual BAN::ErrorOr<void> initialize_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 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; virtual void send_data_buffer(uint8_t endpoint_id, paddr_t buffer, size_t buffer_len) = 0;
static USB::SpeedClass determine_speed_class(uint64_t bits_per_second); 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: protected:
void handle_stall(uint8_t endpoint_id); void handle_stall(uint8_t endpoint_id);
@ -79,8 +99,12 @@ namespace Kernel
private: private:
BAN::ErrorOr<ConfigurationDescriptor> parse_configuration(size_t index); BAN::ErrorOr<ConfigurationDescriptor> parse_configuration(size_t index);
private:
USBController& m_controller;
protected: protected:
const USB::SpeedClass m_speed_class; const USB::SpeedClass m_speed_class;
const uint8_t m_depth;
private: private:
DeviceDescriptor m_descriptor; 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

@ -5,6 +5,7 @@
#include <kernel/Lock/Mutex.h> #include <kernel/Lock/Mutex.h>
#include <kernel/Memory/DMARegion.h> #include <kernel/Memory/DMARegion.h>
#include <kernel/ThreadBlocker.h> #include <kernel/ThreadBlocker.h>
#include <kernel/USB/Definitions.h>
#include <kernel/USB/USBManager.h> #include <kernel/USB/USBManager.h>
#include <kernel/USB/XHCI/Definitions.h> #include <kernel/USB/XHCI/Definitions.h>
@ -23,19 +24,7 @@ namespace Kernel
{ {
uint8_t revision_major { 0 }; uint8_t revision_major { 0 };
uint8_t revision_minor { 0 }; uint8_t revision_minor { 0 };
uint8_t slot_type { 0 };
uint8_t slot_id { 0 }; uint8_t slot_id { 0 };
uint64_t speed_id_to_speed[0x10] {
0,
12'000'000,
1'500'000,
480'000'000,
5'000'000'000,
10'000'000'000,
5'000'000'000,
10'000'000'000,
};
}; };
public: public:
@ -57,7 +46,8 @@ namespace Kernel
void port_updater_task(); void port_updater_task();
BAN::ErrorOr<void> initialize_slot(int port_index); 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&); BAN::ErrorOr<XHCI::TRB> send_command(const XHCI::TRB&);
void advance_command_enqueue(); void advance_command_enqueue();
@ -74,16 +64,22 @@ namespace Kernel
const volatile XHCI::TRB& current_event_trb(); const volatile XHCI::TRB& current_event_trb();
uint8_t speed_class_to_id(USB::SpeedClass speed_class) const;
USB::SpeedClass speed_id_to_class(uint8_t) const;
private: private:
static constexpr uint32_t m_command_ring_trb_count = 256; static constexpr uint32_t m_command_ring_trb_count = 256;
static constexpr uint32_t m_event_ring_trb_count = 252; static constexpr uint32_t m_event_ring_trb_count = 252;
Mutex m_mutex; Mutex m_mutex;
Process* m_port_updater { nullptr }; BAN::Atomic<Process*> m_port_updater { nullptr };
ThreadBlocker m_port_thread_blocker; ThreadBlocker m_port_thread_blocker;
BAN::Atomic<bool> m_port_changed { false }; BAN::Atomic<bool> m_port_changed { false };
bool m_running { true };
bool m_ports_initialized { false };
PCI::Device& m_pci_device; PCI::Device& m_pci_device;
BAN::UniqPtr<PCI::BarRegion> m_configuration_bar; BAN::UniqPtr<PCI::BarRegion> m_configuration_bar;
BAN::UniqPtr<DMARegion> m_dcbaa_region; BAN::UniqPtr<DMARegion> m_dcbaa_region;

View File

@ -30,10 +30,23 @@ namespace Kernel
void(XHCIDevice::*callback)(XHCI::TRB); void(XHCIDevice::*callback)(XHCI::TRB);
}; };
public: struct Info
static BAN::ErrorOr<BAN::UniqPtr<XHCIDevice>> create(XHCIController&, uint32_t port_id, uint32_t slot_id); {
XHCIDevice* parent_hub;
uint8_t parent_port_id;
USB::SpeedClass speed_class;
uint8_t slot_id;
uint32_t route_string;
uint8_t depth;
};
BAN::ErrorOr<void> initialize_endpoint(const USBEndpointDescriptor&) override; public:
static BAN::ErrorOr<BAN::UniqPtr<XHCIDevice>> create(XHCIController&, const Info& info);
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; 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; void send_data_buffer(uint8_t endpoint_id, paddr_t buffer, size_t buffer_size) override;
@ -43,22 +56,22 @@ namespace Kernel
BAN::ErrorOr<void> initialize_control_endpoint() override; BAN::ErrorOr<void> initialize_control_endpoint() override;
private: private:
XHCIDevice(XHCIController& controller, uint32_t port_id, uint32_t slot_id); XHCIDevice(XHCIController& controller, const Info& info);
~XHCIDevice(); ~XHCIDevice();
BAN::ErrorOr<void> update_actual_max_packet_size(); BAN::ErrorOr<void> update_actual_max_packet_size();
bool is_multi_tt() const;
void on_interrupt_or_bulk_endpoint_event(XHCI::TRB); void on_interrupt_or_bulk_endpoint_event(XHCI::TRB);
void advance_endpoint_enqueue(Endpoint&, bool chain); void advance_endpoint_enqueue(Endpoint&, bool chain);
static uint64_t calculate_port_bits_per_second(XHCIController&, uint32_t port_id);
private: private:
static constexpr uint32_t m_transfer_ring_trb_count = PAGE_SIZE / sizeof(XHCI::TRB); static constexpr uint32_t m_transfer_ring_trb_count = PAGE_SIZE / sizeof(XHCI::TRB);
XHCIController& m_controller; XHCIController& m_controller;
const uint32_t m_port_id; Info m_info;
const uint32_t m_slot_id;
Mutex m_mutex; Mutex m_mutex;

View File

@ -16,6 +16,7 @@ namespace Kernel
Partition::Partition(BAN::RefPtr<BlockDevice> device, const BAN::GUID& type, const BAN::GUID& guid, uint64_t first_block, uint64_t last_block, uint64_t attr, const char* label, uint32_t index, BAN::StringView name_prefix) Partition::Partition(BAN::RefPtr<BlockDevice> device, const BAN::GUID& type, const BAN::GUID& guid, uint64_t first_block, uint64_t last_block, uint64_t attr, const char* label, uint32_t index, BAN::StringView name_prefix)
: BlockDevice(0660, 0, 0) : BlockDevice(0660, 0, 0)
, m_device(device) , m_device(device)
, m_block_size(device->blksize())
, m_type(type) , m_type(type)
, m_guid(guid) , m_guid(guid)
, m_guid_string(MUST(guid.to_string())) , m_guid_string(MUST(guid.to_string()))
@ -30,30 +31,42 @@ namespace Kernel
BAN::ErrorOr<void> Partition::read_blocks(uint64_t first_block, size_t block_count, BAN::ByteSpan buffer) BAN::ErrorOr<void> Partition::read_blocks(uint64_t first_block, size_t block_count, BAN::ByteSpan buffer)
{ {
ASSERT(buffer.size() >= block_count * m_device->blksize()); auto device = m_device.lock();
if (!device)
return BAN::Error::from_errno(ENODEV);
ASSERT(buffer.size() >= block_count * device->blksize());
const uint32_t blocks_in_partition = m_last_block - m_first_block + 1; const uint32_t blocks_in_partition = m_last_block - m_first_block + 1;
if (first_block + block_count > blocks_in_partition) if (first_block + block_count > blocks_in_partition)
return BAN::Error::from_error_code(ErrorCode::Storage_Boundaries); return BAN::Error::from_error_code(ErrorCode::Storage_Boundaries);
TRY(m_device->read_blocks(m_first_block + first_block, block_count, buffer)); TRY(device->read_blocks(m_first_block + first_block, block_count, buffer));
return {}; return {};
} }
BAN::ErrorOr<void> Partition::write_blocks(uint64_t first_block, size_t block_count, BAN::ConstByteSpan buffer) BAN::ErrorOr<void> Partition::write_blocks(uint64_t first_block, size_t block_count, BAN::ConstByteSpan buffer)
{ {
ASSERT(buffer.size() >= block_count * m_device->blksize()); auto device = m_device.lock();
if (!device)
return BAN::Error::from_errno(ENODEV);
ASSERT(buffer.size() >= block_count * device->blksize());
const uint32_t blocks_in_partition = m_last_block - m_first_block + 1; const uint32_t blocks_in_partition = m_last_block - m_first_block + 1;
if (first_block + block_count > blocks_in_partition) if (first_block + block_count > blocks_in_partition)
return BAN::Error::from_error_code(ErrorCode::Storage_Boundaries); return BAN::Error::from_error_code(ErrorCode::Storage_Boundaries);
TRY(m_device->write_blocks(m_first_block + first_block, block_count, buffer)); TRY(device->write_blocks(m_first_block + first_block, block_count, buffer));
return {}; return {};
} }
BAN::ErrorOr<void> Partition::sync_blocks(uint64_t block, size_t block_count) BAN::ErrorOr<void> Partition::sync_blocks(uint64_t block, size_t block_count)
{ {
auto device = m_device.lock();
if (!device)
return BAN::Error::from_errno(ENODEV);
const uint32_t blocks_in_partition = m_last_block - m_first_block + 1; const uint32_t blocks_in_partition = m_last_block - m_first_block + 1;
if (block + block_count > blocks_in_partition) if (block + block_count > blocks_in_partition)
return BAN::Error::from_error_code(ErrorCode::Storage_Boundaries); return BAN::Error::from_error_code(ErrorCode::Storage_Boundaries);
TRY(m_device->sync_blocks(m_first_block + block, block_count)); TRY(device->sync_blocks(m_first_block + block, block_count));
return {}; return {};
} }
@ -61,12 +74,16 @@ namespace Kernel
{ {
ASSERT(offset >= 0); ASSERT(offset >= 0);
if (offset % m_device->blksize() || buffer.size() % m_device->blksize()) auto device = m_device.lock();
if (!device)
return BAN::Error::from_errno(ENODEV);
if (offset % device->blksize() || buffer.size() % device->blksize())
return BAN::Error::from_errno(ENOTSUP); return BAN::Error::from_errno(ENOTSUP);
const uint32_t blocks_in_partition = m_last_block - m_first_block + 1; const uint32_t blocks_in_partition = m_last_block - m_first_block + 1;
uint32_t first_block = offset / m_device->blksize(); uint32_t first_block = offset / device->blksize();
uint32_t block_count = buffer.size() / m_device->blksize(); uint32_t block_count = buffer.size() / device->blksize();
if (first_block >= blocks_in_partition) if (first_block >= blocks_in_partition)
return 0; return 0;
@ -74,7 +91,7 @@ namespace Kernel
block_count = blocks_in_partition - first_block; block_count = blocks_in_partition - first_block;
TRY(read_blocks(first_block, block_count, buffer)); TRY(read_blocks(first_block, block_count, buffer));
return block_count * m_device->blksize(); return block_count * device->blksize();
} }
} }

View File

@ -204,6 +204,9 @@ namespace Kernel
StorageDevice::~StorageDevice() StorageDevice::~StorageDevice()
{ {
for (auto& partition : m_partitions)
if (partition)
DevFileSystem::get().remove_device(partition);
} }
void StorageDevice::add_disk_cache() void StorageDevice::add_disk_cache()

View File

@ -107,41 +107,38 @@ namespace Kernel
while (*ptr) while (*ptr)
putchar(*ptr++); putchar(*ptr++);
if (getchar() != '\033') if (auto ch = getchar(); !ch.has_value() || ch.value() != '\033')
return false; return false;
if (getchar() != '[') if (auto ch = getchar(); !ch.has_value() || ch.value() != '[')
return false; return false;
auto read_number = auto read_number =
[&](char end) [&](uint8_t end) -> BAN::Optional<uint32_t>
{ {
uint32_t number = 0; uint32_t number = 0;
while (true) while (true)
{ {
char c = getchar(); const auto ch = getchar();
if (c == end) if (!ch.has_value())
break; return {};
if (!isdigit(c)) if (ch.value() == end)
return UINT32_MAX; return number;
number = (number * 10) + (c - '0'); if (!isdigit(ch.value()))
return {};
number = (number * 10) + (ch.value() - '0');
} }
return number;
}; };
m_height = read_number(';'); const auto height = read_number(';');
if (m_height == UINT32_MAX) if (!height.has_value())
{
m_port = 0;
return false; return false;
}
m_width = read_number('R'); const auto width = read_number('R');
if (m_width == UINT32_MAX) if (!width.has_value())
{
m_port = 0;
return false; return false;
}
m_height = height.value();
m_width = width.value();
return true; return true;
} }
@ -150,25 +147,26 @@ namespace Kernel
return s_has_devices; return s_has_devices;
} }
void Serial::putchar(char c) void Serial::putchar(uint8_t ch)
{ {
while (!(IO::inb(m_port + 5) & 0x20)) while (!(IO::inb(m_port + 5) & 0x20))
continue; continue;
IO::outb(m_port, c); IO::outb(m_port, ch);
} }
char Serial::getchar() BAN::Optional<uint8_t> Serial::getchar()
{ {
while (!(IO::inb(m_port + 5) & 0x01)) for (size_t i = 0; i < 10'000'000; i++)
continue; if (IO::inb(m_port + 5) & 0x01)
return IO::inb(m_port); return IO::inb(m_port);
return {};
} }
void Serial::putchar_any(char c) void Serial::putchar_any(uint8_t ch)
{ {
for (auto& device : s_serial_drivers) for (auto& device : s_serial_drivers)
if (device.is_valid()) if (device.is_valid())
device.putchar(c); return device.putchar(ch);
} }
SerialTTY::SerialTTY(Serial serial) SerialTTY::SerialTTY(Serial serial)

View File

@ -110,12 +110,11 @@ namespace Kernel
m_state = State::Normal; m_state = State::Normal;
} }
void VirtualTTY::handle_ansi_csi_color() void VirtualTTY::handle_ansi_csi_color(uint8_t ch)
{ {
ASSERT(m_write_lock.current_processor_has_lock()); ASSERT(m_write_lock.current_processor_has_lock());
switch (m_ansi_state.nums[0]) switch (ch)
{ {
case -1:
case 0: case 0:
m_foreground = TerminalColor::BRIGHT_WHITE; m_foreground = TerminalColor::BRIGHT_WHITE;
m_background = TerminalColor::BLACK; m_background = TerminalColor::BLACK;
@ -165,18 +164,25 @@ namespace Kernel
void VirtualTTY::handle_ansi_csi(uint8_t ch) void VirtualTTY::handle_ansi_csi(uint8_t ch)
{ {
constexpr size_t max_ansi_args = sizeof(m_ansi_state.nums) / sizeof(*m_ansi_state.nums);
ASSERT(m_write_lock.current_processor_has_lock()); ASSERT(m_write_lock.current_processor_has_lock());
switch (ch) switch (ch)
{ {
case '0': case '1': case '2': case '3': case '4': case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': case '5': case '6': case '7': case '8': case '9':
{ {
int32_t& val = m_ansi_state.nums[m_ansi_state.index]; if ((size_t)m_ansi_state.index >= max_ansi_args)
val = (val == -1) ? (ch - '0') : (val * 10 + ch - '0'); dwarnln("Only {} arguments supported with ANSI codes", max_ansi_args);
else
{
int32_t& val = m_ansi_state.nums[m_ansi_state.index];
val = (val == -1) ? (ch - '0') : (val * 10 + ch - '0');
}
return; return;
} }
case ';': case ';':
m_ansi_state.index++; m_ansi_state.index = BAN::Math::min<size_t>(m_ansi_state.index + 1, max_ansi_args);
return; return;
case 'A': // Cursor Up case 'A': // Cursor Up
if (m_ansi_state.nums[0] == -1) if (m_ansi_state.nums[0] == -1)
@ -308,7 +314,9 @@ namespace Kernel
dprintln_if(DEBUG_VTTY, "Unsupported ANSI CSI character f"); dprintln_if(DEBUG_VTTY, "Unsupported ANSI CSI character f");
return; return;
case 'm': case 'm':
handle_ansi_csi_color(); handle_ansi_csi_color(BAN::Math::max(m_ansi_state.nums[0], 0));
for (int i = 1; i < m_ansi_state.index; i++)
handle_ansi_csi_color(BAN::Math::max(m_ansi_state.nums[i], 0));
return reset_ansi(); return reset_ansi();
case 's': case 's':
m_saved_row = m_row; m_saved_row = m_row;

View File

@ -0,0 +1,40 @@
#include <kernel/USB/Controller.h>
namespace Kernel
{
USBController::USBController()
{
for (auto& count : m_hubs_to_init_per_tier)
count = 0;
m_hubs_to_init_per_tier[0] = 1;
}
uint8_t USBController::current_hub_init_tier() const
{
SpinLockGuard _(m_hub_init_lock);
return m_current_hub_init_tier;
}
void USBController::register_hub_to_init(uint8_t tier)
{
ASSERT(tier >= 1);
ASSERT(tier <= m_hubs_to_init_per_tier.size());
SpinLockGuard _(m_hub_init_lock);
m_hubs_to_init_per_tier[tier]++;
if (tier < m_current_hub_init_tier)
m_current_hub_init_tier = tier;
}
void USBController::mark_hub_init_done(uint8_t tier)
{
ASSERT(tier < m_hubs_to_init_per_tier.size());
SpinLockGuard _(m_hub_init_lock);
m_hubs_to_init_per_tier[tier]--;
if (tier == m_current_hub_init_tier && m_hubs_to_init_per_tier[tier] == 0)
m_current_hub_init_tier++;
}
}

View File

@ -1,6 +1,7 @@
#include <kernel/Memory/DMARegion.h> #include <kernel/Memory/DMARegion.h>
#include <kernel/USB/Device.h> #include <kernel/USB/Device.h>
#include <kernel/USB/HID/HIDDriver.h> #include <kernel/USB/HID/HIDDriver.h>
#include <kernel/USB/Hub/HubDriver.h>
#include <kernel/USB/MassStorage/MassStorageDriver.h> #include <kernel/USB/MassStorage/MassStorageDriver.h>
#define USB_DUMP_DESCRIPTORS 0 #define USB_DUMP_DESCRIPTORS 0
@ -107,8 +108,26 @@ namespace Kernel
dprintln_if(DEBUG_USB, "Found CommunicationAndCDCControl device"); dprintln_if(DEBUG_USB, "Found CommunicationAndCDCControl device");
return BAN::Error::from_errno(ENOTSUP); return BAN::Error::from_errno(ENOTSUP);
case USB::DeviceBaseClass::Hub: case USB::DeviceBaseClass::Hub:
dprintln_if(DEBUG_USB, "Found Hub device"); {
return BAN::Error::from_errno(ENOTSUP); if (auto ret = BAN::UniqPtr<USBHubDriver>::create(*this, m_descriptor); !ret.is_error())
TRY(m_class_drivers.push_back(ret.release_value()));
else
{
dwarnln("Failed to create USB Hub: {}", ret.error());
return ret.release_error();
}
if (auto ret = m_class_drivers[0]->initialize(); ret.is_error())
{
dwarnln("Failed to initialize USB Hub: {}", ret.error());
m_class_drivers.clear();
return ret.release_error();
}
dprintln_if(DEBUG_USB, "Successfully initialized USB hub");
return {};
}
case USB::DeviceBaseClass::BillboardDeviceClass: case USB::DeviceBaseClass::BillboardDeviceClass:
dprintln_if(DEBUG_USB, "Found BillboardDeviceClass device"); dprintln_if(DEBUG_USB, "Found BillboardDeviceClass device");
return BAN::Error::from_errno(ENOTSUP); return BAN::Error::from_errno(ENOTSUP);
@ -146,6 +165,10 @@ namespace Kernel
for (const auto& interface : configuration.interfaces) for (const auto& interface : configuration.interfaces)
{ {
// FIXME: support alternate settings
if (interface.descriptor.bAlternateSetting != 0)
continue;
switch (static_cast<USB::InterfaceBaseClass>(interface.descriptor.bInterfaceClass)) switch (static_cast<USB::InterfaceBaseClass>(interface.descriptor.bInterfaceClass))
{ {
case USB::InterfaceBaseClass::Audio: case USB::InterfaceBaseClass::Audio:
@ -340,15 +363,4 @@ namespace Kernel
driver->handle_input_data(byte_count, endpoint_id); driver->handle_input_data(byte_count, endpoint_id);
} }
USB::SpeedClass USBDevice::determine_speed_class(uint64_t bits_per_second)
{
if (bits_per_second <= 1'500'000)
return USB::SpeedClass::LowSpeed;
if (bits_per_second <= 12'000'000)
return USB::SpeedClass::FullSpeed;
else if (bits_per_second <= 480'000'000)
return USB::SpeedClass::HighSpeed;
return USB::SpeedClass::SuperSpeed;
}
} }

View File

@ -194,7 +194,7 @@ namespace Kernel
if ((desc.bmAttributes & 0x03) != 0x03) if ((desc.bmAttributes & 0x03) != 0x03)
continue; continue;
TRY(m_device.initialize_endpoint(desc)); TRY(m_device.configure_endpoint(desc));
m_data_buffer = TRY(DMARegion::create(desc.wMaxPacketSize & 0x07FF)); m_data_buffer = TRY(DMARegion::create(desc.wMaxPacketSize & 0x07FF));
m_data_endpoint_id = (desc.bEndpointAddress & 0x0F) * 2 + !!(desc.bEndpointAddress & 0x80); m_data_endpoint_id = (desc.bEndpointAddress & 0x0F) * 2 + !!(desc.bEndpointAddress & 0x80);

View File

@ -0,0 +1,451 @@
#include <BAN/ScopeGuard.h>
#include <kernel/USB/Hub/Definitions.h>
#include <kernel/USB/Hub/HubDriver.h>
#include <kernel/Timer/Timer.h>
namespace Kernel
{
USBHubDriver::USBHubDriver(USBDevice& device, const USBDevice::DeviceDescriptor& desciptor)
: m_device(device)
, m_descriptor(desciptor)
{}
USBHubDriver::~USBHubDriver()
{
m_running = false;
m_changed_port_blocker.unblock();
while (m_port_updater)
continue;
for (const auto info : m_ports)
{
if (info.slot == 0)
continue;
m_device.deinitialize_device_slot(info.slot);
}
}
BAN::ErrorOr<void> USBHubDriver::initialize()
{
#if DEBUG_USB_HUB
switch (m_device.speed_class())
{
case USB::SpeedClass::LowSpeed:
dprintln("configuring low speed hub");
break;
case USB::SpeedClass::FullSpeed:
dprintln("configuring full speed hub");
break;
case USB::SpeedClass::HighSpeed:
dprintln("configuring high speed hub");
break;
case USB::SpeedClass::SuperSpeed:
dprintln("configuring super speed hub");
break;
}
#endif
m_data_region = TRY(DMARegion::create(PAGE_SIZE));
if (m_descriptor.configurations.empty())
{
dwarnln("USB hub does not have any configurations");
return BAN::Error::from_errno(EFAULT);
}
const auto& configuration = m_descriptor.configurations[0];
{
dprintln_if(DEBUG_USB_HUB, "setting configuration");
USBDeviceRequest request;
request.bmRequestType = USB::RequestType::HostToDevice | USB::RequestType::Standard | USB::RequestType::Device;
request.bRequest = USB::SET_CONFIGURATION;
request.wValue = configuration.desciptor.bConfigurationValue;
request.wIndex = 0;
request.wLength = 0;
TRY(m_device.send_request(request, 0));
dprintln_if(DEBUG_USB_HUB, " -> done");
}
if (configuration.interfaces.empty())
{
dwarnln("USB hub does not have any interfaces");
return BAN::Error::from_errno(EFAULT);
}
const auto* interface = &configuration.interfaces[0];
// High speed hubs may have alternate multi tt interface
if (m_device.speed_class() == USB::SpeedClass::HighSpeed)
{
for (size_t i = 0; i < configuration.interfaces.size(); i++)
{
if (configuration.interfaces[i].descriptor.bInterfaceProtocol != 2)
continue;
interface = &configuration.interfaces[i];
break;
}
if (interface->descriptor.bAlternateSetting != 0)
{
dprintln_if(DEBUG_USB_HUB, "enabling multi tt interface");
USBDeviceRequest request;
request.bmRequestType = USB::RequestType::HostToDevice | USB::RequestType::Standard | USB::RequestType::Interface;
request.bRequest = USB::SET_INTERFACE;
request.wValue = interface->descriptor.bAlternateSetting;
request.wIndex = interface->descriptor.iInterface;
request.wLength = 0;
TRY(m_device.send_request(request, 0));
dprintln_if(DEBUG_USB_HUB, " -> done");
}
m_is_multi_tt = (interface->descriptor.bInterfaceProtocol == 2);
}
if (interface->endpoints.size() != 1)
{
dwarnln("USB hub has {} endpoints", interface->endpoints.size());
return BAN::Error::from_errno(EFAULT);
}
const auto& endpoint = interface->endpoints[0];
m_is_usb3 = (m_device.speed_class() == USB::SpeedClass::SuperSpeed);
m_is_usb2 = !m_is_usb3;
ASSERT(m_is_usb2 ^ m_is_usb3);
// Set multi tt to false until we know tt think time
dprintln_if(DEBUG_USB_HUB, "configuring endpoint with 4 ports");
TRY(m_device.configure_endpoint(endpoint.descriptor, {
.number_of_ports = m_port_count,
.multi_tt = false,
.tt_think_time = 0
}));
dprintln_if(DEBUG_USB_HUB, " -> done");
// USB 3 devices use route_string and hub depth for routing packets
if (m_is_usb3)
{
dprintln_if(DEBUG_USB_HUB, "setting hub depth");
USBDeviceRequest request;
request.bmRequestType = USB::RequestType::HostToDevice | USB::RequestType::Class | USB::RequestType::Device;
request.bRequest = 12; // SET_HUB_DEPTH
request.wValue = m_device.depth();
request.wIndex = 0;
request.wLength = 0;
TRY(m_device.send_request(request, 0));
dprintln_if(DEBUG_USB_HUB, " -> done");
}
uint8_t tt_think_time = 0;
// Hub descriptor has to be requested after device is configured
{
dprintln_if(DEBUG_USB_HUB, "getting hub descriptor");
USBDeviceRequest request;
request.bmRequestType = USB::RequestType::DeviceToHost | USB::RequestType::Class | USB::RequestType::Device;
request.bRequest = USB::Request::GET_DESCRIPTOR;
request.wValue = m_is_usb3 ? 0x2A00 : 0x2900;
request.wIndex = 0;
request.wLength = 8;
if (TRY(m_device.send_request(request, m_data_region->paddr())) < 8)
{
dwarnln("USB hub did not respond with full hub descriptor");
return BAN::Error::from_errno(EFAULT);
}
dprintln_if(DEBUG_USB_HUB, " -> done");
const auto& hub_descriptor = *reinterpret_cast<USBHub::HubDescriptor*>(m_data_region->vaddr());
m_port_count = hub_descriptor.bNbrPorts;
if (m_device.speed_class() == USB::SpeedClass::HighSpeed)
tt_think_time = (hub_descriptor.wHubCharacteristics >> 5) & 0x03;
}
if (m_port_count > 31)
{
dwarnln("USB hubs only support up to 31 ports");
m_port_count = 31;
}
TRY(m_ports.resize(m_port_count));
dprintln_if(DEBUG_USB_HUB, "re-configuring endpoint with {} ports", m_port_count);
TRY(m_device.configure_endpoint(endpoint.descriptor, {
.number_of_ports = m_port_count,
.multi_tt = m_is_multi_tt,
.tt_think_time = tt_think_time
}));
dprintln_if(DEBUG_USB_HUB, " -> done");
m_endpoint_id = (endpoint.descriptor.bEndpointAddress & 0x0F) * 2 + !!(endpoint.descriptor.bEndpointAddress & 0x80);
m_device.send_data_buffer(m_endpoint_id, m_data_region->paddr() + sizeof(USBHub::PortStatus), m_port_count / 8 + 1);
// Reset all ports in powered off state
for (size_t port_id = 1; port_id <= m_port_count; port_id++)
{
USBDeviceRequest request;
request.bmRequestType = USB::RequestType::DeviceToHost | USB::RequestType::Class | USB::RequestType::Other;
request.bRequest = USB::Request::GET_STATUS;
request.wValue = 0;
request.wIndex = port_id;
request.wLength = sizeof(USBHub::PortStatus);
auto result = m_device.send_request(request, m_data_region->paddr());
if (result.is_error() || result.value() != sizeof(USBHub::PortStatus))
{
dwarnln("Failed to get port {} status");
continue;
}
const auto& port_status = *reinterpret_cast<volatile USBHub::PortStatus*>(m_data_region->vaddr());
const bool is_powered =
(m_is_usb3 && port_status.wPortStatus.usb3.power) ||
(m_is_usb2 && port_status.wPortStatus.usb2.power);
if (!is_powered)
if (auto ret = set_port_feature(port_id, USBHub::PORT_POWER); ret.is_error())
dwarnln("Failed to power on USB hub port {}: {}", port_id, ret.error());
dprintln_if(DEBUG_USB_HUB, "port {}, status {4H}, changed {4H}",
port_id,
*(uint16_t*)(m_data_region->vaddr() + 0),
*(uint16_t*)(m_data_region->vaddr() + 2)
);
m_changed_ports |= 1u << port_id;
}
m_port_updater = Process::create_kernel([](void* data) { reinterpret_cast<USBHubDriver*>(data)->port_updater_task(); }, this);
if (m_port_updater == nullptr)
return BAN::Error::from_errno(ENOMEM);
return {};
}
BAN::ErrorOr<void> USBHubDriver::clear_port_feature(uint8_t port, uint8_t feature)
{
USBDeviceRequest request;
request.bmRequestType = USB::RequestType::HostToDevice | USB::RequestType::Class | USB::RequestType::Other;
request.bRequest = USB::Request::CLEAR_FEATURE;
request.wValue = feature;
request.wIndex = port;
request.wLength = 0;
TRY(m_device.send_request(request, 0));
return {};
}
BAN::ErrorOr<void> USBHubDriver::set_port_feature(uint8_t port, uint8_t feature)
{
USBDeviceRequest request;
request.bmRequestType = USB::RequestType::HostToDevice | USB::RequestType::Class | USB::RequestType::Other;
request.bRequest = USB::Request::SET_FEATURE;
request.wValue = feature;
request.wIndex = port;
request.wLength = 0;
TRY(m_device.send_request(request, 0));
return {};
}
void USBHubDriver::port_updater_task()
{
m_device.register_hub_to_init();
while (m_running && !m_device.can_start_hub_init())
Processor::yield();
uint64_t last_port_update_ms = SystemTimer::get().ms_since_boot();
while (m_running)
{
uint8_t changed_port = 0xFF;
{
const auto temp = m_changed_ports.exchange(0);
if (temp == 0)
{
// If there has been no changed ports in 100ms, this hub has initialized its devices
if (!m_is_init_done && SystemTimer::get().ms_since_boot() - last_port_update_ms >= 100)
{
m_device.mark_hub_init_done();
m_is_init_done = true;
}
m_changed_port_blocker.block_with_timeout_ms(100);
continue;
}
last_port_update_ms = SystemTimer::get().ms_since_boot();
for (size_t i = 0; i <= m_ports.size(); i++)
{
if (!(temp & (1u << i)))
continue;
changed_port = i;
break;
}
m_changed_ports |= temp & ~(1u << changed_port);
}
if (changed_port == 0)
{
dprintln_if(DEBUG_USB_HUB, "TODO: USB Hub changed");
continue;
}
{
USBDeviceRequest request;
request.bmRequestType = USB::RequestType::DeviceToHost | USB::RequestType::Class | USB::RequestType::Other;
request.bRequest = USB::Request::GET_STATUS;
request.wValue = 0;
request.wIndex = changed_port;
request.wLength = sizeof(USBHub::PortStatus);
auto result = m_device.send_request(request, m_data_region->paddr());
if (result.is_error() || result.value() != sizeof(USBHub::PortStatus))
{
dwarnln("Failed to get port {} status", changed_port);
continue;
}
}
const USBHub::PortStatus port_status {
.wPortStatus = { .raw = reinterpret_cast<volatile USBHub::PortStatus*>(m_data_region->vaddr())->wPortStatus.raw },
.wPortChanged = { .raw = reinterpret_cast<volatile USBHub::PortStatus*>(m_data_region->vaddr())->wPortChanged.raw },
};
if (port_status.wPortChanged.connection)
{
(void)clear_port_feature(changed_port, USBHub::C_PORT_CONNECTION);
if (port_status.wPortStatus.connection)
{
// USB 2 devices have to be reset to enter enabled state
if (auto ret = set_port_feature(changed_port, USBHub::PORT_RESET); ret.is_error())
dwarnln("Failed to reset USB hub port {}: {}", changed_port, ret.error());
}
else
{
// Cleanup port on disconnection
auto& port_info = m_ports[changed_port - 1];
if (port_info.slot != 0)
m_device.deinitialize_device_slot(port_info.slot);
port_info = {};
}
}
if (port_status.wPortChanged.reset)
{
// If this is USB3 device and the port is not in enabled state don't
// clear reset changed so hub will trigger another port changed interrupt
if (!port_status.wPortStatus.connection || !m_is_usb3 || port_status.wPortStatus.enable)
(void)clear_port_feature(changed_port, USBHub::C_PORT_RESET);
}
if (port_status.wPortChanged.over_current)
{
(void)clear_port_feature(changed_port, USBHub::C_PORT_OVER_CURRENT);
dwarnln_if(DEBUG_USB_HUB, "TODO: USB hub port over current change");
}
if (m_is_usb2)
{
if (port_status.wPortChanged.usb2.enable)
(void)clear_port_feature(changed_port, USBHub::C_PORT_ENABLE);
if (port_status.wPortChanged.usb2.suspend)
{
(void)clear_port_feature(changed_port, USBHub::C_PORT_SUSPEND);
dwarnln_if(DEBUG_USB_HUB, "TODO: USB hub port suspend change");
}
}
else if (m_is_usb3)
{
if (port_status.wPortChanged.usb3.link_state)
(void)clear_port_feature(changed_port, USBHub::C_PORT_LINK_STATE);
if (port_status.wPortChanged.usb3.bh_reset)
{
(void)clear_port_feature(changed_port, USBHub::C_BH_PORT_RESET);
dwarnln_if(DEBUG_USB_HUB, "TODO: USB hub bh port reset change");
}
if (port_status.wPortChanged.usb3.config_error)
{
(void)clear_port_feature(changed_port, USBHub::C_PORT_CONFIG_ERROR);
dwarnln_if(DEBUG_USB_HUB, "TODO: USB hub port config error chage");
}
}
else
{
ASSERT_NOT_REACHED();
}
// Initialize new devices that have not failed initialization
if (port_status.wPortStatus.enable && !m_ports[changed_port - 1].slot && !m_ports[changed_port - 1].failed)
{
USB::SpeedClass speed_class;
if (m_is_usb3)
speed_class = USB::SpeedClass::SuperSpeed;
else if (port_status.wPortStatus.usb2.low_speed)
speed_class = USB::SpeedClass::LowSpeed;
else if (port_status.wPortStatus.usb2.high_speed)
speed_class = USB::SpeedClass::HighSpeed;
else
speed_class = USB::SpeedClass::FullSpeed;
#if DEBUG_USB_HUB
const char* speed_str = "<invalid>";
switch (speed_class)
{
case USB::SpeedClass::LowSpeed: speed_str = "low"; break;
case USB::SpeedClass::FullSpeed: speed_str = "full"; break;
case USB::SpeedClass::HighSpeed: speed_str = "high"; break;
case USB::SpeedClass::SuperSpeed: speed_str = "super"; break;
}
dprintln("Initializing {} speed device on hub port {}", speed_str, changed_port);
#endif
auto result = m_device.initialize_device_on_hub_port(changed_port, speed_class);
if (!result.is_error())
m_ports[changed_port - 1].slot = result.value();
else
{
m_ports[changed_port - 1].failed = true;
dwarnln("Failed to initialize USB hub port {}: {}", changed_port, result.error());
}
}
}
m_port_updater = nullptr;
}
void USBHubDriver::handle_stall(uint8_t endpoint_id)
{
(void)endpoint_id;
dwarnln("TODO: USB hub handle stall");
}
void USBHubDriver::handle_input_data(size_t byte_count, uint8_t endpoint_id)
{
if (endpoint_id != m_endpoint_id)
return;
BAN::ScopeGuard query_changes([&] {
m_device.send_data_buffer(m_endpoint_id, m_data_region->paddr() + sizeof(USBHub::PortStatus), m_port_count / 8 + 1);
});
if (m_ports.size() / 8 + 1 < byte_count)
byte_count = m_ports.size() / 8 + 1;
uint32_t new_ports = 0;
const auto* bitmap = reinterpret_cast<const uint8_t*>(m_data_region->vaddr() + sizeof(USBHub::PortStatus));
for (size_t i = 0; i < byte_count; i++)
new_ports |= static_cast<uint32_t>(bitmap[i]) << (i * 8);
if (new_ports)
{
m_changed_ports |= new_ports;
m_changed_port_blocker.unblock();
}
}
}

View File

@ -20,7 +20,11 @@ namespace Kernel
{ } { }
USBMassStorageDriver::~USBMassStorageDriver() USBMassStorageDriver::~USBMassStorageDriver()
{ } {
for (auto& device : m_storage_devices)
if (device)
DevFileSystem::get().remove_device(device);
}
BAN::ErrorOr<void> USBMassStorageDriver::initialize() BAN::ErrorOr<void> USBMassStorageDriver::initialize()
{ {
@ -74,8 +78,8 @@ namespace Kernel
return BAN::Error::from_errno(EFAULT); return BAN::Error::from_errno(EFAULT);
} }
TRY(m_device.initialize_endpoint(m_interface.endpoints[bulk_in_index].descriptor)); TRY(m_device.configure_endpoint(m_interface.endpoints[bulk_in_index].descriptor));
TRY(m_device.initialize_endpoint(m_interface.endpoints[bulk_out_index].descriptor)); TRY(m_device.configure_endpoint(m_interface.endpoints[bulk_out_index].descriptor));
{ {
const auto& desc = m_interface.endpoints[bulk_in_index].descriptor; const auto& desc = m_interface.endpoints[bulk_in_index].descriptor;

View File

@ -16,8 +16,9 @@ namespace Kernel
XHCIController::~XHCIController() XHCIController::~XHCIController()
{ {
if (m_port_updater) m_running = false;
m_port_updater->exit(0, SIGKILL); while (m_port_updater)
Processor::yield();
for (auto paddr : m_scratchpad_buffers) for (auto paddr : m_scratchpad_buffers)
if (paddr) if (paddr)
@ -148,6 +149,8 @@ namespace Kernel
ASSERT(m_ports.size() == max_ports); ASSERT(m_ports.size() == max_ports);
bool overrides_speed_ids = false;
{ {
uint16_t ext_offset = capabilities.hccparams1.xhci_extended_capabilities_pointer; uint16_t ext_offset = capabilities.hccparams1.xhci_extended_capabilities_pointer;
if (ext_offset == 0) if (ext_offset == 0)
@ -159,11 +162,11 @@ namespace Kernel
vaddr_t ext_addr = m_configuration_bar->vaddr() + ext_offset * 4; vaddr_t ext_addr = m_configuration_bar->vaddr() + ext_offset * 4;
while (true) while (true)
{ {
auto& ext_cap = *reinterpret_cast<volatile XHCI::ExtendedCap*>(ext_addr); const auto& ext_cap = *reinterpret_cast<volatile XHCI::ExtendedCap*>(ext_addr);
if (ext_cap.capability_id == XHCI::ExtendedCapabilityID::SupportedProtocol) if (ext_cap.capability_id == XHCI::ExtendedCapabilityID::SupportedProtocol)
{ {
auto& protocol = reinterpret_cast<volatile XHCI::SupportedPrococolCap&>(ext_cap); const auto& protocol = reinterpret_cast<const volatile XHCI::SupportedPrococolCap&>(ext_cap);
const uint32_t target_name_string { const uint32_t target_name_string {
('U' << 0) | ('U' << 0) |
@ -183,21 +186,20 @@ namespace Kernel
return BAN::Error::from_errno(EFAULT); return BAN::Error::from_errno(EFAULT);
} }
if (protocol.protocol_slot_type != 0)
{
dwarnln("Invalid slot type specified in SupportedProtocols");
return BAN::Error::from_errno(EFAULT);
}
if (protocol.protocol_speed_id_count != 0)
overrides_speed_ids = true;
for (size_t i = 0; i < protocol.compatible_port_count; i++) for (size_t i = 0; i < protocol.compatible_port_count; i++)
{ {
auto& port = m_ports[protocol.compatible_port_offset + i - 1]; auto& port = m_ports[protocol.compatible_port_offset + i - 1];
port.revision_major = protocol.major_revision; port.revision_major = protocol.major_revision;
port.revision_minor = protocol.minor_revision; port.revision_minor = protocol.minor_revision;
port.slot_type = protocol.protocol_slot_type;
for (size_t j = 0; j < protocol.protocol_speed_id_count; j++)
{
uint32_t speed_info = reinterpret_cast<const volatile uint32_t*>(ext_addr + sizeof(XHCI::SupportedPrococolCap))[j];
uint32_t port_speed = speed_info >> 16;
for (size_t exp = 0; exp < ((speed_info >> 4) & 0x03); exp++)
port_speed *= 1000;
port.speed_id_to_speed[speed_info & 0x0F] = port_speed;
}
} }
} }
@ -207,6 +209,9 @@ namespace Kernel
} }
} }
if (overrides_speed_ids)
dwarnln("xHCI overrides default speed ids, USB may not work");
// set max slots enabled // set max slots enabled
auto& operational = operational_regs(); auto& operational = operational_regs();
operational.config.max_device_slots_enabled = capabilities.hcsparams1.max_slots; operational.config.max_device_slots_enabled = capabilities.hcsparams1.max_slots;
@ -214,6 +219,30 @@ namespace Kernel
return {}; return {};
} }
uint8_t XHCIController::speed_class_to_id(USB::SpeedClass speed_class) const
{
switch (speed_class)
{
case USB::SpeedClass::LowSpeed: return 2;
case USB::SpeedClass::FullSpeed: return 1;
case USB::SpeedClass::HighSpeed: return 3;
case USB::SpeedClass::SuperSpeed: return 4;
}
ASSERT_NOT_REACHED();
}
USB::SpeedClass XHCIController::speed_id_to_class(uint8_t speed_id) const
{
switch (speed_id)
{
case 2: return USB::SpeedClass::LowSpeed;
case 1: return USB::SpeedClass::FullSpeed;
case 3: return USB::SpeedClass::HighSpeed;
case 4: return USB::SpeedClass::SuperSpeed;
}
ASSERT_NOT_REACHED();
}
BAN::ErrorOr<void> XHCIController::initialize_primary_interrupter() BAN::ErrorOr<void> XHCIController::initialize_primary_interrupter()
{ {
TRY(m_pci_device.reserve_interrupts(1)); TRY(m_pci_device.reserve_interrupts(1));
@ -278,17 +307,28 @@ namespace Kernel
// attached ports // attached ports
m_port_changed = true; m_port_changed = true;
while (true) uint64_t last_port_update = SystemTimer::get().ms_since_boot();
while (m_running)
{ {
{ {
bool expected { true }; bool expected { true };
while (!m_port_changed.compare_exchange(expected, false)) while (!m_port_changed.compare_exchange(expected, false))
{ {
// If there has been no port activity in 100 ms, mark root hub as initialized
if (!m_ports_initialized && SystemTimer::get().ms_since_boot() - last_port_update >= 100)
{
mark_hub_init_done(0);
m_ports_initialized = true;
}
m_port_thread_blocker.block_with_timeout_ms(100); m_port_thread_blocker.block_with_timeout_ms(100);
expected = true; expected = true;
} }
} }
last_port_update = SystemTimer::get().ms_since_boot();;
for (size_t i = 0; i < m_ports.size(); i++) for (size_t i = 0; i < m_ports.size(); i++)
{ {
auto& my_port = m_ports[i]; auto& my_port = m_ports[i];
@ -308,10 +348,9 @@ namespace Kernel
if (!(op_port.portsc & XHCI::PORTSC::CCS)) if (!(op_port.portsc & XHCI::PORTSC::CCS))
{ {
// if device detached, clear the port
if (my_port.slot_id != 0) if (my_port.slot_id != 0)
{ {
m_slots[my_port.slot_id - 1].clear(); deinitialize_slot(my_port.slot_id);
my_port.slot_id = 0; my_port.slot_id = 0;
} }
continue; continue;
@ -336,7 +375,12 @@ namespace Kernel
continue; continue;
} }
if (auto ret = initialize_slot(i); ret.is_error()) const uint8_t speed_id = (op_port.portsc >> XHCI::PORTSC::PORT_SPEED_SHIFT) & XHCI::PORTSC::PORT_SPEED_MASK;
if (auto temp = speed_class_to_id(speed_id_to_class(speed_id)); temp != speed_id)
dwarnln("FIXME: Using incorrect speed id, {} instead of {}", temp, speed_id);
if (auto ret = initialize_device(i + 1, 0, speed_id_to_class(speed_id), nullptr, 0); !ret.is_error())
my_port.slot_id = ret.value();
else
{ {
dwarnln("Could not initialize USB {H}.{H} device: {}", dwarnln("Could not initialize USB {H}.{H} device: {}",
my_port.revision_major, my_port.revision_major,
@ -346,26 +390,45 @@ namespace Kernel
} }
} }
} }
m_port_updater = nullptr;
} }
BAN::ErrorOr<void> XHCIController::initialize_slot(int port_index) BAN::ErrorOr<uint8_t> XHCIController::initialize_device(uint32_t route_string, uint8_t depth, USB::SpeedClass speed_class, XHCIDevice* parent_hub, uint8_t parent_port_id)
{ {
auto& my_port = m_ports[port_index];
XHCI::TRB enable_slot { .enable_slot_command {} }; XHCI::TRB enable_slot { .enable_slot_command {} };
enable_slot.enable_slot_command.trb_type = XHCI::TRBType::EnableSlotCommand; enable_slot.enable_slot_command.trb_type = XHCI::TRBType::EnableSlotCommand;
enable_slot.enable_slot_command.slot_type = my_port.slot_type; // 7.2.2.1.4: The Protocol Slot Type field of a USB3 or USB2 xHCI Supported Protocol Capability shall be set to 0.
enable_slot.enable_slot_command.slot_type = 0;
auto result = TRY(send_command(enable_slot)); auto result = TRY(send_command(enable_slot));
uint8_t slot_id = result.command_completion_event.slot_id; const uint8_t slot_id = result.command_completion_event.slot_id;
if (slot_id == 0 || slot_id > capability_regs().hcsparams1.max_slots) if (slot_id == 0 || slot_id > capability_regs().hcsparams1.max_slots)
{ {
dwarnln("EnableSlot gave an invalid slot {}", slot_id); dwarnln("EnableSlotCommand returned an invalid slot {}", slot_id);
return BAN::Error::from_errno(EFAULT); return BAN::Error::from_errno(EFAULT);
} }
dprintln_if(DEBUG_XHCI, "allocated slot {} for port {}", slot_id, port_index + 1);
m_slots[slot_id - 1] = TRY(XHCIDevice::create(*this, port_index + 1, slot_id)); #if DEBUG_XHCI
const auto& root_port = m_ports[(route_string & 0x0F) - 1];
dprintln("Initializing USB {H}.{H} device on slot {}",
root_port.revision_major,
root_port.revision_minor,
slot_id
);
#endif
const XHCIDevice::Info info {
.parent_hub = parent_hub,
.parent_port_id = parent_port_id,
.speed_class = speed_class,
.slot_id = slot_id,
.route_string = route_string,
.depth = depth
};
m_slots[slot_id - 1] = TRY(XHCIDevice::create(*this, info));
if (auto ret = m_slots[slot_id - 1]->initialize(); ret.is_error()) if (auto ret = m_slots[slot_id - 1]->initialize(); ret.is_error())
{ {
dwarnln("Could not initialize device on slot {}: {}", slot_id, ret.error()); dwarnln("Could not initialize device on slot {}: {}", slot_id, ret.error());
@ -373,11 +436,23 @@ namespace Kernel
return ret.release_error(); return ret.release_error();
} }
my_port.slot_id = slot_id; #if DEBUG_XHCI
dprintln("USB {H}.{H} device on slot {} initialized",
root_port.revision_major,
root_port.revision_minor,
slot_id
);
#endif
dprintln_if(DEBUG_XHCI, "device on slot {} initialized", slot_id); return slot_id;
}
return {}; void XHCIController::deinitialize_slot(uint8_t slot_id)
{
ASSERT(0 < slot_id && slot_id <= m_slots.size());
ASSERT(m_slots[slot_id - 1]);
m_slots[slot_id - 1]->destroy();
m_slots[slot_id - 1].clear();
} }
BAN::ErrorOr<void> XHCIController::reset_controller() BAN::ErrorOr<void> XHCIController::reset_controller()
@ -464,7 +539,8 @@ namespace Kernel
void XHCIController::handle_irq() void XHCIController::handle_irq()
{ {
auto& primary_interrupter = runtime_regs().irs[0]; auto& primary_interrupter = runtime_regs().irs[0];
primary_interrupter.iman = primary_interrupter.iman | XHCI::IMAN::InterruptPending | XHCI::IMAN::InterruptEnable; if (m_pci_device.interrupt_mechanism() != PCI::Device::InterruptMechanism::MSI && m_pci_device.interrupt_mechanism() != PCI::Device::InterruptMechanism::MSIX)
primary_interrupter.iman = primary_interrupter.iman | XHCI::IMAN::InterruptPending | XHCI::IMAN::InterruptEnable;
auto& operational = operational_regs(); auto& operational = operational_regs();
if (!(operational.usbsts & XHCI::USBSTS::EventInterrupt)) if (!(operational.usbsts & XHCI::USBSTS::EventInterrupt))

View File

@ -8,42 +8,33 @@
namespace Kernel namespace Kernel
{ {
BAN::ErrorOr<BAN::UniqPtr<XHCIDevice>> XHCIDevice::create(XHCIController& controller, uint32_t port_id, uint32_t slot_id) BAN::ErrorOr<BAN::UniqPtr<XHCIDevice>> XHCIDevice::create(XHCIController& controller, const Info& info)
{ {
return TRY(BAN::UniqPtr<XHCIDevice>::create(controller, port_id, slot_id)); return TRY(BAN::UniqPtr<XHCIDevice>::create(controller, info));
} }
uint64_t XHCIDevice::calculate_port_bits_per_second(XHCIController& controller, uint32_t port_id) XHCIDevice::XHCIDevice(XHCIController& controller, const Info& info)
{ : USBDevice(controller, info.speed_class, info.depth)
const uint32_t portsc = controller.operational_regs().ports[port_id - 1].portsc;
const uint32_t speed_id = (portsc >> XHCI::PORTSC::PORT_SPEED_SHIFT) & XHCI::PORTSC::PORT_SPEED_MASK;
return controller.port(port_id).speed_id_to_speed[speed_id];
}
XHCIDevice::XHCIDevice(XHCIController& controller, uint32_t port_id, uint32_t slot_id)
: USBDevice(determine_speed_class(calculate_port_bits_per_second(controller, port_id)))
, m_controller(controller) , m_controller(controller)
, m_port_id(port_id) , m_info(info)
, m_slot_id(slot_id)
{} {}
XHCIDevice::~XHCIDevice() XHCIDevice::~XHCIDevice()
{ {
XHCI::TRB disable_slot { .disable_slot_command {} }; XHCI::TRB disable_slot { .disable_slot_command {} };
disable_slot.disable_slot_command.trb_type = XHCI::TRBType::DisableSlotCommand; disable_slot.disable_slot_command.trb_type = XHCI::TRBType::DisableSlotCommand;
disable_slot.disable_slot_command.slot_id = m_slot_id; disable_slot.disable_slot_command.slot_id = m_info.slot_id;
if (auto ret = m_controller.send_command(disable_slot); ret.is_error()) if (auto ret = m_controller.send_command(disable_slot); ret.is_error())
dwarnln("Could not disable slot {}: {}", m_slot_id, ret.error()); dwarnln("Could not disable slot {}: {}", m_info.slot_id, ret.error());
else else
dprintln_if(DEBUG_XHCI, "Slot {} disabled", m_slot_id); dprintln_if(DEBUG_XHCI, "Slot {} disabled", m_info.slot_id);
} }
BAN::ErrorOr<void> XHCIDevice::initialize_control_endpoint() BAN::ErrorOr<void> XHCIDevice::initialize_control_endpoint()
{ {
const uint32_t context_size = m_controller.context_size_set() ? 64 : 32; const uint32_t context_size = m_controller.context_size_set() ? 64 : 32;
const uint32_t portsc = m_controller.operational_regs().ports[m_port_id - 1].portsc; bool is_ls_or_fs_device_on_hs_hub = false;
const uint32_t speed_id = (portsc >> XHCI::PORTSC::PORT_SPEED_SHIFT) & XHCI::PORTSC::PORT_SPEED_MASK;
m_endpoints[0].max_packet_size = 0; m_endpoints[0].max_packet_size = 0;
switch (m_speed_class) switch (m_speed_class)
@ -51,6 +42,7 @@ namespace Kernel
case USB::SpeedClass::LowSpeed: case USB::SpeedClass::LowSpeed:
case USB::SpeedClass::FullSpeed: case USB::SpeedClass::FullSpeed:
m_endpoints[0].max_packet_size = 8; m_endpoints[0].max_packet_size = 8;
is_ls_or_fs_device_on_hs_hub = m_info.parent_hub && (m_info.parent_hub->speed_class() == USB::SpeedClass::HighSpeed);
break; break;
case USB::SpeedClass::HighSpeed: case USB::SpeedClass::HighSpeed:
m_endpoints[0].max_packet_size = 64; m_endpoints[0].max_packet_size = 64;
@ -75,25 +67,32 @@ namespace Kernel
auto& slot_context = *reinterpret_cast<XHCI::SlotContext*> (m_input_context->vaddr() + 1 * context_size); auto& slot_context = *reinterpret_cast<XHCI::SlotContext*> (m_input_context->vaddr() + 1 * context_size);
auto& endpoint0_context = *reinterpret_cast<XHCI::EndpointContext*> (m_input_context->vaddr() + 2 * context_size); auto& endpoint0_context = *reinterpret_cast<XHCI::EndpointContext*> (m_input_context->vaddr() + 2 * context_size);
memset(&input_control_context, 0, context_size); input_control_context.add_context_flags = (1 << 1) | (1 << 0);
input_control_context.add_context_flags = 0b11;
memset(&slot_context, 0, context_size); slot_context.route_string = m_info.route_string >> 4;
slot_context.route_string = 0; slot_context.root_hub_port_number = m_info.route_string & 0x0F;
slot_context.root_hub_port_number = m_port_id;
slot_context.context_entries = 1; slot_context.context_entries = 1;
slot_context.interrupter_target = 0; slot_context.interrupter_target = 0;
slot_context.speed = speed_id; slot_context.speed = m_controller.speed_class_to_id(m_info.speed_class);
// FIXME: 4.5.2 hub if (is_ls_or_fs_device_on_hs_hub)
{
slot_context.parent_hub_slot_id = m_info.parent_hub->m_info.slot_id;
slot_context.parent_port_number = m_info.parent_port_id;
slot_context.multi_tt = m_info.parent_hub->is_multi_tt();
}
memset(&endpoint0_context, 0, context_size);
endpoint0_context.endpoint_type = XHCI::EndpointType::Control; endpoint0_context.endpoint_type = XHCI::EndpointType::Control;
endpoint0_context.max_packet_size = m_endpoints[0].max_packet_size; endpoint0_context.max_packet_size = m_endpoints[0].max_packet_size;
endpoint0_context.error_count = 3; endpoint0_context.max_burst_size = 0; // FIXME: SuperSpeed
endpoint0_context.interval = 0;
endpoint0_context.tr_dequeue_pointer = m_endpoints[0].transfer_ring->paddr() | 1; endpoint0_context.tr_dequeue_pointer = m_endpoints[0].transfer_ring->paddr() | 1;
endpoint0_context.max_primary_streams = 0;
endpoint0_context.error_count = 3;
} }
m_controller.dcbaa_reg(m_slot_id) = m_output_context->paddr(); m_controller.dcbaa_reg(m_info.slot_id) = m_output_context->paddr();
dprintln_if(DEBUG_XHCI, "Addressing device on slot {}", m_info.slot_id);
for (int i = 0; i < 2; i++) for (int i = 0; i < 2; i++)
{ {
@ -102,7 +101,7 @@ namespace Kernel
address_device.address_device_command.input_context_pointer = m_input_context->paddr(); address_device.address_device_command.input_context_pointer = m_input_context->paddr();
// NOTE: some legacy devices require sending request with BSR=1 before actual BSR=0 // NOTE: some legacy devices require sending request with BSR=1 before actual BSR=0
address_device.address_device_command.block_set_address_request = (i == 0); address_device.address_device_command.block_set_address_request = (i == 0);
address_device.address_device_command.slot_id = m_slot_id; address_device.address_device_command.slot_id = m_info.slot_id;
TRY(m_controller.send_command(address_device)); TRY(m_controller.send_command(address_device));
} }
@ -123,12 +122,14 @@ namespace Kernel
USBDeviceRequest request; USBDeviceRequest request;
request.bmRequestType = USB::RequestType::DeviceToHost | USB::RequestType::Standard | USB::RequestType::Device; request.bmRequestType = USB::RequestType::DeviceToHost | USB::RequestType::Standard | USB::RequestType::Device;
request.bRequest = USB::Request::GET_DESCRIPTOR; request.bRequest = USB::Request::GET_DESCRIPTOR;
request.wValue = 0x0100; request.wValue = USB::DescriptorType::DEVICE << 8;
request.wIndex = 0; request.wIndex = 0;
request.wLength = 8; request.wLength = 8;
TRY(send_request(request, kmalloc_paddr_of((vaddr_t)buffer.data()).value())); TRY(send_request(request, kmalloc_paddr_of((vaddr_t)buffer.data()).value()));
const bool is_usb3 = m_controller.port(m_port_id).revision_major == 3; dprintln_if(DEBUG_XHCI, "Got device descriptor");
const bool is_usb3 = (m_speed_class == USB::SpeedClass::SuperSpeed);
const uint32_t new_max_packet_size = is_usb3 ? 1u << buffer.back() : buffer.back(); const uint32_t new_max_packet_size = is_usb3 ? 1u << buffer.back() : buffer.back();
if (m_endpoints[0].max_packet_size == new_max_packet_size) if (m_endpoints[0].max_packet_size == new_max_packet_size)
@ -140,39 +141,38 @@ namespace Kernel
{ {
auto& input_control_context = *reinterpret_cast<XHCI::InputControlContext*>(m_input_context->vaddr() + 0 * context_size); auto& input_control_context = *reinterpret_cast<XHCI::InputControlContext*>(m_input_context->vaddr() + 0 * context_size);
auto& slot_context = *reinterpret_cast<XHCI::SlotContext*> (m_input_context->vaddr() + 1 * context_size);
auto& endpoint0_context = *reinterpret_cast<XHCI::EndpointContext*> (m_input_context->vaddr() + 2 * context_size); auto& endpoint0_context = *reinterpret_cast<XHCI::EndpointContext*> (m_input_context->vaddr() + 2 * context_size);
memset(&input_control_context, 0, context_size); memset(&input_control_context, 0, context_size);
input_control_context.add_context_flags = 0b11; input_control_context.add_context_flags = (1 << 1);
memset(&slot_context, 0, context_size); // Only update max packet size. Other fields should be fine from initial configuration
slot_context.max_exit_latency = 0; // FIXME: endpoint0_context.max_packet_size = new_max_packet_size;
slot_context.interrupter_target = 0;
memset(&endpoint0_context, 0, context_size);
endpoint0_context.endpoint_type = XHCI::EndpointType::Control;
endpoint0_context.max_packet_size = m_endpoints[0].max_packet_size;
endpoint0_context.error_count = 3;
endpoint0_context.tr_dequeue_pointer = m_endpoints[0].transfer_ring->paddr() | 1;
} }
XHCI::TRB evaluate_context { .address_device_command = {} }; XHCI::TRB evaluate_context { .address_device_command = {} };
evaluate_context.address_device_command.trb_type = XHCI::TRBType::EvaluateContextCommand; evaluate_context.address_device_command.trb_type = XHCI::TRBType::EvaluateContextCommand;
evaluate_context.address_device_command.input_context_pointer = m_input_context->paddr(); evaluate_context.address_device_command.input_context_pointer = m_input_context->paddr();
evaluate_context.address_device_command.block_set_address_request = 0; evaluate_context.address_device_command.block_set_address_request = 0;
evaluate_context.address_device_command.slot_id = m_slot_id; evaluate_context.address_device_command.slot_id = m_info.slot_id;
TRY(m_controller.send_command(evaluate_context)); TRY(m_controller.send_command(evaluate_context));
dprintln_if(DEBUG_XHCI, "successfully updated max packet size to {}", m_endpoints[0].max_packet_size); dprintln_if(DEBUG_XHCI, "Updated max packet size to {}", new_max_packet_size);
return {}; return {};
} }
bool XHCIDevice::is_multi_tt() const
{
const uint32_t context_size = m_controller.context_size_set() ? 64 : 32;
const auto& slot_context = *reinterpret_cast<const XHCI::SlotContext*>(m_input_context->vaddr() + context_size);
return slot_context.multi_tt;
}
// 6.2.3.6 Interval // 6.2.3.6 Interval
static uint32_t determine_interval(const USBEndpointDescriptor& endpoint_descriptor, USB::SpeedClass speed_class) static uint32_t determine_interval(const USBEndpointDescriptor& endpoint_descriptor, USB::SpeedClass speed_class)
{ {
auto ep_type = static_cast<USB::EndpointType>(endpoint_descriptor.bDescriptorType & 0x03); const auto ep_type = static_cast<USB::EndpointType>(endpoint_descriptor.bmAttributes & 0x03);
switch (speed_class) switch (speed_class)
{ {
@ -202,18 +202,31 @@ namespace Kernel
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
BAN::ErrorOr<void> XHCIDevice::initialize_endpoint(const USBEndpointDescriptor& endpoint_descriptor) BAN::ErrorOr<uint8_t> XHCIDevice::initialize_device_on_hub_port(uint8_t port_id, USB::SpeedClass speed_class)
{
if (m_info.depth + 1 > 5)
{
dwarnln("Invalid USB hub on depth {}", m_info.depth);
return BAN::Error::from_errno(EFAULT);
}
uint32_t route_string = m_info.route_string;
route_string |= static_cast<uint32_t>(port_id) << ((m_info.depth + 1) * 4);
return m_controller.initialize_device(route_string, m_info.depth + 1, speed_class, this, port_id);
}
void XHCIDevice::deinitialize_device_slot(uint8_t slot_id)
{
m_controller.deinitialize_slot(slot_id);
}
BAN::ErrorOr<void> XHCIDevice::configure_endpoint(const USBEndpointDescriptor& endpoint_descriptor, const HubInfo& hub_info)
{ {
const bool is_control { (endpoint_descriptor.bmAttributes & 0x03) == 0x00 }; const bool is_control { (endpoint_descriptor.bmAttributes & 0x03) == 0x00 };
const bool is_isoch { (endpoint_descriptor.bmAttributes & 0x03) == 0x01 }; const bool is_isoch { (endpoint_descriptor.bmAttributes & 0x03) == 0x01 };
const bool is_bulk { (endpoint_descriptor.bmAttributes & 0x03) == 0x02 }; const bool is_bulk { (endpoint_descriptor.bmAttributes & 0x03) == 0x02 };
const bool is_interrupt { (endpoint_descriptor.bmAttributes & 0x03) == 0x03 }; const bool is_interrupt { (endpoint_descriptor.bmAttributes & 0x03) == 0x03 };
(void)is_control;
(void)is_isoch;
(void)is_bulk;
(void)is_interrupt;
XHCI::EndpointType endpoint_type; XHCI::EndpointType endpoint_type;
switch ((endpoint_descriptor.bEndpointAddress & 0x80) | (endpoint_descriptor.bmAttributes & 0x03)) switch ((endpoint_descriptor.bEndpointAddress & 0x80) | (endpoint_descriptor.bmAttributes & 0x03))
{ {
@ -238,20 +251,29 @@ namespace Kernel
const uint32_t average_trb_length = (is_control) ? 8 : max_esit_payload; const uint32_t average_trb_length = (is_control) ? 8 : max_esit_payload;
const uint32_t error_count = (is_isoch) ? 0 : 3; const uint32_t error_count = (is_isoch) ? 0 : 3;
auto& endpoint = m_endpoints[endpoint_id - 1];
ASSERT(!endpoint.transfer_ring);
uint32_t last_valid_endpoint_id = endpoint_id; uint32_t last_valid_endpoint_id = endpoint_id;
for (size_t i = endpoint_id; i < m_endpoints.size(); i++) for (size_t i = endpoint_id; i < m_endpoints.size(); i++)
if (m_endpoints[i].transfer_ring) if (m_endpoints[i].transfer_ring)
last_valid_endpoint_id = i + 1; last_valid_endpoint_id = i + 1;
endpoint.transfer_ring = TRY(DMARegion::create(m_transfer_ring_trb_count * sizeof(XHCI::TRB))); auto& endpoint = m_endpoints[endpoint_id - 1];
endpoint.max_packet_size = max_packet_size; LockGuard _(endpoint.mutex);
endpoint.dequeue_index = 0;
endpoint.enqueue_index = 0; if (!endpoint.transfer_ring)
endpoint.cycle_bit = 1; {
endpoint.callback = (is_interrupt || is_bulk) ? &XHCIDevice::on_interrupt_or_bulk_endpoint_event : nullptr; endpoint.transfer_ring = TRY(DMARegion::create(m_transfer_ring_trb_count * sizeof(XHCI::TRB)));
endpoint.max_packet_size = max_packet_size;
endpoint.dequeue_index = 0;
endpoint.enqueue_index = 0;
endpoint.cycle_bit = 1;
endpoint.callback = (is_interrupt || is_bulk) ? &XHCIDevice::on_interrupt_or_bulk_endpoint_event : nullptr;
}
else
{
endpoint.dequeue_index = 0;
endpoint.enqueue_index = 0;
endpoint.cycle_bit = 1;
}
memset(reinterpret_cast<void*>(endpoint.transfer_ring->vaddr()), 0, endpoint.transfer_ring->size()); memset(reinterpret_cast<void*>(endpoint.transfer_ring->vaddr()), 0, endpoint.transfer_ring->size());
@ -263,11 +285,16 @@ namespace Kernel
auto& endpoint_context = *reinterpret_cast<XHCI::EndpointContext*> (m_input_context->vaddr() + (endpoint_id + 1) * context_size); auto& endpoint_context = *reinterpret_cast<XHCI::EndpointContext*> (m_input_context->vaddr() + (endpoint_id + 1) * context_size);
memset(&input_control_context, 0, context_size); memset(&input_control_context, 0, context_size);
input_control_context.add_context_flags = (1u << endpoint_id) | 1; input_control_context.add_context_flags = (1u << endpoint_id) | (1 << 0);
memset(&slot_context, 0, context_size);
slot_context.context_entries = last_valid_endpoint_id; slot_context.context_entries = last_valid_endpoint_id;
// FIXME: 4.5.2 hub slot_context.hub = (hub_info.number_of_ports > 0);
slot_context.number_of_ports = hub_info.number_of_ports;
if (m_speed_class == USB::SpeedClass::HighSpeed)
{
slot_context.multi_tt = hub_info.multi_tt;
slot_context.tt_think_time = hub_info.tt_think_time;
}
memset(&endpoint_context, 0, context_size); memset(&endpoint_context, 0, context_size);
endpoint_context.endpoint_type = endpoint_type; endpoint_context.endpoint_type = endpoint_type;
@ -286,7 +313,7 @@ namespace Kernel
configure_endpoint.configure_endpoint_command.trb_type = XHCI::TRBType::ConfigureEndpointCommand; configure_endpoint.configure_endpoint_command.trb_type = XHCI::TRBType::ConfigureEndpointCommand;
configure_endpoint.configure_endpoint_command.input_context_pointer = m_input_context->paddr(); configure_endpoint.configure_endpoint_command.input_context_pointer = m_input_context->paddr();
configure_endpoint.configure_endpoint_command.deconfigure = 0; configure_endpoint.configure_endpoint_command.deconfigure = 0;
configure_endpoint.configure_endpoint_command.slot_id = m_slot_id; configure_endpoint.configure_endpoint_command.slot_id = m_info.slot_id;
TRY(m_controller.send_command(configure_endpoint)); TRY(m_controller.send_command(configure_endpoint));
return {}; return {};
@ -368,17 +395,9 @@ namespace Kernel
BAN::ErrorOr<size_t> XHCIDevice::send_request(const USBDeviceRequest& request, paddr_t buffer_paddr) BAN::ErrorOr<size_t> XHCIDevice::send_request(const USBDeviceRequest& request, paddr_t buffer_paddr)
{ {
// FIXME: This is more or less generic USB code ASSERT(request.wLength == 0 || buffer_paddr);
auto& endpoint = m_endpoints[0]; const uint8_t transfer_type =
// minus 3: Setup, Status, Link (this is probably too generous and will result in STALL)
if (request.wLength > (m_transfer_ring_trb_count - 3) * endpoint.max_packet_size)
return BAN::Error::from_errno((ENOBUFS));
LockGuard _(endpoint.mutex);
uint8_t transfer_type =
[&request]() -> uint8_t [&request]() -> uint8_t
{ {
if (request.wLength == 0) if (request.wLength == 0)
@ -388,6 +407,12 @@ namespace Kernel
return 2; return 2;
}(); }();
const bool status_stage_dir = !((request.wLength > 0) && (request.bmRequestType & USB::RequestType::DeviceToHost));
auto& endpoint = m_endpoints[0];
LockGuard _(endpoint.mutex);
auto* transfer_trb_arr = reinterpret_cast<volatile XHCI::TRB*>(endpoint.transfer_ring->vaddr()); auto* transfer_trb_arr = reinterpret_cast<volatile XHCI::TRB*>(endpoint.transfer_ring->vaddr());
{ {
@ -410,32 +435,23 @@ namespace Kernel
advance_endpoint_enqueue(endpoint, false); advance_endpoint_enqueue(endpoint, false);
} }
const uint32_t td_packet_count = BAN::Math::div_round_up<uint32_t>(request.wLength, endpoint.max_packet_size); if (request.wLength)
uint32_t packets_transferred = 1;
uint32_t bytes_handled = 0;
while (bytes_handled < request.wLength)
{ {
const uint32_t to_handle = BAN::Math::min<uint32_t>(endpoint.max_packet_size, request.wLength - bytes_handled);
auto& trb = transfer_trb_arr[endpoint.enqueue_index]; auto& trb = transfer_trb_arr[endpoint.enqueue_index];
memset(const_cast<XHCI::TRB*>(&trb), 0, sizeof(XHCI::TRB)); memset(const_cast<XHCI::TRB*>(&trb), 0, sizeof(XHCI::TRB));
trb.data_stage.trb_type = XHCI::TRBType::DataStage; trb.data_stage.trb_type = XHCI::TRBType::DataStage;
trb.data_stage.direction = 1; trb.data_stage.direction = !!(request.bmRequestType & USB::RequestType::DeviceToHost);
trb.data_stage.trb_transfer_length = to_handle; trb.data_stage.trb_transfer_length = request.wLength;
trb.data_stage.td_size = BAN::Math::min<uint32_t>(td_packet_count - packets_transferred, 31); trb.data_stage.td_size = 0;
trb.data_stage.chain_bit = (bytes_handled + to_handle < request.wLength); trb.data_stage.chain_bit = 0;
trb.data_stage.interrupt_on_completion = 0; trb.data_stage.interrupt_on_completion = 0;
trb.data_stage.interrupt_on_short_packet = 1; trb.data_stage.interrupt_on_short_packet = 0;
trb.data_stage.immediate_data = 0; trb.data_stage.immediate_data = 0;
trb.data_stage.data_buffer_pointer = buffer_paddr + bytes_handled; trb.data_stage.data_buffer_pointer = buffer_paddr;
trb.data_stage.cycle_bit = endpoint.cycle_bit; trb.data_stage.cycle_bit = endpoint.cycle_bit;
bytes_handled += to_handle; advance_endpoint_enqueue(endpoint, false);
packets_transferred++;
advance_endpoint_enqueue(endpoint, trb.data_stage.chain_bit);
} }
{ {
@ -443,10 +459,10 @@ namespace Kernel
memset(const_cast<XHCI::TRB*>(&trb), 0, sizeof(XHCI::TRB)); memset(const_cast<XHCI::TRB*>(&trb), 0, sizeof(XHCI::TRB));
trb.status_stage.trb_type = XHCI::TRBType::StatusStage; trb.status_stage.trb_type = XHCI::TRBType::StatusStage;
trb.status_stage.direction = 0; trb.status_stage.direction = status_stage_dir;
trb.status_stage.chain_bit = 0; trb.status_stage.chain_bit = 0;
trb.status_stage.interrupt_on_completion = 1; trb.status_stage.interrupt_on_completion = 1;
trb.data_stage.cycle_bit = endpoint.cycle_bit; trb.status_stage.cycle_bit = endpoint.cycle_bit;
advance_endpoint_enqueue(endpoint, false); advance_endpoint_enqueue(endpoint, false);
} }
@ -459,7 +475,7 @@ namespace Kernel
endpoint.transfer_count = request.wLength; endpoint.transfer_count = request.wLength;
m_controller.doorbell_reg(m_slot_id) = 1; m_controller.doorbell_reg(m_info.slot_id) = 1;
const uint64_t timeout_ms = SystemTimer::get().ms_since_boot() + 1000; const uint64_t timeout_ms = SystemTimer::get().ms_since_boot() + 1000;
while ((__atomic_load_n(&completion_trb.raw.dword2, __ATOMIC_SEQ_CST) >> 24) == 0) while ((__atomic_load_n(&completion_trb.raw.dword2, __ATOMIC_SEQ_CST) >> 24) == 0)
@ -482,7 +498,7 @@ namespace Kernel
ASSERT(endpoint_id != 0); ASSERT(endpoint_id != 0);
auto& endpoint = m_endpoints[endpoint_id - 1]; auto& endpoint = m_endpoints[endpoint_id - 1];
ASSERT(buffer_len <= endpoint.max_packet_size); ASSERT(buffer_len <= (1 << 16));
auto& trb = *reinterpret_cast<volatile XHCI::TRB*>(endpoint.transfer_ring->vaddr() + endpoint.enqueue_index * sizeof(XHCI::TRB)); auto& trb = *reinterpret_cast<volatile XHCI::TRB*>(endpoint.transfer_ring->vaddr() + endpoint.enqueue_index * sizeof(XHCI::TRB));
memset(const_cast<XHCI::TRB*>(&trb), 0, sizeof(XHCI::TRB)); memset(const_cast<XHCI::TRB*>(&trb), 0, sizeof(XHCI::TRB));
@ -496,7 +512,7 @@ namespace Kernel
trb.normal.interrupt_on_short_packet = 1; trb.normal.interrupt_on_short_packet = 1;
advance_endpoint_enqueue(endpoint, false); advance_endpoint_enqueue(endpoint, false);
m_controller.doorbell_reg(m_slot_id) = endpoint_id; m_controller.doorbell_reg(m_info.slot_id) = endpoint_id;
} }
void XHCIDevice::advance_endpoint_enqueue(Endpoint& endpoint, bool chain) void XHCIDevice::advance_endpoint_enqueue(Endpoint& endpoint, bool chain)

View File

@ -228,11 +228,13 @@ static void init2(void*)
dprintln("USBManager initialized"); dprintln("USBManager initialized");
} }
if (!cmdline.disable_acpi && ACPI::ACPI::get().enter_acpi_mode(InterruptController::get().is_using_apic()).is_error()) if (!cmdline.disable_acpi)
dprintln("Failed to enter ACPI mode"); {
if (auto ret = ACPI::ACPI::get().enter_acpi_mode(InterruptController::get().is_using_apic()); ret.is_error())
if (auto ret = ACPI::ACPI::get().initialize_acpi_devices(); ret.is_error()) dprintln("Failed to enter ACPI mode: {}", ret.error());
dwarnln("Could not initialize ACPI devices: {}", ret.error()); if (auto ret = ACPI::ACPI::get().initialize_acpi_devices(); ret.is_error())
dwarnln("Could not initialize ACPI devices: {}", ret.error());
}
DevFileSystem::get().initialize_device_updater(); DevFileSystem::get().initialize_device_updater();