Compare commits
17 Commits
b30a79c7fe
...
d0452a3510
Author | SHA1 | Date |
---|---|---|
|
d0452a3510 | |
|
11310e7615 | |
|
22b32a0fe5 | |
|
ad143c184f | |
|
803a4cd163 | |
|
267fdf9fa1 | |
|
26d2a4420e | |
|
c623ad7da0 | |
|
7de689055c | |
|
63b15a8855 | |
|
a2a7302964 | |
|
6a5367dbe3 | |
|
6768a18475 | |
|
242ed4a3c2 | |
|
f9b70d1b5b | |
|
faa5252191 | |
|
4212f48d7a |
|
@ -306,20 +306,8 @@ memset32:
|
|||
movw $GDT_DATA32, %dx
|
||||
movw %dx, %es
|
||||
|
||||
movl %ecx, %edx
|
||||
|
||||
andl $3, %ecx
|
||||
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
|
||||
|
||||
.code16
|
||||
|
@ -370,14 +358,8 @@ memcpy32:
|
|||
movw %dx, %ds
|
||||
movw %dx, %es
|
||||
|
||||
movl %ecx, %edx
|
||||
andl $3, %ecx
|
||||
rep movsb %ds:(%esi), %es:(%edi)
|
||||
|
||||
movl %edx, %ecx
|
||||
shrl $2, %ecx
|
||||
rep movsl %ds:(%esi), %es:(%edi)
|
||||
|
||||
ljmpl $GDT_CODE16, $.memcpy32_pmode16
|
||||
|
||||
.code16
|
||||
|
|
|
@ -96,10 +96,12 @@ set(KERNEL_SOURCES
|
|||
kernel/Timer/PIT.cpp
|
||||
kernel/Timer/RTC.cpp
|
||||
kernel/Timer/Timer.cpp
|
||||
kernel/USB/Controller.cpp
|
||||
kernel/USB/Device.cpp
|
||||
kernel/USB/HID/HIDDriver.cpp
|
||||
kernel/USB/HID/Keyboard.cpp
|
||||
kernel/USB/HID/Mouse.cpp
|
||||
kernel/USB/Hub/HubDriver.cpp
|
||||
kernel/USB/MassStorage/MassStorageDriver.cpp
|
||||
kernel/USB/MassStorage/SCSIDevice.cpp
|
||||
kernel/USB/USBManager.cpp
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace Kernel
|
|||
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:
|
||||
virtual BAN::ErrorOr<void> read_blocks(uint64_t first_block, size_t block_count, BAN::ByteSpan) = 0;
|
||||
|
|
|
@ -97,6 +97,8 @@ namespace Kernel::PCI
|
|||
BAN::ErrorOr<void> reserve_interrupts(uint8_t count);
|
||||
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);
|
||||
|
||||
void enable_bus_mastering();
|
||||
|
|
|
@ -13,9 +13,8 @@ namespace Kernel
|
|||
|
||||
const BAN::GUID& partition_type() const { return m_type; }
|
||||
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> 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);
|
||||
|
||||
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_guid;
|
||||
const BAN::String m_guid_string;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <BAN/CircularQueue.h>
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/Optional.h>
|
||||
#include <kernel/Interruptable.h>
|
||||
#include <kernel/Terminal/TTY.h>
|
||||
|
||||
|
@ -13,12 +14,12 @@ namespace Kernel
|
|||
public:
|
||||
static void initialize();
|
||||
static bool has_devices();
|
||||
static void putchar_any(char);
|
||||
static void putchar_any(uint8_t);
|
||||
|
||||
static void initialize_devices();
|
||||
|
||||
void putchar(char);
|
||||
char getchar();
|
||||
void putchar(uint8_t);
|
||||
BAN::Optional<uint8_t> getchar();
|
||||
|
||||
bool is_valid() const { return m_port != 0; }
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace Kernel
|
|||
|
||||
void reset_ansi();
|
||||
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 render_from_buffer(uint32_t x, uint32_t y);
|
||||
void set_cursor_position(uint32_t x, uint32_t y);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
#include <BAN/NoCopyMove.h>
|
||||
|
||||
#include <kernel/Memory/DMARegion.h>
|
||||
#include <kernel/USB/USBManager.h>
|
||||
#include <kernel/USB/Controller.h>
|
||||
#include <kernel/USB/USBManager.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
@ -55,21 +55,41 @@ 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;
|
||||
|
||||
// Class drivers have to be destroyed before derived class destructor is called
|
||||
void destroy() { m_class_drivers.clear(); }
|
||||
|
||||
BAN::ErrorOr<void> initialize();
|
||||
|
||||
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 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:
|
||||
void handle_stall(uint8_t endpoint_id);
|
||||
|
@ -79,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;
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
}
|
|
@ -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>;
|
||||
};
|
||||
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
#include <kernel/Lock/Mutex.h>
|
||||
#include <kernel/Memory/DMARegion.h>
|
||||
#include <kernel/ThreadBlocker.h>
|
||||
#include <kernel/USB/Definitions.h>
|
||||
#include <kernel/USB/USBManager.h>
|
||||
#include <kernel/USB/XHCI/Definitions.h>
|
||||
|
||||
|
@ -23,19 +24,7 @@ namespace Kernel
|
|||
{
|
||||
uint8_t revision_major { 0 };
|
||||
uint8_t revision_minor { 0 };
|
||||
uint8_t slot_type { 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:
|
||||
|
@ -57,7 +46,8 @@ namespace Kernel
|
|||
|
||||
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&);
|
||||
void advance_command_enqueue();
|
||||
|
@ -74,16 +64,22 @@ namespace Kernel
|
|||
|
||||
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:
|
||||
static constexpr uint32_t m_command_ring_trb_count = 256;
|
||||
static constexpr uint32_t m_event_ring_trb_count = 252;
|
||||
|
||||
Mutex m_mutex;
|
||||
|
||||
Process* m_port_updater { nullptr };
|
||||
BAN::Atomic<Process*> m_port_updater { nullptr };
|
||||
ThreadBlocker m_port_thread_blocker;
|
||||
BAN::Atomic<bool> m_port_changed { false };
|
||||
|
||||
bool m_running { true };
|
||||
bool m_ports_initialized { false };
|
||||
|
||||
PCI::Device& m_pci_device;
|
||||
BAN::UniqPtr<PCI::BarRegion> m_configuration_bar;
|
||||
BAN::UniqPtr<DMARegion> m_dcbaa_region;
|
||||
|
|
|
@ -30,10 +30,23 @@ namespace Kernel
|
|||
void(XHCIDevice::*callback)(XHCI::TRB);
|
||||
};
|
||||
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::UniqPtr<XHCIDevice>> create(XHCIController&, uint32_t port_id, uint32_t slot_id);
|
||||
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;
|
||||
};
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
private:
|
||||
XHCIDevice(XHCIController& controller, uint32_t port_id, uint32_t slot_id);
|
||||
XHCIDevice(XHCIController& controller, const Info& info);
|
||||
~XHCIDevice();
|
||||
|
||||
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);
|
||||
|
||||
static uint64_t calculate_port_bits_per_second(XHCIController&, uint32_t port_id);
|
||||
|
||||
private:
|
||||
static constexpr uint32_t m_transfer_ring_trb_count = PAGE_SIZE / sizeof(XHCI::TRB);
|
||||
|
||||
XHCIController& m_controller;
|
||||
const uint32_t m_port_id;
|
||||
const uint32_t m_slot_id;
|
||||
Info m_info;
|
||||
|
||||
Mutex m_mutex;
|
||||
|
||||
|
|
|
@ -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)
|
||||
: BlockDevice(0660, 0, 0)
|
||||
, m_device(device)
|
||||
, m_block_size(device->blksize())
|
||||
, m_type(type)
|
||||
, m_guid(guid)
|
||||
, 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)
|
||||
{
|
||||
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;
|
||||
if (first_block + block_count > blocks_in_partition)
|
||||
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 {};
|
||||
}
|
||||
|
||||
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;
|
||||
if (first_block + block_count > blocks_in_partition)
|
||||
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 {};
|
||||
}
|
||||
|
||||
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;
|
||||
if (block + block_count > blocks_in_partition)
|
||||
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 {};
|
||||
}
|
||||
|
||||
|
@ -61,12 +74,16 @@ namespace Kernel
|
|||
{
|
||||
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);
|
||||
|
||||
const uint32_t blocks_in_partition = m_last_block - m_first_block + 1;
|
||||
uint32_t first_block = offset / m_device->blksize();
|
||||
uint32_t block_count = buffer.size() / m_device->blksize();
|
||||
uint32_t first_block = offset / device->blksize();
|
||||
uint32_t block_count = buffer.size() / device->blksize();
|
||||
|
||||
if (first_block >= blocks_in_partition)
|
||||
return 0;
|
||||
|
@ -74,7 +91,7 @@ namespace Kernel
|
|||
block_count = blocks_in_partition - first_block;
|
||||
|
||||
TRY(read_blocks(first_block, block_count, buffer));
|
||||
return block_count * m_device->blksize();
|
||||
return block_count * device->blksize();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -204,6 +204,9 @@ namespace Kernel
|
|||
|
||||
StorageDevice::~StorageDevice()
|
||||
{
|
||||
for (auto& partition : m_partitions)
|
||||
if (partition)
|
||||
DevFileSystem::get().remove_device(partition);
|
||||
}
|
||||
|
||||
void StorageDevice::add_disk_cache()
|
||||
|
|
|
@ -107,41 +107,38 @@ namespace Kernel
|
|||
while (*ptr)
|
||||
putchar(*ptr++);
|
||||
|
||||
if (getchar() != '\033')
|
||||
if (auto ch = getchar(); !ch.has_value() || ch.value() != '\033')
|
||||
return false;
|
||||
if (getchar() != '[')
|
||||
if (auto ch = getchar(); !ch.has_value() || ch.value() != '[')
|
||||
return false;
|
||||
|
||||
auto read_number =
|
||||
[&](char end)
|
||||
[&](uint8_t end) -> BAN::Optional<uint32_t>
|
||||
{
|
||||
uint32_t number = 0;
|
||||
while (true)
|
||||
{
|
||||
char c = getchar();
|
||||
if (c == end)
|
||||
break;
|
||||
if (!isdigit(c))
|
||||
return UINT32_MAX;
|
||||
number = (number * 10) + (c - '0');
|
||||
}
|
||||
const auto ch = getchar();
|
||||
if (!ch.has_value())
|
||||
return {};
|
||||
if (ch.value() == end)
|
||||
return number;
|
||||
if (!isdigit(ch.value()))
|
||||
return {};
|
||||
number = (number * 10) + (ch.value() - '0');
|
||||
}
|
||||
};
|
||||
|
||||
m_height = read_number(';');
|
||||
if (m_height == UINT32_MAX)
|
||||
{
|
||||
m_port = 0;
|
||||
const auto height = read_number(';');
|
||||
if (!height.has_value())
|
||||
return false;
|
||||
}
|
||||
|
||||
m_width = read_number('R');
|
||||
if (m_width == UINT32_MAX)
|
||||
{
|
||||
m_port = 0;
|
||||
const auto width = read_number('R');
|
||||
if (!width.has_value())
|
||||
return false;
|
||||
}
|
||||
|
||||
m_height = height.value();
|
||||
m_width = width.value();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -150,25 +147,26 @@ namespace Kernel
|
|||
return s_has_devices;
|
||||
}
|
||||
|
||||
void Serial::putchar(char c)
|
||||
void Serial::putchar(uint8_t ch)
|
||||
{
|
||||
while (!(IO::inb(m_port + 5) & 0x20))
|
||||
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))
|
||||
continue;
|
||||
for (size_t i = 0; i < 10'000'000; i++)
|
||||
if (IO::inb(m_port + 5) & 0x01)
|
||||
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)
|
||||
if (device.is_valid())
|
||||
device.putchar(c);
|
||||
return device.putchar(ch);
|
||||
}
|
||||
|
||||
SerialTTY::SerialTTY(Serial serial)
|
||||
|
|
|
@ -110,12 +110,11 @@ namespace Kernel
|
|||
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());
|
||||
switch (m_ansi_state.nums[0])
|
||||
switch (ch)
|
||||
{
|
||||
case -1:
|
||||
case 0:
|
||||
m_foreground = TerminalColor::BRIGHT_WHITE;
|
||||
m_background = TerminalColor::BLACK;
|
||||
|
@ -165,18 +164,25 @@ namespace Kernel
|
|||
|
||||
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());
|
||||
switch (ch)
|
||||
{
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
{
|
||||
if ((size_t)m_ansi_state.index >= max_ansi_args)
|
||||
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;
|
||||
}
|
||||
case ';':
|
||||
m_ansi_state.index++;
|
||||
m_ansi_state.index = BAN::Math::min<size_t>(m_ansi_state.index + 1, max_ansi_args);
|
||||
return;
|
||||
case 'A': // Cursor Up
|
||||
if (m_ansi_state.nums[0] == -1)
|
||||
|
@ -308,7 +314,9 @@ namespace Kernel
|
|||
dprintln_if(DEBUG_VTTY, "Unsupported ANSI CSI character f");
|
||||
return;
|
||||
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();
|
||||
case 's':
|
||||
m_saved_row = m_row;
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
#include <kernel/Memory/DMARegion.h>
|
||||
#include <kernel/USB/Device.h>
|
||||
#include <kernel/USB/HID/HIDDriver.h>
|
||||
#include <kernel/USB/Hub/HubDriver.h>
|
||||
#include <kernel/USB/MassStorage/MassStorageDriver.h>
|
||||
|
||||
#define USB_DUMP_DESCRIPTORS 0
|
||||
|
@ -107,8 +108,26 @@ namespace Kernel
|
|||
dprintln_if(DEBUG_USB, "Found CommunicationAndCDCControl device");
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
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:
|
||||
dprintln_if(DEBUG_USB, "Found BillboardDeviceClass device");
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
|
@ -146,6 +165,10 @@ namespace Kernel
|
|||
|
||||
for (const auto& interface : configuration.interfaces)
|
||||
{
|
||||
// FIXME: support alternate settings
|
||||
if (interface.descriptor.bAlternateSetting != 0)
|
||||
continue;
|
||||
|
||||
switch (static_cast<USB::InterfaceBaseClass>(interface.descriptor.bInterfaceClass))
|
||||
{
|
||||
case USB::InterfaceBaseClass::Audio:
|
||||
|
@ -340,15 +363,4 @@ namespace Kernel
|
|||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -194,7 +194,7 @@ namespace Kernel
|
|||
if ((desc.bmAttributes & 0x03) != 0x03)
|
||||
continue;
|
||||
|
||||
TRY(m_device.initialize_endpoint(desc));
|
||||
TRY(m_device.configure_endpoint(desc));
|
||||
m_data_buffer = TRY(DMARegion::create(desc.wMaxPacketSize & 0x07FF));
|
||||
|
||||
m_data_endpoint_id = (desc.bEndpointAddress & 0x0F) * 2 + !!(desc.bEndpointAddress & 0x80);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -20,7 +20,11 @@ namespace Kernel
|
|||
{ }
|
||||
|
||||
USBMassStorageDriver::~USBMassStorageDriver()
|
||||
{ }
|
||||
{
|
||||
for (auto& device : m_storage_devices)
|
||||
if (device)
|
||||
DevFileSystem::get().remove_device(device);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> USBMassStorageDriver::initialize()
|
||||
{
|
||||
|
@ -74,8 +78,8 @@ namespace Kernel
|
|||
return BAN::Error::from_errno(EFAULT);
|
||||
}
|
||||
|
||||
TRY(m_device.initialize_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_in_index].descriptor));
|
||||
TRY(m_device.configure_endpoint(m_interface.endpoints[bulk_out_index].descriptor));
|
||||
|
||||
{
|
||||
const auto& desc = m_interface.endpoints[bulk_in_index].descriptor;
|
||||
|
|
|
@ -16,8 +16,9 @@ namespace Kernel
|
|||
|
||||
XHCIController::~XHCIController()
|
||||
{
|
||||
if (m_port_updater)
|
||||
m_port_updater->exit(0, SIGKILL);
|
||||
m_running = false;
|
||||
while (m_port_updater)
|
||||
Processor::yield();
|
||||
|
||||
for (auto paddr : m_scratchpad_buffers)
|
||||
if (paddr)
|
||||
|
@ -148,6 +149,8 @@ namespace Kernel
|
|||
|
||||
ASSERT(m_ports.size() == max_ports);
|
||||
|
||||
bool overrides_speed_ids = false;
|
||||
|
||||
{
|
||||
uint16_t ext_offset = capabilities.hccparams1.xhci_extended_capabilities_pointer;
|
||||
if (ext_offset == 0)
|
||||
|
@ -159,11 +162,11 @@ namespace Kernel
|
|||
vaddr_t ext_addr = m_configuration_bar->vaddr() + ext_offset * 4;
|
||||
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)
|
||||
{
|
||||
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 {
|
||||
('U' << 0) |
|
||||
|
@ -183,21 +186,20 @@ namespace Kernel
|
|||
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++)
|
||||
{
|
||||
auto& port = m_ports[protocol.compatible_port_offset + i - 1];
|
||||
port.revision_major = protocol.major_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
|
||||
auto& operational = operational_regs();
|
||||
operational.config.max_device_slots_enabled = capabilities.hcsparams1.max_slots;
|
||||
|
@ -214,6 +219,30 @@ namespace Kernel
|
|||
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()
|
||||
{
|
||||
TRY(m_pci_device.reserve_interrupts(1));
|
||||
|
@ -278,17 +307,28 @@ namespace Kernel
|
|||
// attached ports
|
||||
m_port_changed = true;
|
||||
|
||||
while (true)
|
||||
uint64_t last_port_update = SystemTimer::get().ms_since_boot();
|
||||
|
||||
while (m_running)
|
||||
{
|
||||
{
|
||||
bool expected { true };
|
||||
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);
|
||||
expected = true;
|
||||
}
|
||||
}
|
||||
|
||||
last_port_update = SystemTimer::get().ms_since_boot();;
|
||||
|
||||
for (size_t i = 0; i < m_ports.size(); i++)
|
||||
{
|
||||
auto& my_port = m_ports[i];
|
||||
|
@ -308,10 +348,9 @@ namespace Kernel
|
|||
|
||||
if (!(op_port.portsc & XHCI::PORTSC::CCS))
|
||||
{
|
||||
// if device detached, clear the port
|
||||
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;
|
||||
}
|
||||
continue;
|
||||
|
@ -336,7 +375,12 @@ namespace Kernel
|
|||
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: {}",
|
||||
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 {} };
|
||||
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));
|
||||
|
||||
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)
|
||||
{
|
||||
dwarnln("EnableSlot gave an invalid slot {}", slot_id);
|
||||
dwarnln("EnableSlotCommand returned an invalid slot {}", slot_id);
|
||||
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())
|
||||
{
|
||||
dwarnln("Could not initialize device on slot {}: {}", slot_id, ret.error());
|
||||
|
@ -373,11 +436,23 @@ namespace Kernel
|
|||
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()
|
||||
|
@ -464,6 +539,7 @@ namespace Kernel
|
|||
void XHCIController::handle_irq()
|
||||
{
|
||||
auto& primary_interrupter = runtime_regs().irs[0];
|
||||
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();
|
||||
|
|
|
@ -8,42 +8,33 @@
|
|||
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)
|
||||
{
|
||||
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)))
|
||||
XHCIDevice::XHCIDevice(XHCIController& controller, const Info& info)
|
||||
: USBDevice(controller, info.speed_class, info.depth)
|
||||
, m_controller(controller)
|
||||
, m_port_id(port_id)
|
||||
, m_slot_id(slot_id)
|
||||
, m_info(info)
|
||||
{}
|
||||
|
||||
XHCIDevice::~XHCIDevice()
|
||||
{
|
||||
XHCI::TRB disable_slot { .disable_slot_command {} };
|
||||
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())
|
||||
dwarnln("Could not disable slot {}: {}", m_slot_id, ret.error());
|
||||
dwarnln("Could not disable slot {}: {}", m_info.slot_id, ret.error());
|
||||
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()
|
||||
{
|
||||
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;
|
||||
const uint32_t speed_id = (portsc >> XHCI::PORTSC::PORT_SPEED_SHIFT) & XHCI::PORTSC::PORT_SPEED_MASK;
|
||||
bool is_ls_or_fs_device_on_hs_hub = false;
|
||||
|
||||
m_endpoints[0].max_packet_size = 0;
|
||||
switch (m_speed_class)
|
||||
|
@ -51,6 +42,7 @@ namespace Kernel
|
|||
case USB::SpeedClass::LowSpeed:
|
||||
case USB::SpeedClass::FullSpeed:
|
||||
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;
|
||||
case USB::SpeedClass::HighSpeed:
|
||||
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& 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 = 0b11;
|
||||
input_control_context.add_context_flags = (1 << 1) | (1 << 0);
|
||||
|
||||
memset(&slot_context, 0, context_size);
|
||||
slot_context.route_string = 0;
|
||||
slot_context.root_hub_port_number = m_port_id;
|
||||
slot_context.route_string = m_info.route_string >> 4;
|
||||
slot_context.root_hub_port_number = m_info.route_string & 0x0F;
|
||||
slot_context.context_entries = 1;
|
||||
slot_context.interrupter_target = 0;
|
||||
slot_context.speed = speed_id;
|
||||
// FIXME: 4.5.2 hub
|
||||
|
||||
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;
|
||||
slot_context.speed = m_controller.speed_class_to_id(m_info.speed_class);
|
||||
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();
|
||||
}
|
||||
|
||||
m_controller.dcbaa_reg(m_slot_id) = m_output_context->paddr();
|
||||
endpoint0_context.endpoint_type = XHCI::EndpointType::Control;
|
||||
endpoint0_context.max_packet_size = m_endpoints[0].max_packet_size;
|
||||
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.max_primary_streams = 0;
|
||||
endpoint0_context.error_count = 3;
|
||||
}
|
||||
|
||||
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++)
|
||||
{
|
||||
|
@ -102,7 +101,7 @@ namespace Kernel
|
|||
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
|
||||
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));
|
||||
}
|
||||
|
||||
|
@ -123,12 +122,14 @@ namespace Kernel
|
|||
USBDeviceRequest request;
|
||||
request.bmRequestType = USB::RequestType::DeviceToHost | USB::RequestType::Standard | USB::RequestType::Device;
|
||||
request.bRequest = USB::Request::GET_DESCRIPTOR;
|
||||
request.wValue = 0x0100;
|
||||
request.wValue = USB::DescriptorType::DEVICE << 8;
|
||||
request.wIndex = 0;
|
||||
request.wLength = 8;
|
||||
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();
|
||||
|
||||
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& 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);
|
||||
|
||||
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);
|
||||
slot_context.max_exit_latency = 0; // FIXME:
|
||||
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;
|
||||
// Only update max packet size. Other fields should be fine from initial configuration
|
||||
endpoint0_context.max_packet_size = new_max_packet_size;
|
||||
}
|
||||
|
||||
XHCI::TRB evaluate_context { .address_device_command = {} };
|
||||
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.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));
|
||||
|
||||
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 {};
|
||||
}
|
||||
|
||||
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
|
||||
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)
|
||||
{
|
||||
|
@ -202,18 +202,31 @@ namespace Kernel
|
|||
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_isoch { (endpoint_descriptor.bmAttributes & 0x03) == 0x01 };
|
||||
const bool is_bulk { (endpoint_descriptor.bmAttributes & 0x03) == 0x02 };
|
||||
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;
|
||||
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 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;
|
||||
for (size_t i = endpoint_id; i < m_endpoints.size(); i++)
|
||||
if (m_endpoints[i].transfer_ring)
|
||||
last_valid_endpoint_id = i + 1;
|
||||
|
||||
auto& endpoint = m_endpoints[endpoint_id - 1];
|
||||
LockGuard _(endpoint.mutex);
|
||||
|
||||
if (!endpoint.transfer_ring)
|
||||
{
|
||||
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());
|
||||
|
||||
|
@ -263,11 +285,16 @@ namespace Kernel
|
|||
auto& endpoint_context = *reinterpret_cast<XHCI::EndpointContext*> (m_input_context->vaddr() + (endpoint_id + 1) * 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;
|
||||
// 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);
|
||||
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.input_context_pointer = m_input_context->paddr();
|
||||
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));
|
||||
|
||||
return {};
|
||||
|
@ -368,17 +395,9 @@ namespace Kernel
|
|||
|
||||
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];
|
||||
|
||||
// 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 =
|
||||
const uint8_t transfer_type =
|
||||
[&request]() -> uint8_t
|
||||
{
|
||||
if (request.wLength == 0)
|
||||
|
@ -388,6 +407,12 @@ namespace Kernel
|
|||
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());
|
||||
|
||||
{
|
||||
|
@ -410,32 +435,23 @@ namespace Kernel
|
|||
advance_endpoint_enqueue(endpoint, false);
|
||||
}
|
||||
|
||||
const uint32_t td_packet_count = BAN::Math::div_round_up<uint32_t>(request.wLength, endpoint.max_packet_size);
|
||||
uint32_t packets_transferred = 1;
|
||||
|
||||
uint32_t bytes_handled = 0;
|
||||
while (bytes_handled < request.wLength)
|
||||
if (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];
|
||||
memset(const_cast<XHCI::TRB*>(&trb), 0, sizeof(XHCI::TRB));
|
||||
|
||||
trb.data_stage.trb_type = XHCI::TRBType::DataStage;
|
||||
trb.data_stage.direction = 1;
|
||||
trb.data_stage.trb_transfer_length = to_handle;
|
||||
trb.data_stage.td_size = BAN::Math::min<uint32_t>(td_packet_count - packets_transferred, 31);
|
||||
trb.data_stage.chain_bit = (bytes_handled + to_handle < request.wLength);
|
||||
trb.data_stage.direction = !!(request.bmRequestType & USB::RequestType::DeviceToHost);
|
||||
trb.data_stage.trb_transfer_length = request.wLength;
|
||||
trb.data_stage.td_size = 0;
|
||||
trb.data_stage.chain_bit = 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.data_buffer_pointer = buffer_paddr + bytes_handled;
|
||||
trb.data_stage.data_buffer_pointer = buffer_paddr;
|
||||
trb.data_stage.cycle_bit = endpoint.cycle_bit;
|
||||
|
||||
bytes_handled += to_handle;
|
||||
packets_transferred++;
|
||||
|
||||
advance_endpoint_enqueue(endpoint, trb.data_stage.chain_bit);
|
||||
advance_endpoint_enqueue(endpoint, false);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -443,10 +459,10 @@ namespace Kernel
|
|||
memset(const_cast<XHCI::TRB*>(&trb), 0, sizeof(XHCI::TRB));
|
||||
|
||||
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.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);
|
||||
}
|
||||
|
@ -459,7 +475,7 @@ namespace Kernel
|
|||
|
||||
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;
|
||||
while ((__atomic_load_n(&completion_trb.raw.dword2, __ATOMIC_SEQ_CST) >> 24) == 0)
|
||||
|
@ -482,7 +498,7 @@ namespace Kernel
|
|||
ASSERT(endpoint_id != 0);
|
||||
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));
|
||||
memset(const_cast<XHCI::TRB*>(&trb), 0, sizeof(XHCI::TRB));
|
||||
|
@ -496,7 +512,7 @@ namespace Kernel
|
|||
trb.normal.interrupt_on_short_packet = 1;
|
||||
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)
|
||||
|
|
|
@ -228,11 +228,13 @@ static void init2(void*)
|
|||
dprintln("USBManager initialized");
|
||||
}
|
||||
|
||||
if (!cmdline.disable_acpi && ACPI::ACPI::get().enter_acpi_mode(InterruptController::get().is_using_apic()).is_error())
|
||||
dprintln("Failed to enter ACPI mode");
|
||||
|
||||
if (!cmdline.disable_acpi)
|
||||
{
|
||||
if (auto ret = ACPI::ACPI::get().enter_acpi_mode(InterruptController::get().is_using_apic()); ret.is_error())
|
||||
dprintln("Failed to enter ACPI mode: {}", 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();
|
||||
|
||||
|
|
Loading…
Reference in New Issue