Compare commits

..

12 Commits

Author SHA1 Message Date
Bananymous baa4e6475a Kernel: Implement basic USB Mouse
This has the same problem I described in previous commit for keyboard
2024-07-14 02:11:32 +03:00
Bananymous ac5c77ee2c Kernel: Implement USB Keyboard
This is kinda hacky, as I had disable the PS/2 initialization so that
usb keyboard gets /dev/keyboard0. I should add device hot plugging
support for TTY and GUI...
2024-07-14 02:09:18 +03:00
Bananymous 1efc6a1385 Kernel: Implement simple USB HID driver
This should be easily expandable to add HID devices
2024-07-14 02:04:48 +03:00
Bananymous 442ea8a692 BAN: Remove Optional emplace constructor
This was kind breaking some initializations. Emplacing is still possible
through Optional::emplace
2024-07-14 01:53:50 +03:00
Bananymous 749be67df3 Kernel: Fix cxxabi for function static variable guards 2024-07-14 01:53:50 +03:00
Bananymous a97a574718 Kernel: Rewrite the whole input system
PS/2 code is now kind of messed up, but it works. Keyboards and mice are
now an abstract class that is automatically exposed to userspace. This
will make adding USB input much nicer.
2024-07-14 01:53:50 +03:00
Bananymous 110a45bee6 BAN: Implement Variant::has_value() and Variant::operator bool() 2024-07-12 20:37:56 +03:00
Bananymous f120da3aca Kernel: USB device now sets the current configuration 2024-07-12 11:26:06 +03:00
Bananymous 240684bc1f Kernel: Refactor some xHCI code and add new definitions 2024-07-12 11:25:24 +03:00
Bananymous 62003d96f3 BAN: Implement Optional::value_or
This will return value specified in the argument if optional is not
storing any value.
2024-07-12 11:22:10 +03:00
Bananymous e905634343 Kernel: Fix bugs and cleanup USB and xHCI code and API 2024-07-11 14:10:55 +03:00
Bananymous 14dce1abac Kernel: Start work on USB stack
Current code can enumerate all xHCI devices and detect their type based
on the class code on device or interface descriptors.
2024-07-10 12:06:00 +03:00
41 changed files with 3919 additions and 199 deletions

View File

@ -18,8 +18,6 @@ namespace BAN
constexpr Optional(const Optional&);
constexpr Optional(const T&);
constexpr Optional(T&&);
template<typename... Args>
constexpr Optional(Args&&...);
~Optional();
@ -40,6 +38,8 @@ namespace BAN
constexpr T release_value();
constexpr T& value();
constexpr const T& value() const;
constexpr T& value_or(T&);
constexpr const T& value_or(const T&) const;
constexpr void clear();
@ -83,14 +83,6 @@ namespace BAN
new (m_storage) T(move(value));
}
template<typename T>
template<typename... Args>
constexpr Optional<T>::Optional(Args&&... args)
: m_has_value(true)
{
new (m_storage) T(forward<Args>(args)...);
}
template<typename T>
Optional<T>::~Optional()
{
@ -112,7 +104,7 @@ namespace BAN
{
clear();
m_has_value = other.has_value();
if (other.has_value)
if (other.has_value())
new (m_storage) T(other.value());
return *this;
}
@ -185,6 +177,22 @@ namespace BAN
return (const T&)m_storage;
}
template<typename T>
constexpr T& Optional<T>::value_or(T& empty)
{
if (!has_value())
return empty;
return (T&)m_storage;
}
template<typename T>
constexpr const T& Optional<T>::value_or(const T& empty) const
{
if (!has_value())
return empty;
return (const T&)m_storage;
}
template<typename T>
constexpr void Optional<T>::clear()
{

View File

@ -286,6 +286,16 @@ namespace BAN
return **reinterpret_cast<const remove_reference_t<T>**>(m_storage);
}
bool has_value() const
{
return m_index != invalid_index();
}
explicit operator bool() const
{
return has_value();
}
void clear()
{
if (m_index != invalid_index())

View File

@ -34,6 +34,7 @@ set(KERNEL_SOURCES
kernel/FS/VirtualFileSystem.cpp
kernel/GDT.cpp
kernel/IDT.cpp
kernel/Input/InputDevice.cpp
kernel/Input/PS2/Controller.cpp
kernel/Input/PS2/Device.cpp
kernel/Input/PS2/Keyboard.cpp
@ -93,6 +94,13 @@ set(KERNEL_SOURCES
kernel/Timer/PIT.cpp
kernel/Timer/RTC.cpp
kernel/Timer/Timer.cpp
kernel/USB/Device.cpp
kernel/USB/HID/HIDDriver.cpp
kernel/USB/HID/Keyboard.cpp
kernel/USB/HID/Mouse.cpp
kernel/USB/USBManager.cpp
kernel/USB/XHCI/Controller.cpp
kernel/USB/XHCI/Device.cpp
icxxabi.cpp
)
@ -169,7 +177,8 @@ target_compile_definitions(kernel PUBLIC __arch=${BANAN_ARCH})
target_compile_options(kernel PUBLIC -O2 -g)
target_compile_options(kernel PUBLIC $<$<COMPILE_LANGUAGE:CXX>:-Wno-literal-suffix -fno-rtti -fno-exceptions>)
target_compile_options(kernel PUBLIC -fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}=.)
target_compile_options(kernel PUBLIC -fstack-protector -ffreestanding -Wall -Wextra -Werror -Wstack-usage=1024 -fno-omit-frame-pointer -mgeneral-regs-only)
target_compile_options(kernel PUBLIC -fstack-protector -ffreestanding -fno-omit-frame-pointer -fstrict-volatile-bitfields -mgeneral-regs-only)
target_compile_options(kernel PUBLIC -Wall -Wextra -Werror -Wstack-usage=1024)
# This might not work with other toolchains
target_compile_options(kernel PUBLIC $<$<COMPILE_LANGUAGE:CXX>:-Wno-invalid-offsetof>)

View File

@ -42,20 +42,20 @@ namespace __cxxabiv1
{
using __guard = uint64_t;
int __cxa_guard_acquire (__guard* g)
extern "C" int __cxa_guard_acquire (__guard* g)
{
uint8_t* byte = reinterpret_cast<uint8_t*>(g);
uint8_t zero = 0;
return __atomic_compare_exchange_n(byte, &zero, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
}
void __cxa_guard_release (__guard* g)
extern "C" void __cxa_guard_release (__guard* g)
{
uint8_t* byte = reinterpret_cast<uint8_t*>(g);
__atomic_store_n(byte, 0, __ATOMIC_RELEASE);
}
void __cxa_guard_abort (__guard*)
extern "C" void __cxa_guard_abort (__guard*)
{
Kernel::panic("__cxa_guard_abort");
}

View File

@ -13,7 +13,8 @@ namespace Kernel
Null,
Zero,
Debug,
Input,
Keyboard,
Mouse,
SCSI,
NVMeController,
NVMeNamespace,

View File

@ -20,8 +20,6 @@ namespace Kernel
void add_device(BAN::RefPtr<Device>);
void add_inode(BAN::StringView path, BAN::RefPtr<TmpInode>);
int get_next_input_device() const;
void initiate_sync(bool should_block);
private:

View File

@ -0,0 +1,50 @@
#pragma once
#include <BAN/ByteSpan.h>
#include <kernel/Device/Device.h>
namespace Kernel
{
class InputDevice : public CharacterDevice
{
public:
enum class Type
{
Mouse,
Keyboard,
};
public:
InputDevice(Type type);
protected:
void add_event(BAN::ConstByteSpan);
BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
bool can_read_impl() const override { SpinLockGuard _(m_event_lock); return m_event_count > 0; }
bool can_write_impl() const override { return false; }
bool has_error_impl() const override { return false; }
virtual BAN::StringView name() const final override { return m_name; }
virtual dev_t rdev() const final override { return m_rdev; }
private:
const dev_t m_rdev;
const BAN::String m_name;
mutable SpinLock m_event_lock;
Semaphore m_event_semaphore;
static constexpr size_t m_max_event_count { 128 };
BAN::Vector<uint8_t> m_event_buffer;
const size_t m_event_size;
size_t m_event_tail { 0 };
size_t m_event_head { 0 };
size_t m_event_count { 0 };
};
}

View File

@ -60,6 +60,7 @@ namespace Kernel::Input
private:
BAN::RefPtr<PS2Device> m_devices[2];
Mutex m_mutex;
BAN::CircularQueue<Command, 128> m_command_queue;

View File

@ -1,16 +1,15 @@
#pragma once
#include <kernel/Input/PS2/Controller.h>
#include <kernel/Input/InputDevice.h>
#include <kernel/Interruptable.h>
namespace Kernel::Input
{
class PS2Device : public CharacterDevice, public Interruptable
class PS2Device : public Interruptable, public InputDevice
{
public:
virtual ~PS2Device() {}
virtual void send_initialize() = 0;
virtual void command_timedout(uint8_t* command_data, uint8_t command_size) = 0;
@ -21,17 +20,10 @@ namespace Kernel::Input
virtual void handle_byte(uint8_t) = 0;
virtual BAN::StringView name() const final override { return m_name; }
virtual dev_t rdev() const final override { return m_rdev; }
virtual void update() final override { m_controller.update_command_queue(); }
protected:
PS2Device(PS2Controller&, InputDevice::Type type);
protected:
PS2Device(PS2Controller&);
private:
const dev_t m_rdev;
const BAN::String m_name;
PS2Controller& m_controller;
};

View File

@ -1,11 +1,8 @@
#pragma once
#include <BAN/Array.h>
#include <BAN/CircularQueue.h>
#include <kernel/Input/PS2/Device.h>
#include <kernel/Input/PS2/Keymap.h>
#include <kernel/Semaphore.h>
#include <LibInput/KeyEvent.h>
namespace Kernel::Input
{
@ -20,13 +17,15 @@ namespace Kernel::Input
};
public:
static BAN::ErrorOr<PS2Keyboard*> create(PS2Controller&);
static BAN::ErrorOr<BAN::RefPtr<PS2Keyboard>> create(PS2Controller&);
virtual void send_initialize() override;
virtual void command_timedout(uint8_t* command_data, uint8_t command_size) final override;
virtual void handle_byte(uint8_t) final override;
virtual void update() final override { m_controller.update_command_queue(); }
private:
PS2Keyboard(PS2Controller& controller);
@ -37,22 +36,11 @@ namespace Kernel::Input
uint8_t m_byte_index { 0 };
uint8_t m_scancode_set { 0xFF };
uint16_t m_modifiers { 0 };
BAN::CircularQueue<LibInput::RawKeyEvent, 50> m_event_queue;
SpinLock m_event_lock;
PS2Keymap m_keymap;
Semaphore m_semaphore;
protected:
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
virtual bool can_read_impl() const override { return !m_event_queue.empty(); }
virtual bool can_write_impl() const override { return false; }
virtual bool has_error_impl() const override { return false; }
friend class BAN::RefPtr<PS2Keyboard>;
};
}

View File

@ -1,8 +1,6 @@
#pragma once
#include <kernel/Input/PS2/Device.h>
#include <kernel/Semaphore.h>
#include <LibInput/MouseEvent.h>
namespace Kernel::Input
{
@ -16,13 +14,15 @@ namespace Kernel::Input
};
public:
static BAN::ErrorOr<PS2Mouse*> create(PS2Controller&);
static BAN::ErrorOr<BAN::RefPtr<PS2Mouse>> create(PS2Controller&);
virtual void send_initialize() override;
virtual void command_timedout(uint8_t* command_data, uint8_t command_size) final override { (void)command_data; (void)command_size; }
virtual void handle_byte(uint8_t) final override;
virtual void update() final override { m_controller.update_command_queue(); }
private:
PS2Mouse(PS2Controller& controller);
@ -36,17 +36,7 @@ namespace Kernel::Input
uint8_t m_mouse_id { 0x00 };
uint8_t m_button_mask { 0x00 };
BAN::CircularQueue<LibInput::MouseEvent, 128> m_event_queue;
SpinLock m_event_lock;
Semaphore m_semaphore;
protected:
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
virtual bool can_read_impl() const override { return !m_event_queue.empty(); }
virtual bool can_write_impl() const override { return false; }
virtual bool has_error_impl() const override { return false; }
friend class BAN::RefPtr<PS2Mouse>;
};
}

View File

@ -0,0 +1,10 @@
#pragma once
namespace Kernel
{
class USBController
{
};
}

View File

@ -0,0 +1,167 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
namespace Kernel
{
namespace USB
{
enum class SpeedClass
{
None,
LowSpeed,
FullSpeed,
HighSpeed,
SuperSpeed,
};
enum class DeviceBaseClass : uint8_t
{
CommunicationAndCDCControl = 0x02,
Hub = 0x09,
BillboardDeviceClass = 0x11,
DiagnosticDevice = 0xDC,
Miscellaneous = 0xEF,
VendorSpecific = 0xFF,
};
enum class InterfaceBaseClass : uint8_t
{
Audio = 0x01,
CommunicationAndCDCControl = 0x02,
HID = 0x03,
Physical = 0x05,
Image = 0x06,
Printer = 0x07,
MassStorage = 0x08,
CDCData = 0x0A,
SmartCard = 0x0B,
ContentSecurity = 0x0D,
Video = 0x0E,
PersonalHealthcare = 0x0F,
AudioVideoDevice = 0x10,
USBTypeCBridgeClass = 0x12,
USBBulkDisplayProtocolDeviceClass = 0x13,
MCTPOverUSBProtocolEndpointDeviceClass = 0x14,
I3CDeviceClass = 0x3C,
DiagnosticDevice = 0xDC,
WirelessController = 0xE0,
Miscellaneous = 0xEF,
ApplicationSpecific = 0xFE,
VendorSpecific = 0xFF,
};
enum DescriptorType : uint8_t
{
DEVICE = 1,
CONFIGURATION = 2,
STRING = 3,
INTERFACE = 4,
ENDPOINT = 5,
DEVICE_QUALIFIER = 6,
OTHER_SPEED_CONFIGURATION = 7,
INTERFACE_POWER = 8,
};
enum RequestType : uint8_t
{
HostToDevice = 0b0 << 7,
DeviceToHost = 0b1 << 7,
Standard = 0b00 << 5,
Class = 0b01 << 5,
Vendor = 0b10 << 5,
Device = 0b00000,
Interface = 0b00001,
Endpoint = 0b00010,
Other = 0b00011,
};
enum Request : uint8_t
{
GET_STATUS = 0,
CLEAR_FEATURE = 1,
SET_FEATURE = 3,
SET_ADDRESS = 5,
GET_DESCRIPTOR = 6,
SET_DESCRIPTOR = 7,
GET_CONFIGURATION = 8,
SET_CONFIGURATION = 9,
GET_INTERFACE = 10,
SET_INTERFACE = 11,
SYNC_FRAME = 12,
};
}
struct USBDeviceDescriptor
{
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdUSB;
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize0;
uint16_t idVendor;
uint16_t idProduct;
uint16_t bcdDevice;
uint8_t iManufacturer;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
};
static_assert(sizeof(USBDeviceDescriptor) == 18);
struct USBConfigurationDescriptor
{
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wTotalLength __attribute__((packed));
uint8_t bNumInterfaces;
uint8_t bConfigurationValue;
uint8_t iConfiguration;
uint8_t bmAttributes;
uint8_t bMaxPower;
};
static_assert(sizeof(USBConfigurationDescriptor) == 9);
static constexpr size_t foo = sizeof(USBConfigurationDescriptor);
struct USBInterfaceDescriptor
{
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bInterfaceNumber;
uint8_t bAlternateSetting;
uint8_t bNumEndpoints;
uint8_t bInterfaceClass;
uint8_t bInterfaceSubClass;
uint8_t bInterfaceProtocol;
uint8_t iInterface;
};
static_assert(sizeof(USBInterfaceDescriptor) == 9);
struct USBEndpointDescriptor
{
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bEndpointAddress;
uint8_t bmAttributes;
uint16_t wMaxPacketSize __attribute__((packed));
uint8_t bInterval;
};
static_assert(sizeof(USBEndpointDescriptor) == 7);
struct USBDeviceRequest
{
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
};
static_assert(sizeof(USBDeviceRequest) == 8);
}

View File

@ -0,0 +1,83 @@
#pragma once
#include <BAN/ByteSpan.h>
#include <BAN/NoCopyMove.h>
#include <kernel/Memory/DMARegion.h>
#include <kernel/USB/USBManager.h>
#include <kernel/USB/Controller.h>
namespace Kernel
{
class USBClassDriver
{
BAN_NON_COPYABLE(USBClassDriver);
BAN_NON_MOVABLE(USBClassDriver);
public:
USBClassDriver() = default;
virtual ~USBClassDriver() = default;
virtual void handle_input_data(BAN::ConstByteSpan, uint8_t endpoint_id) = 0;
};
class USBDevice
{
BAN_NON_COPYABLE(USBDevice);
BAN_NON_MOVABLE(USBDevice);
public:
struct EndpointDescriptor
{
USBEndpointDescriptor descriptor;
};
struct InterfaceDescriptor
{
USBInterfaceDescriptor descriptor;
BAN::Vector<EndpointDescriptor> endpoints;
BAN::Vector<BAN::Vector<uint8_t>> misc_descriptors;
};
struct ConfigurationDescriptor
{
USBConfigurationDescriptor desciptor;
BAN::Vector<InterfaceDescriptor> interfaces;
};
struct DeviceDescriptor
{
USBDeviceDescriptor descriptor;
BAN::Vector<ConfigurationDescriptor> configurations;
};
public:
USBDevice() = default;
virtual ~USBDevice() = default;
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<size_t> send_request(const USBDeviceRequest&, paddr_t buffer) = 0;
static USB::SpeedClass determine_speed_class(uint64_t bits_per_second);
protected:
void handle_input_data(BAN::ConstByteSpan, uint8_t endpoint_id);
virtual BAN::ErrorOr<void> initialize_control_endpoint() = 0;
private:
BAN::ErrorOr<ConfigurationDescriptor> parse_configuration(size_t index);
private:
DeviceDescriptor m_descriptor;
BAN::UniqPtr<DMARegion> m_dma_buffer;
// FIXME: support more than one interface from a configuration
BAN::UniqPtr<USBClassDriver> m_class_driver;
};
}

View File

@ -0,0 +1,94 @@
#pragma once
#include <kernel/Input/InputDevice.h>
#include <kernel/USB/Device.h>
namespace Kernel
{
namespace USBHID
{
struct Report
{
enum class Type { Input, Output, Feature };
uint16_t usage_page;
uint16_t usage_id;
Type type;
uint32_t report_count;
uint32_t report_size;
uint32_t usage_minimum;
uint32_t usage_maximum;
int64_t logical_minimum;
int64_t logical_maximum;
int64_t physical_minimum;
int64_t physical_maximum;
uint8_t flags;
};
struct Collection
{
uint16_t usage_page;
uint16_t usage_id;
uint8_t type;
BAN::Vector<BAN::Variant<Collection, Report>> entries;
};
}
class USBHIDDevice : public InputDevice
{
BAN_NON_COPYABLE(USBHIDDevice);
BAN_NON_MOVABLE(USBHIDDevice);
public:
USBHIDDevice(InputDevice::Type type)
: InputDevice(type)
{}
virtual ~USBHIDDevice() = default;
virtual void start_report() = 0;
virtual void stop_report() = 0;
virtual void handle_variable(uint16_t usage_page, uint16_t usage, int64_t state) = 0;
virtual void handle_array(uint16_t usage_page, uint16_t usage) = 0;
};
class USBHIDDriver final : public USBClassDriver
{
BAN_NON_COPYABLE(USBHIDDriver);
BAN_NON_MOVABLE(USBHIDDriver);
public:
static BAN::ErrorOr<BAN::UniqPtr<USBHIDDriver>> create(USBDevice&, const USBDevice::InterfaceDescriptor&, uint8_t interface_index);
void handle_input_data(BAN::ConstByteSpan, uint8_t endpoint_id) override;
private:
USBHIDDriver(USBDevice&, const USBDevice::InterfaceDescriptor&, uint8_t interface_index);
~USBHIDDriver();
BAN::ErrorOr<void> initialize();
void forward_collection_inputs(const USBHID::Collection&, BAN::ConstByteSpan& data, size_t bit_offset);
private:
USBDevice& m_device;
USBDevice::InterfaceDescriptor m_interface;
const uint8_t m_interface_index;
uint8_t m_endpoint_id { 0 };
USBHID::Collection m_collection;
BAN::RefPtr<USBHIDDevice> m_hid_device;
friend class BAN::UniqPtr<USBHIDDriver>;
};
}

View File

@ -0,0 +1,34 @@
#pragma once
#include <kernel/USB/HID/HIDDriver.h>
namespace Kernel
{
class USBKeyboard final : public USBHIDDevice
{
BAN_NON_COPYABLE(USBKeyboard);
BAN_NON_MOVABLE(USBKeyboard);
public:
void start_report() override;
void stop_report() override;
void handle_variable(uint16_t usage_page, uint16_t usage, int64_t state) override;
void handle_array(uint16_t usage_page, uint16_t usage) override;
private:
USBKeyboard()
: USBHIDDevice(InputDevice::Type::Keyboard)
{}
~USBKeyboard() = default;
private:
BAN::Array<bool, 0x100> m_keyboard_state { false };
BAN::Array<bool, 0x100> m_keyboard_state_temp { false };
uint8_t m_toggle_mask { 0 };
friend class BAN::RefPtr<USBKeyboard>;
};
}

View File

@ -0,0 +1,36 @@
#pragma once
#include <kernel/USB/HID/HIDDriver.h>
namespace Kernel
{
class USBMouse final : public USBHIDDevice
{
BAN_NON_COPYABLE(USBMouse);
BAN_NON_MOVABLE(USBMouse);
public:
void start_report() override;
void stop_report() override;
void handle_variable(uint16_t usage_page, uint16_t usage, int64_t state) override;
void handle_array(uint16_t usage_page, uint16_t usage) override;
private:
USBMouse()
: USBHIDDevice(InputDevice::Type::Mouse)
{}
~USBMouse() = default;
private:
BAN::Array<bool, 5> m_button_state { false };
BAN::Array<bool, 5> m_button_state_temp { false };
int64_t m_pointer_x { 0 };
int64_t m_pointer_y { 0 };
int64_t m_wheel { 0 };
friend class BAN::RefPtr<USBMouse>;
};
}

View File

@ -0,0 +1,30 @@
#pragma once
#include <kernel/PCI.h>
#include <kernel/USB/Controller.h>
#include <kernel/USB/Definitions.h>
namespace Kernel
{
class USBManager
{
BAN_NON_COPYABLE(USBManager);
BAN_NON_MOVABLE(USBManager);
public:
static BAN::ErrorOr<void> initialize();
static USBManager& get();
BAN::ErrorOr<void> add_controller(PCI::Device& pci_device);
private:
USBManager() = default;
private:
BAN::Vector<BAN::UniqPtr<USBController>> m_controllers;
friend class BAN::UniqPtr<USBManager>;
};
}

View File

@ -0,0 +1,105 @@
#pragma once
#include <BAN/Vector.h>
#include <kernel/Lock/Mutex.h>
#include <kernel/Memory/DMARegion.h>
#include <kernel/USB/USBManager.h>
#include <kernel/USB/XHCI/Definitions.h>
namespace Kernel
{
class XHCIDevice;
class XHCIController : public USBController, public Interruptable
{
BAN_NON_COPYABLE(XHCIController);
BAN_NON_MOVABLE(XHCIController);
public:
struct Port
{
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:
static BAN::ErrorOr<BAN::UniqPtr<XHCIController>> initialize(PCI::Device&);
void handle_irq() final override;
private:
XHCIController(PCI::Device& pci_device);
~XHCIController();
BAN::ErrorOr<void> initialize_impl();
BAN::ErrorOr<void> initialize_ports();
BAN::ErrorOr<void> initialize_primary_interrupter();
BAN::ErrorOr<void> reset_controller();
void port_updater_task();
BAN::ErrorOr<void> initialize_slot(int port_index);
BAN::ErrorOr<XHCI::TRB> send_command(const XHCI::TRB&);
void advance_command_enqueue();
bool context_size_set() { return capability_regs().hccparams1.context_size; }
const Port& port(uint32_t port_id) const { return m_ports[port_id - 1]; }
volatile XHCI::CapabilityRegs& capability_regs();
volatile XHCI::OperationalRegs& operational_regs();
volatile XHCI::RuntimeRegs& runtime_regs();
volatile uint32_t& doorbell_reg(uint32_t slot_id);
volatile uint64_t& dcbaa_reg(uint32_t slot_id);
const volatile XHCI::TRB& current_event_trb();
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 };
Semaphore m_port_semaphore;
BAN::Atomic<bool> m_port_changed { false };
PCI::Device& m_pci_device;
BAN::UniqPtr<PCI::BarRegion> m_configuration_bar;
BAN::UniqPtr<DMARegion> m_dcbaa_region;
BAN::UniqPtr<DMARegion> m_command_ring_region;
uint32_t m_command_enqueue { 0 };
bool m_command_cycle { 1 };
BAN::UniqPtr<DMARegion> m_event_ring_region;
uint32_t m_event_dequeue { 0 };
bool m_event_cycle { 1 };
BAN::Vector<XHCI::TRB> m_command_completions;
BAN::Vector<Port> m_ports;
BAN::Vector<BAN::UniqPtr<XHCIDevice>> m_slots;
friend class XHCIDevice;
friend class BAN::UniqPtr<XHCIController>;
};
}

View File

@ -0,0 +1,626 @@
#pragma once
#include <stdint.h>
namespace Kernel::XHCI
{
struct CapabilityRegs
{
uint32_t caplength : 8;
uint32_t : 8;
uint32_t minor_revision : 8;
uint32_t major_revision : 8;
union
{
uint32_t hcsparams1_raw;
struct
{
uint32_t max_slots : 8;
uint32_t max_interrupters : 11;
uint32_t : 5;
uint32_t max_ports : 8;
} hcsparams1;
};
union
{
uint32_t hcsparams2_raw;
struct
{
uint32_t isochronous_scheduling_threshold : 4;
uint32_t event_ring_segment_table_max : 4;
uint32_t : 13;
uint32_t max_scratchpad_buffers_hi : 5;
uint32_t scratchpad_restore : 1;
uint32_t max_scratchpad_buffers_lo : 5;
} hcsparams2;
};
union
{
uint32_t hcsparams3_raw;
struct
{
uint32_t u1_device_exit_latency : 8;
uint32_t : 8;
uint32_t u2_device_exit_latency : 16;
} hcsparams3;
};
union
{
uint32_t hccparams1_raw;
struct
{
uint32_t addressing_capability64 : 1;
uint32_t bw_negotation_capability : 1;
uint32_t context_size : 1;
uint32_t port_power_control : 1;
uint32_t port_indicators : 1;
uint32_t light_hc_reset_capability : 1;
uint32_t latency_tolerance_messaging_capability : 1;
uint32_t no_secondary_sid_support : 1;
uint32_t parse_all_event_data : 1;
uint32_t stopped_short_packet_capability : 1;
uint32_t stopped_edtla_capability : 1;
uint32_t contiguous_frame_id_capability : 1;
uint32_t maximum_primary_stream_array_size : 4;
uint32_t xhci_extended_capabilities_pointer : 16;
} hccparams1;
};
uint32_t dboff;
uint32_t rstoff;
union
{
uint32_t hccparams2_raw;
struct
{
uint32_t u3_entry_capability : 1;
uint32_t configure_endpoint_command_max_latency_too_large_capability : 1;
uint32_t force_save_context_capability : 1;
uint32_t compliance_transition_capability : 1;
uint32_t large_esit_payload_capability : 1;
uint32_t configuration_information_capability : 1;
uint32_t extended_tbc_capability : 1;
uint32_t extended_tbc_trb_status_capability : 1;
uint32_t get_set_extended_property_capability : 1;
uint32_t virtualiaztion_based_trusted_io_capability : 1;
uint32_t : 22;
} hccparams2;
};
};
static_assert(sizeof(CapabilityRegs) == 0x20);
struct PortRegs
{
uint32_t portsc;
uint32_t portmsc;
uint32_t portli;
uint32_t porthlpmc;
};
static_assert(sizeof(PortRegs) == 0x10);
struct OperationalRegs
{
union
{
uint32_t usbcmd_raw;
struct
{
uint32_t run_stop : 1;
uint32_t host_controller_reset : 1;
uint32_t interrupter_enable : 1;
uint32_t host_system_error_enable : 1;
uint32_t : 3;
uint32_t light_host_controller_reset : 1;
uint32_t controller_save_state : 1;
uint32_t controller_restore_state : 1;
uint32_t enable_wrap_event : 1;
uint32_t enable_u3_mfindex_stop : 1;
uint32_t : 1;
uint32_t cem_enable : 1;
uint32_t extended_tbc_enable : 1;
uint32_t extended_tbc_trb_status_enable : 1;
uint32_t vtio_enable : 1;
uint32_t : 15;
} usbcmd;
};
uint32_t usbsts;
uint32_t pagesize;
uint32_t __reserved0[2];
uint32_t dnctrl;
uint32_t crcr_lo;
uint32_t crcr_hi;
uint32_t __reserved1[4];
uint32_t dcbaap_lo;
uint32_t dcbaap_hi;
union
{
uint32_t config_raw;
struct
{
uint32_t max_device_slots_enabled : 8;
uint32_t u3_entry_enable : 1;
uint32_t configuration_information_enable : 1;
uint32_t : 22;
} config;
};
uint32_t __reserved2[241];
PortRegs ports[];
};
static_assert(sizeof(OperationalRegs) == 0x400);
struct InterrupterRegs
{
uint32_t iman;
uint32_t imod;
uint32_t erstsz;
uint32_t __reserved;
uint64_t erstba;
uint64_t erdp;
};
static_assert(sizeof(InterrupterRegs) == 0x20);
struct RuntimeRegs
{
uint32_t mfindex;
uint32_t __reserved[7];
InterrupterRegs irs[];
};
static_assert(sizeof(RuntimeRegs) == 0x20);
struct TRB
{
union
{
struct
{
uint64_t parameter;
uint32_t status;
uint16_t cycle : 1;
uint16_t ent : 1;
uint16_t : 8;
uint16_t trb_type : 6;
uint16_t control;
};
struct
{
uint32_t dword0;
uint32_t dword1;
uint32_t dword2;
uint32_t dword3;
} raw;
struct
{
uint64_t data_buffer_pointer : 64;
uint32_t trb_transfer_length : 17;
uint32_t td_size : 5;
uint32_t interrupt_target : 10;
uint32_t cycle_bit : 1;
uint32_t evaluate_next_trb : 1;
uint32_t interrupt_on_short_packet : 1;
uint32_t no_snoop : 1;
uint32_t chain_bit : 1;
uint32_t interrupt_on_completion : 1;
uint32_t immediate_data : 1;
uint32_t : 2;
uint32_t block_event_interrupt : 1;
uint32_t trb_type : 6;
uint32_t : 16;
} normal;
struct
{
uint32_t bmRequestType : 8;
uint32_t bRequest : 8;
uint32_t wValue : 16;
uint32_t wIndex : 16;
uint32_t wLength : 16;
uint32_t trb_transfer_length : 17;
uint32_t : 5;
uint32_t interrupt_target : 10;
uint32_t cycle_bit : 1;
uint32_t : 4;
uint32_t interrupt_on_completion : 1;
uint32_t immediate_data : 1;
uint32_t : 3;
uint32_t trb_type : 6;
uint32_t transfer_type : 2;
uint32_t : 14;
} setup_stage;
struct
{
uint64_t data_buffer_pointer : 64;
uint32_t trb_transfer_length : 17;
uint32_t td_size : 5;
uint32_t interrupt_target : 10;
uint32_t cycle_bit : 1;
uint32_t evaluate_next_trb : 1;
uint32_t interrupt_on_short_packet : 1;
uint32_t no_snoop : 1;
uint32_t chain_bit : 1;
uint32_t interrupt_on_completion : 1;
uint32_t immediate_data : 1;
uint32_t : 3;
uint32_t trb_type : 6;
uint32_t direction : 1;
uint32_t : 15;
} data_stage;
struct
{
uint32_t : 32;
uint32_t : 32;
uint32_t : 22;
uint32_t interrupter_target : 10;
uint32_t cycle_bit : 1;
uint32_t evaluate_next_trb : 1;
uint32_t : 2;
uint32_t chain_bit : 1;
uint32_t interrupt_on_completion : 1;
uint32_t : 4;
uint32_t trb_type : 6;
uint32_t direction : 1;
uint32_t : 15;
} status_stage;
struct
{
uint64_t trb_pointer : 64;
uint32_t trb_transfer_length : 24;
uint32_t completion_code : 8;
uint32_t cycle_bit : 1;
uint32_t : 1;
uint32_t event_data : 1;
uint32_t : 7;
uint32_t trb_type : 6;
uint32_t endpoint_id : 5;
uint32_t : 3;
uint32_t slot_id : 8;
} transfer_event;
struct
{
uint64_t command_trb_pointer : 64;
uint32_t command_completion_parameter : 24;
uint32_t completion_code : 8;
uint32_t cycle_bit : 1;
uint32_t : 9;
uint32_t trb_type : 6;
uint32_t vf_id : 8;
uint32_t slot_id : 8;
} command_completion_event;
struct
{
uint32_t : 24;
uint32_t port_id : 8;
uint32_t : 32;
uint32_t : 24;
uint32_t completion_code : 8;
uint32_t cycle : 1;
uint32_t : 9;
uint32_t trb_type : 6;
uint32_t : 16;
} port_status_chage_event;
struct
{
uint32_t : 32;
uint32_t : 32;
uint32_t : 32;
uint32_t cycle : 1;
uint32_t : 9;
uint32_t trb_type : 6;
uint32_t slot_type : 5;
uint32_t : 11;
} enable_slot_command;
struct
{
uint32_t : 32;
uint32_t : 32;
uint32_t : 32;
uint32_t cycle : 1;
uint32_t : 9;
uint32_t trb_type : 6;
uint32_t : 8;
uint32_t slot_id : 8;
} disable_slot_command;
struct
{
uint64_t input_context_pointer : 64;
uint32_t : 32;
uint32_t cycle_bit : 1;
uint32_t : 8;
uint32_t block_set_address_request : 1;
uint32_t trb_type : 6;
uint32_t : 8;
uint32_t slot_id : 8;
} address_device_command;
struct
{
uint64_t input_context_pointer : 64;
uint32_t : 32;
uint32_t cycle_bit : 1;
uint32_t : 8;
uint32_t deconfigure : 1;
uint32_t trb_type : 6;
uint32_t : 8;
uint32_t slot_id : 8;
} configure_endpoint_command;
struct
{
uint64_t ring_segment_ponter : 64;
uint32_t : 22;
uint32_t interrupter_target : 10;
uint32_t cycle_bit : 1;
uint32_t toggle_cycle : 1;
uint32_t : 2;
uint32_t chain_bit : 1;
uint32_t interrupt_on_completion : 1;
uint32_t : 4;
uint32_t trb_type : 6;
uint32_t : 16;
} link_trb;
};
};
static_assert(sizeof(TRB) == 0x10);
struct EventRingTableEntry
{
uint64_t rsba;
uint32_t rsz;
uint32_t __reserved;
};
static_assert(sizeof(EventRingTableEntry) == 0x10);
struct ExtendedCap
{
uint32_t capability_id : 8;
uint32_t next_capability : 8;
uint32_t : 16;
};
static_assert(sizeof(ExtendedCap) == 4);
struct SupportedPrococolCap
{
uint32_t capability_id : 8;
uint32_t next_capability : 8;
uint32_t minor_revision : 8;
uint32_t major_revision : 8;
uint32_t name_string : 32;
uint32_t compatible_port_offset : 8;
uint32_t compatible_port_count : 8;
uint32_t protocol_defied : 12;
uint32_t protocol_speed_id_count : 4;
uint32_t protocol_slot_type : 5;
uint32_t : 27;
};
static_assert(sizeof(SupportedPrococolCap) == 0x10);
struct SlotContext
{
uint32_t route_string : 20;
uint32_t speed : 4;
uint32_t : 1;
uint32_t multi_tt : 1;
uint32_t hub : 1;
uint32_t context_entries : 5;
uint16_t max_exit_latency;
uint8_t root_hub_port_number;
uint8_t number_of_ports;
uint32_t parent_hub_slot_id : 8;
uint32_t parent_port_number : 8;
uint32_t tt_think_time : 2;
uint32_t : 4;
uint32_t interrupter_target : 10;
uint32_t usb_device_address : 8;
uint32_t : 19;
uint32_t slot_state : 5;
uint32_t : 32;
uint32_t : 32;
uint32_t : 32;
uint32_t : 32;
};
static_assert(sizeof(SlotContext) == 0x20);
struct EndpointContext
{
uint32_t endpoint_state : 3;
uint32_t : 5;
uint32_t mult : 2;
uint32_t max_primary_streams : 5;
uint32_t linear_stream_array : 1;
uint32_t interval : 8;
uint32_t max_esit_payload_hi : 8;
uint32_t : 1;
uint32_t error_count : 2;
uint32_t endpoint_type : 3;
uint32_t : 1;
uint32_t host_initiate_disable : 1;
uint32_t max_burst_size : 8;
uint32_t max_packet_size : 16;
// LSB is dequeue cycle state
uint64_t tr_dequeue_pointer;
uint32_t average_trb_length : 16;
uint32_t max_esit_payload_lo : 16;
uint32_t : 32;
uint32_t : 32;
uint32_t : 32;
};
static_assert(sizeof(EndpointContext) == 0x20);
struct InputControlContext
{
uint32_t drop_context_flags;
uint32_t add_context_flags;
uint32_t : 32;
uint32_t : 32;
uint32_t : 32;
uint32_t : 32;
uint32_t : 32;
uint8_t configuration_value;
uint8_t interface_number;
uint8_t alternate_setting;
uint8_t : 8;
};
static_assert(sizeof(InputControlContext) == 0x20);
enum USBSTS
{
HCHalted = 1 << 0,
HostSystemError = 1 << 2,
EventInterrupt = 1 << 3,
PortChangeDetect = 1 << 4,
SaveStateStatus = 1 << 8,
RstoreStateStatus = 1 << 9,
SaveRestoreError = 1 << 10,
ControllerNotReady = 1 << 11,
HostControllerError = 1 << 12,
};
enum CRCR : uint32_t
{
RingCycleState = 1 << 0,
CommandStop = 1 << 1,
CommandAbort = 1 << 2,
CommandRingRunning = 1 << 3,
};
enum IMAN : uint32_t
{
InterruptPending = 1 << 0,
InterruptEnable = 1 << 1,
};
enum ERDP
{
EventHandlerBusy = 1 << 3,
};
enum PORTSC : uint32_t
{
CCS = 1u << 0,
PED = 1u << 1,
OCA = 1u << 3,
PR = 1u << 4,
PP = 1u << 9,
LWS = 1u << 16,
CSC = 1u << 17,
PEC = 1u << 18,
WRC = 1u << 19,
OCC = 1u << 20,
PRC = 1u << 21,
PLC = 1u << 22,
CEC = 1u << 23,
CAS = 1u << 24,
WCE = 1u << 25,
WDE = 1u << 26,
WOE = 1u << 27,
DR = 1u << 30,
WPR = 1u << 31,
PLS_SHIFT = 5,
PLS_MASK = 0xF,
PORT_SPEED_SHIFT = 10,
PORT_SPEED_MASK = 0xF,
PIC_SHIFT = 14,
PIC_MASK = 0x3,
};
enum ExtendedCapabilityID : uint8_t
{
USBLegacySupport = 1,
SupportedProtocol = 2,
ExtendedPowerManagement = 3,
IOVirtualization = 4,
MessageInterrupt = 5,
LocalMemory = 6,
USBDebugCapability = 10,
ExtendedMessageInterrupt = 17,
};
enum TRBType
{
Normal = 1,
SetupStage = 2,
DataStage = 3,
StatusStage = 4,
Link = 6,
EnableSlotCommand = 9,
DisableSlotCommand = 10,
AddressDeviceCommand = 11,
ConfigureEndpointCommand = 12,
EvaluateContextCommand = 13,
ResetEndpointCommand = 14,
StopEndpointCommand = 15,
SetTRDequeuePointerCommand = 16,
ResetDeviceCommand = 17,
ForceEventCommand = 18,
NegotiateBandwidthCommand = 19,
SetLatencyToleranceValueCommand = 20,
GetPortBandwidthCommand = 21,
ForceHeaderCommand = 22,
NoOpCommand = 23,
GetExtendedPropertyCommand = 24,
SetExtendedPropertyCommand = 25,
TransferEvent = 32,
CommandCompletionEvent = 33,
PortStatusChangeEvent = 34,
BandwidthRequestEvent = 35,
DoorbellEvent = 36,
HostControllerEvent = 37,
DeviceNotificationEvent = 38,
MFINDEXWrapEvent = 39,
};
enum EndpointType
{
IsochOut = 1,
BulkOut = 2,
InterruptOut = 3,
Control = 4,
IsochIn = 5,
BulkIn = 6,
InterruptIn = 7,
};
}

View File

@ -0,0 +1,75 @@
#pragma once
#include <BAN/Array.h>
#include <BAN/RefPtr.h>
#include <kernel/USB/Device.h>
#include <kernel/USB/XHCI/Controller.h>
namespace Kernel
{
class XHCIDevice final : public USBDevice
{
BAN_NON_COPYABLE(XHCIDevice);
BAN_NON_MOVABLE(XHCIDevice);
public:
struct Endpoint
{
BAN::UniqPtr<DMARegion> transfer_ring;
uint32_t max_packet_size { 0 };
uint32_t dequeue_index { 0 };
uint32_t enqueue_index { 0 };
bool cycle_bit { 1 };
Mutex mutex;
volatile uint32_t transfer_count { 0 };
volatile XHCI::TRB completion_trb;
BAN::UniqPtr<DMARegion> data_region;
void(XHCIDevice::*callback)(XHCI::TRB);
};
public:
static BAN::ErrorOr<BAN::UniqPtr<XHCIDevice>> create(XHCIController&, uint32_t port_id, uint32_t slot_id);
BAN::ErrorOr<void> initialize_endpoint(const USBEndpointDescriptor&) override;
BAN::ErrorOr<size_t> send_request(const USBDeviceRequest&, paddr_t buffer) override;
void on_transfer_event(const volatile XHCI::TRB&);
protected:
BAN::ErrorOr<void> initialize_control_endpoint() override;
private:
XHCIDevice(XHCIController& controller, uint32_t port_id, uint32_t slot_id)
: m_controller(controller)
, m_port_id(port_id)
, m_slot_id(slot_id)
{}
~XHCIDevice();
BAN::ErrorOr<void> update_actual_max_packet_size();
void on_interrupt_endpoint_event(XHCI::TRB);
void advance_endpoint_enqueue(Endpoint&, bool chain);
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;
Mutex m_mutex;
BAN::UniqPtr<DMARegion> m_input_context;
BAN::UniqPtr<DMARegion> m_output_context;
BAN::Array<Endpoint, 31> m_endpoints;
friend class BAN::UniqPtr<XHCIDevice>;
};
}

View File

@ -119,10 +119,4 @@ namespace Kernel
MUST(static_cast<TmpDirectoryInode*>(root_inode().ptr())->link_inode(*inode, path));
}
int DevFileSystem::get_next_input_device() const
{
static BAN::Atomic<dev_t> next_dev = 0;
return next_dev++;
}
}

View File

@ -0,0 +1,104 @@
#include <kernel/Device/DeviceNumbers.h>
#include <kernel/Input/InputDevice.h>
#include <kernel/Lock/LockGuard.h>
#include <LibInput/KeyEvent.h>
#include <LibInput/MouseEvent.h>
#include <sys/sysmacros.h>
namespace Kernel
{
static BAN::Atomic<uint16_t> s_next_keyboard { 0 };
static BAN::Atomic<uint16_t> s_next_mouse { 0 };
static const char* get_name_format(InputDevice::Type type)
{
switch (type)
{
case InputDevice::Type::Keyboard:
return "keyboard{}";
case InputDevice::Type::Mouse:
return "mouse{}";
}
ASSERT_NOT_REACHED();
}
static dev_t get_rdev(InputDevice::Type type)
{
switch (type)
{
case InputDevice::Type::Keyboard:
return makedev(DeviceNumber::Keyboard, s_next_keyboard++);
case InputDevice::Type::Mouse:
return makedev(DeviceNumber::Mouse, s_next_mouse++);
}
ASSERT_NOT_REACHED();
}
static size_t get_event_size(InputDevice::Type type)
{
switch (type)
{
case InputDevice::Type::Keyboard:
return sizeof(LibInput::RawKeyEvent);
case InputDevice::Type::Mouse:
return sizeof(LibInput::MouseEvent);
}
ASSERT_NOT_REACHED();
}
InputDevice::InputDevice(Type type)
: CharacterDevice(0440, 0, 901)
, m_rdev(get_rdev(type))
, m_name(MUST(BAN::String::formatted(get_name_format(type), minor(m_rdev))))
, m_event_size(get_event_size(type))
{
MUST(m_event_buffer.resize(m_event_size * m_max_event_count, 0));
}
void InputDevice::add_event(BAN::ConstByteSpan event)
{
SpinLockGuard _(m_event_lock);
ASSERT(event.size() == m_event_size);
if (m_event_count == m_max_event_count)
{
m_event_tail = (m_event_tail + 1) % m_max_event_count;
m_event_count--;
}
memcpy(&m_event_buffer[m_event_head * m_event_size], event.data(), m_event_size);
m_event_head = (m_event_head + 1) % m_max_event_count;
m_event_count++;
m_event_semaphore.unblock();
}
BAN::ErrorOr<size_t> InputDevice::read_impl(off_t, BAN::ByteSpan buffer)
{
if (buffer.size() < m_event_size)
return BAN::Error::from_errno(ENOBUFS);
auto state = m_event_lock.lock();
while (m_event_count == 0)
{
m_event_lock.unlock(state);
{
LockFreeGuard _(m_mutex);
TRY(Thread::current().block_or_eintr_indefinite(m_event_semaphore));
}
state = m_event_lock.lock();
}
memcpy(buffer.data(), &m_event_buffer[m_event_tail * m_event_size], m_event_size);
m_event_tail = (m_event_tail + 1) % m_max_event_count;
m_event_count--;
m_event_lock.unlock(state);
return m_event_size;
}
}

View File

@ -89,9 +89,9 @@ namespace Kernel::Input
uint8_t PS2Controller::get_device_index(PS2Device* device) const
{
ASSERT(device);
if (m_devices[0] && device == m_devices[0].ptr())
if (m_devices[0].ptr() == device)
return 0;
if (m_devices[1] && device == m_devices[1].ptr())
if (m_devices[1].ptr() == device)
return 1;
ASSERT_NOT_REACHED();
}
@ -359,12 +359,12 @@ namespace Kernel::Input
TRY(send_command(PS2::Command::WRITE_CONFIG, config));
// Send device initialization sequence after interrupts are enabled
for (uint8_t device = 0; device < 2; device++)
for (uint8_t i = 0; i < 2; i++)
{
if (!m_devices[device])
if (!m_devices[i])
continue;
m_devices[device]->send_initialize();
DevFileSystem::get().add_device(m_devices[device]);
m_devices[i]->send_initialize();
DevFileSystem::get().add_device(m_devices[i]);
}
return {};

View File

@ -1,18 +1,13 @@
#include <kernel/Device/DeviceNumbers.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Input/PS2/Config.h>
#include <kernel/Input/PS2/Device.h>
#include <kernel/IO.h>
#include <sys/sysmacros.h>
namespace Kernel::Input
{
PS2Device::PS2Device(PS2Controller& controller)
: CharacterDevice(0440, 0, 901)
, m_rdev(makedev(DeviceNumber::Input, DevFileSystem::get().get_next_input_device()))
, m_name(MUST(BAN::String::formatted("input{}", minor(m_rdev))))
PS2Device::PS2Device(PS2Controller& controller, InputDevice::Type type)
: InputDevice(type)
, m_controller(controller)
{ }

View File

@ -4,20 +4,18 @@
#include <kernel/Input/PS2/Keyboard.h>
#include <kernel/Thread.h>
#include <LibInput/KeyboardLayout.h>
#include <LibInput/KeyEvent.h>
namespace Kernel::Input
{
BAN::ErrorOr<PS2Keyboard*> PS2Keyboard::create(PS2Controller& controller)
BAN::ErrorOr<BAN::RefPtr<PS2Keyboard>> PS2Keyboard::create(PS2Controller& controller)
{
PS2Keyboard* keyboard = new PS2Keyboard(controller);
if (keyboard == nullptr)
return BAN::Error::from_errno(ENOMEM);
return keyboard;
return TRY(BAN::RefPtr<PS2Keyboard>::create(controller));
}
PS2Keyboard::PS2Keyboard(PS2Controller& controller)
: PS2Device(controller)
: PS2Device(controller, InputDevice::Type::Keyboard)
{ }
void PS2Keyboard::send_initialize()
@ -166,17 +164,7 @@ namespace Kernel::Input
RawKeyEvent event;
event.modifier = m_modifiers | (released ? 0 : KeyModifier::Pressed);
event.keycode = keycode.value();
SpinLockGuard _(m_event_lock);
if (m_event_queue.full())
{
dwarnln("PS/2 event queue full");
m_event_queue.pop();
}
m_event_queue.push(event);
m_semaphore.unblock();
add_event(BAN::ConstByteSpan::from(event));
}
void PS2Keyboard::update_leds()
@ -193,30 +181,4 @@ namespace Kernel::Input
append_command_queue(Command::SET_LEDS, new_leds, 0);
}
BAN::ErrorOr<size_t> PS2Keyboard::read_impl(off_t, BAN::ByteSpan buffer)
{
using LibInput::RawKeyEvent;
if (buffer.size() < sizeof(RawKeyEvent))
return BAN::Error::from_errno(ENOBUFS);
auto state = m_event_lock.lock();
while (m_event_queue.empty())
{
m_event_lock.unlock(state);
{
LockFreeGuard _(m_mutex);
TRY(Thread::current().block_or_eintr_indefinite(m_semaphore));
}
state = m_event_lock.lock();
}
buffer.as<RawKeyEvent>() = m_event_queue.front();
m_event_queue.pop();
m_event_lock.unlock(state);
return sizeof(RawKeyEvent);
}
}

View File

@ -3,6 +3,7 @@
#include <kernel/Input/PS2/Config.h>
#include <kernel/Input/PS2/Mouse.h>
#include <kernel/Thread.h>
#include <LibInput/MouseEvent.h>
#define SET_MASK(byte, mask, on_off) ((on_off) ? ((byte) | (mask)) : ((byte) & ~(mask)))
#define TOGGLE_MASK(byte, mask) ((byte) ^ (mask))
@ -10,16 +11,13 @@
namespace Kernel::Input
{
BAN::ErrorOr<PS2Mouse*> PS2Mouse::create(PS2Controller& controller)
BAN::ErrorOr<BAN::RefPtr<PS2Mouse>> PS2Mouse::create(PS2Controller& controller)
{
PS2Mouse* mouse = new PS2Mouse(controller);
if (mouse == nullptr)
return BAN::Error::from_errno(ENOMEM);
return mouse;
return TRY(BAN::RefPtr<PS2Mouse>::create(controller));
}
PS2Mouse::PS2Mouse(PS2Controller& controller)
: PS2Device(controller)
: PS2Device(controller, InputDevice::Type::Mouse)
{ }
void PS2Mouse::send_initialize()
@ -110,10 +108,6 @@ namespace Kernel::Input
m_byte_index = 0;
// Max 7 events, one for each (5) button, one for movement, one for scroll
BAN::Array<MouseEvent, 7> events;
int event_count = 0;
auto button_index_to_button =
[](int index) -> MouseButton
{
@ -137,10 +131,11 @@ namespace Kernel::Input
if ((new_button_mask & (1 << i)) == (m_button_mask & (1 << i)))
continue;
auto& event = events[event_count++];
MouseEvent event;
event.type = MouseEventType::MouseButtonEvent;
event.button_event.button = button_index_to_button(i);
event.button_event.pressed = !!(new_button_mask & (1 << i));
add_event(BAN::ConstByteSpan::from(event));
}
m_button_mask = new_button_mask;
@ -148,71 +143,20 @@ namespace Kernel::Input
if (rel_x || rel_y)
{
auto& event = events[event_count++];
MouseEvent event;
event.type = MouseEventType::MouseMoveEvent;
event.move_event.rel_x = rel_x;
event.move_event.rel_y = rel_y;
add_event(BAN::ConstByteSpan::from(event));
}
if (rel_z)
{
auto& event = events[event_count++];
MouseEvent event;
event.type = MouseEventType::MouseScrollEvent;
event.scroll_event.scroll = rel_z;
add_event(BAN::ConstByteSpan::from(event));
}
SpinLockGuard _(m_event_lock);
for (int i = 0; i < event_count; i++)
{
if (!m_event_queue.empty() && m_event_queue.back().type == events[i].type)
{
if (events[i].type == MouseEventType::MouseMoveEvent)
{
m_event_queue.back().move_event.rel_x += events[i].move_event.rel_x;
m_event_queue.back().move_event.rel_y += events[i].move_event.rel_y;
continue;
}
if (events[i].type == MouseEventType::MouseScrollEvent)
{
m_event_queue.back().scroll_event.scroll += events[i].scroll_event.scroll;
continue;
}
}
if (m_event_queue.full())
{
dwarnln("PS/2 event queue full");
m_event_queue.pop();
}
m_event_queue.push(events[i]);
}
m_semaphore.unblock();
}
BAN::ErrorOr<size_t> PS2Mouse::read_impl(off_t, BAN::ByteSpan buffer)
{
using LibInput::MouseEvent;
if (buffer.size() < sizeof(MouseEvent))
return BAN::Error::from_errno(ENOBUFS);
auto state = m_event_lock.lock();
while (m_event_queue.empty())
{
m_event_lock.unlock(state);
TRY(Thread::current().block_or_eintr_indefinite(m_semaphore));
state = m_event_lock.lock();
}
buffer.as<MouseEvent>() = m_event_queue.front();
m_event_queue.pop();
m_event_lock.unlock(state);
return sizeof(MouseEvent);
}
}

View File

@ -8,6 +8,7 @@
#include <kernel/Storage/ATA/AHCI/Controller.h>
#include <kernel/Storage/ATA/ATAController.h>
#include <kernel/Storage/NVMe/Controller.h>
#include <kernel/USB/USBManager.h>
#define INVALID_VENDOR 0xFFFF
#define MULTI_FUNCTION 0x80
@ -209,6 +210,20 @@ namespace Kernel::PCI
dprintln("{}", res.error());
break;
}
case 0x0C:
{
switch (pci_device.subclass())
{
case 0x03:
if (auto res = USBManager::get().add_controller(pci_device); res.is_error())
dprintln("{}", res.error());
break;
default:
dprintln("unsupported serail bus controller (pci {2H}.{2H}.{2H})", pci_device.class_code(), pci_device.subclass(), pci_device.prog_if());
break;
}
break;
}
default:
break;
}

View File

@ -83,7 +83,7 @@ namespace Kernel
Process::create_kernel(
[](void*)
{
auto file_or_error = VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, "/dev/input0"_sv, O_RDONLY);
auto file_or_error = VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, "/dev/keyboard0"_sv, O_RDONLY);
if (file_or_error.is_error())
{
dprintln("no input device found");

View File

@ -0,0 +1,327 @@
#include <kernel/Memory/DMARegion.h>
#include <kernel/USB/Device.h>
#include <kernel/USB/HID/HIDDriver.h>
#define DEBUG_USB 0
#define USB_DUMP_DESCRIPTORS 0
namespace Kernel
{
BAN::ErrorOr<void> USBDevice::initialize()
{
TRY(initialize_control_endpoint());
m_dma_buffer = TRY(DMARegion::create(1024));
USBDeviceRequest request;
request.bmRequestType = USB::RequestType::DeviceToHost | USB::RequestType::Standard | USB::RequestType::Device;
request.bRequest = USB::Request::GET_DESCRIPTOR;
request.wValue = 0x0100;
request.wIndex = 0;
request.wLength = sizeof(USBDeviceDescriptor);
auto transferred = TRY(send_request(request, m_dma_buffer->paddr()));
m_descriptor.descriptor = *reinterpret_cast<const USBDeviceDescriptor*>(m_dma_buffer->vaddr());
if (transferred < sizeof(USBDeviceDescriptor) || transferred < m_descriptor.descriptor.bLength)
{
dprintln("invalid device descriptor response {}");
return BAN::Error::from_errno(EINVAL);
}
dprintln_if(DEBUG_USB, "device has {} configurations", m_descriptor.descriptor.bNumConfigurations);
for (uint32_t i = 0; i < m_descriptor.descriptor.bNumConfigurations; i++)
if (auto opt_configuration = parse_configuration(i); !opt_configuration.is_error())
TRY(m_descriptor.configurations.push_back(opt_configuration.release_value()));
#if USB_DUMP_DESCRIPTORS
const auto& descriptor = m_descriptor.descriptor;
dprintln("device descriptor");
dprintln(" bLength: {}", descriptor.bLength);
dprintln(" bDescriptorType: {}", descriptor.bDescriptorType);
dprintln(" bcdUSB: {}", descriptor.bcdUSB);
dprintln(" bDeviceClass: {}", descriptor.bDeviceClass);
dprintln(" bDeviceSubClass: {}", descriptor.bDeviceSubClass);
dprintln(" bDeviceProtocol: {}", descriptor.bDeviceProtocol);
dprintln(" bMaxPacketSize0: {}", descriptor.bMaxPacketSize0);
dprintln(" idVendor: {}", descriptor.idVendor);
dprintln(" idProduct: {}", descriptor.idProduct);
dprintln(" bcdDevice: {}", descriptor.bcdDevice);
dprintln(" iManufacturer: {}", descriptor.iManufacturer);
dprintln(" iProduct: {}", descriptor.iProduct);
dprintln(" iSerialNumber: {}", descriptor.iSerialNumber);
dprintln(" bNumConfigurations: {}", descriptor.bNumConfigurations);
for (const auto& configuration : m_descriptor.configurations)
{
const auto& descriptor = configuration.desciptor;
dprintln(" configuration");
dprintln(" bLength: {}", descriptor.bLength);
dprintln(" bDescriptorType: {}", descriptor.bDescriptorType);
dprintln(" wTotalLength: {}", descriptor.wTotalLength);
dprintln(" bNumInterfaces: {}", descriptor.bNumInterfaces);
dprintln(" bConfigurationValue: {}", descriptor.bConfigurationValue);
dprintln(" iConfiguration: {}", descriptor.iConfiguration);
dprintln(" bmAttributes: {}", descriptor.bmAttributes);
dprintln(" bMaxPower: {}", descriptor.bMaxPower);
for (const auto& interface : configuration.interfaces)
{
const auto& descriptor = interface.descriptor;
dprintln(" interface");
dprintln(" bLength: {}", descriptor.bLength);
dprintln(" bDescriptorType: {}", descriptor.bDescriptorType);
dprintln(" bInterfaceNumber: {}", descriptor.bInterfaceNumber);
dprintln(" bAlternateSetting: {}", descriptor.bAlternateSetting);
dprintln(" bNumEndpoints: {}", descriptor.bNumEndpoints);
dprintln(" bInterfaceClass: {}", descriptor.bInterfaceClass);
dprintln(" bInterfaceSubClass: {}", descriptor.bInterfaceSubClass);
dprintln(" bInterfaceProtocol: {}", descriptor.bInterfaceProtocol);
dprintln(" iInterface: {}", descriptor.iInterface);
for (const auto& endpoint : interface.endpoints)
{
const auto& descriptor = endpoint.descriptor;
dprintln(" endpoint");
dprintln(" bLength: {}", descriptor.bLength);
dprintln(" bDescriptorType: {}", descriptor.bDescriptorType);
dprintln(" bEndpointAddress: {}", descriptor.bEndpointAddress);
dprintln(" bmAttributes: {}", descriptor.bmAttributes);
dprintln(" wMaxPacketSize: {}", +descriptor.wMaxPacketSize);
dprintln(" bInterval: {}", descriptor.bInterval);
}
}
}
#endif
if (m_descriptor.descriptor.bDeviceClass)
{
switch (static_cast<USB::DeviceBaseClass>(m_descriptor.descriptor.bDeviceClass))
{
case USB::DeviceBaseClass::CommunicationAndCDCControl:
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);
case USB::DeviceBaseClass::BillboardDeviceClass:
dprintln_if(DEBUG_USB, "Found BillboardDeviceClass device");
return BAN::Error::from_errno(ENOTSUP);
case USB::DeviceBaseClass::DiagnosticDevice:
dprintln_if(DEBUG_USB, "Found DiagnosticDevice device");
return BAN::Error::from_errno(ENOTSUP);
case USB::DeviceBaseClass::Miscellaneous:
dprintln_if(DEBUG_USB, "Found Miscellaneous device");
return BAN::Error::from_errno(ENOTSUP);
case USB::DeviceBaseClass::VendorSpecific:
dprintln_if(DEBUG_USB, "Found VendorSpecific device");
return BAN::Error::from_errno(ENOTSUP);
default:
dprintln_if(DEBUG_USB, "Invalid device base class {2H}", m_descriptor.descriptor.bDeviceClass);
return BAN::Error::from_errno(EFAULT);
}
ASSERT_NOT_REACHED();
}
for (size_t i = 0; i < m_descriptor.configurations.size(); i++)
{
const auto& configuration = m_descriptor.configurations[i];
{
dprintln_if(DEBUG_USB, "Setting configuration 0x{2H}", configuration.desciptor.bConfigurationValue);
USBDeviceRequest request;
request.bmRequestType = USB::RequestType::HostToDevice | USB::RequestType::Standard | USB::RequestType::Device;
request.bRequest = USB::Request::SET_CONFIGURATION;
request.wValue = configuration.desciptor.bConfigurationValue;
request.wIndex = 0;
request.wLength = 0;
TRY(send_request(request, 0));
}
for (size_t j = 0; j < configuration.interfaces.size(); j++)
{
const auto& interface = configuration.interfaces[j];
switch (static_cast<USB::InterfaceBaseClass>(interface.descriptor.bInterfaceClass))
{
case USB::InterfaceBaseClass::Audio:
dprintln_if(DEBUG_USB, "Found Audio interface");
break;
case USB::InterfaceBaseClass::CommunicationAndCDCControl:
dprintln_if(DEBUG_USB, "Found CommunicationAndCDCControl interface");
break;
case USB::InterfaceBaseClass::HID:
if (auto result = USBHIDDriver::create(*this, interface, j); !result.is_error())
m_class_driver = result.release_value();
break;
case USB::InterfaceBaseClass::Physical:
dprintln_if(DEBUG_USB, "Found Physical interface");
break;
case USB::InterfaceBaseClass::Image:
dprintln_if(DEBUG_USB, "Found Image interface");
break;
case USB::InterfaceBaseClass::Printer:
dprintln_if(DEBUG_USB, "Found Printer interface");
break;
case USB::InterfaceBaseClass::MassStorage:
dprintln_if(DEBUG_USB, "Found MassStorage interface");
break;
case USB::InterfaceBaseClass::CDCData:
dprintln_if(DEBUG_USB, "Found CDCData interface");
break;
case USB::InterfaceBaseClass::SmartCard:
dprintln_if(DEBUG_USB, "Found SmartCard interface");
break;
case USB::InterfaceBaseClass::ContentSecurity:
dprintln_if(DEBUG_USB, "Found ContentSecurity interface");
break;
case USB::InterfaceBaseClass::Video:
dprintln_if(DEBUG_USB, "Found Video interface");
break;
case USB::InterfaceBaseClass::PersonalHealthcare:
dprintln_if(DEBUG_USB, "Found PersonalHealthcare interface");
break;
case USB::InterfaceBaseClass::AudioVideoDevice:
dprintln_if(DEBUG_USB, "Found AudioVideoDevice interface");
break;
case USB::InterfaceBaseClass::USBTypeCBridgeClass:
dprintln_if(DEBUG_USB, "Found USBTypeCBridgeClass interface");
break;
case USB::InterfaceBaseClass::USBBulkDisplayProtocolDeviceClass:
dprintln_if(DEBUG_USB, "Found USBBulkDisplayProtocolDeviceClass interface");
break;
case USB::InterfaceBaseClass::MCTPOverUSBProtocolEndpointDeviceClass:
dprintln_if(DEBUG_USB, "Found MCTPOverUSBProtocolEndpointDeviceClass interface");
break;
case USB::InterfaceBaseClass::I3CDeviceClass:
dprintln_if(DEBUG_USB, "Found I3CDeviceClass interface");
break;
case USB::InterfaceBaseClass::DiagnosticDevice:
dprintln_if(DEBUG_USB, "Found DiagnosticDevice interface");
break;
case USB::InterfaceBaseClass::WirelessController:
dprintln_if(DEBUG_USB, "Found WirelessController interface");
break;
case USB::InterfaceBaseClass::Miscellaneous:
dprintln_if(DEBUG_USB, "Found Miscellaneous interface");
break;
case USB::InterfaceBaseClass::ApplicationSpecific:
dprintln_if(DEBUG_USB, "Found ApplicationSpecific interface");
break;
case USB::InterfaceBaseClass::VendorSpecific:
dprintln_if(DEBUG_USB, "Found VendorSpecific interface");
break;
default:
dprintln_if(DEBUG_USB, "Invalid interface base class {2H}", interface.descriptor.bInterfaceClass);
break;
}
if (m_class_driver)
{
dprintln("Successfully initialized USB interface");
return {};
}
}
}
return BAN::Error::from_errno(ENOTSUP);
}
BAN::ErrorOr<USBDevice::ConfigurationDescriptor> USBDevice::parse_configuration(size_t index)
{
{
USBDeviceRequest request;
request.bmRequestType = USB::RequestType::DeviceToHost | USB::RequestType::Standard | USB::RequestType::Device;
request.bRequest = USB::Request::GET_DESCRIPTOR;
request.wValue = 0x0200 | index;
request.wIndex = 0;
request.wLength = m_dma_buffer->size();
auto transferred = TRY(send_request(request, m_dma_buffer->paddr()));
auto configuration = *reinterpret_cast<const USBConfigurationDescriptor*>(m_dma_buffer->vaddr());
dprintln_if(DEBUG_USB, "configuration {} is {} bytes", index, +configuration.wTotalLength);
if (configuration.bLength < sizeof(USBConfigurationDescriptor) || transferred < configuration.wTotalLength)
{
dwarnln("invalid configuration descriptor size: {} length, {} total", configuration.bLength, +configuration.wTotalLength);
return BAN::Error::from_errno(EINVAL);
}
}
ConfigurationDescriptor configuration;
configuration.desciptor = *reinterpret_cast<const USBConfigurationDescriptor*>(m_dma_buffer->vaddr());
ptrdiff_t offset = configuration.desciptor.bLength;
while (offset < configuration.desciptor.wTotalLength)
{
const uint8_t length = *reinterpret_cast<const uint8_t*>(m_dma_buffer->vaddr() + offset + 0);
const uint8_t type = *reinterpret_cast<const uint8_t*>(m_dma_buffer->vaddr() + offset + 1);
switch (type)
{
case USB::DescriptorType::INTERFACE:
if (length < sizeof(USBInterfaceDescriptor))
{
dwarnln("invalid interface descriptor size {}", length);
return BAN::Error::from_errno(EINVAL);
}
TRY(configuration.interfaces.emplace_back(
*reinterpret_cast<const USBInterfaceDescriptor*>(m_dma_buffer->vaddr() + offset),
BAN::Vector<EndpointDescriptor>(),
BAN::Vector<BAN::Vector<uint8_t>>()
));
break;
case USB::DescriptorType::ENDPOINT:
if (length < sizeof(USBEndpointDescriptor))
{
dwarnln("invalid interface descriptor size {}", length);
return BAN::Error::from_errno(EINVAL);
}
if (configuration.interfaces.empty())
{
dwarnln("invalid endpoint descriptor before interface descriptor");
return BAN::Error::from_errno(EINVAL);
}
TRY(configuration.interfaces.back().endpoints.emplace_back(
*reinterpret_cast<const USBEndpointDescriptor*>(m_dma_buffer->vaddr() + offset)
));
break;
default:
if (configuration.interfaces.empty())
dprintln_if(DEBUG_USB, "skipping descriptor type {}", type);
else
{
BAN::Vector<uint8_t> descriptor;
TRY(descriptor.resize(length));
memcpy(descriptor.data(), reinterpret_cast<const void*>(m_dma_buffer->vaddr() + offset), length);
TRY(configuration.interfaces.back().misc_descriptors.push_back(BAN::move(descriptor)));
}
break;
}
offset += length;
}
return BAN::move(configuration);
}
void USBDevice::handle_input_data(BAN::ConstByteSpan data, uint8_t endpoint_id)
{
if (m_class_driver)
m_class_driver->handle_input_data(data, 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

@ -0,0 +1,742 @@
#include <BAN/ByteSpan.h>
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/USB/HID/HIDDriver.h>
#include <kernel/USB/HID/Keyboard.h>
#include <kernel/USB/HID/Mouse.h>
#define DEBUG_HID 0
namespace Kernel
{
enum class HIDDescriptorType : uint8_t
{
HID = 0x21,
Report = 0x22,
Physical = 0x23,
};
struct HIDDescriptor
{
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdHID;
uint8_t bCountryCode;
uint8_t bNumDescriptors;
struct
{
uint8_t bDescriptorType;
uint16_t wItemLength;
} __attribute__((packed)) descriptors[];
} __attribute__((packed));
static_assert(sizeof(HIDDescriptor) == 6);
struct GlobalState
{
BAN::Optional<uint16_t> usage_page;
BAN::Optional<int32_t> logical_minimum;
BAN::Optional<int32_t> logical_maximum_signed;
BAN::Optional<int32_t> logical_maximum_unsigned;
BAN::Optional<int32_t> physical_minimum;
BAN::Optional<int32_t> physical_maximum;
// FIXME: support units
BAN::Optional<uint32_t> report_size;
// FIXME: support report id
BAN::Optional<uint32_t> report_count;
};
struct LocalState
{
BAN::Vector<uint32_t> usage_stack;
BAN::Optional<uint32_t> usage_minimum;
BAN::Optional<uint32_t> usage_maximum;
// FIXME: support all local items
};
using namespace USBHID;
#if DEBUG_HID
static void dump_hid_collection(const Collection& collection, size_t indent);
#endif
static BAN::ErrorOr<Collection> parse_report_descriptor(BAN::ConstByteSpan report_data);
BAN::ErrorOr<BAN::UniqPtr<USBHIDDriver>> USBHIDDriver::create(USBDevice& device, const USBDevice::InterfaceDescriptor& interface, uint8_t interface_index)
{
auto result = TRY(BAN::UniqPtr<USBHIDDriver>::create(device, interface, interface_index));
TRY(result->initialize());
return result;
}
USBHIDDriver::USBHIDDriver(USBDevice& device, const USBDevice::InterfaceDescriptor& interface, uint8_t interface_index)
: m_device(device)
, m_interface(interface)
, m_interface_index(interface_index)
{}
USBHIDDriver::~USBHIDDriver()
{}
BAN::ErrorOr<void> USBHIDDriver::initialize()
{
auto dma_buffer = TRY(DMARegion::create(1024));
ASSERT(static_cast<USB::InterfaceBaseClass>(m_interface.descriptor.bInterfaceClass) == USB::InterfaceBaseClass::HID);
size_t endpoint_index = static_cast<size_t>(-1);
for (size_t i = 0; i < m_interface.endpoints.size(); i++)
{
const auto& endpoint = m_interface.endpoints[i];
if (!(endpoint.descriptor.bEndpointAddress & 0x80))
continue;
if (endpoint.descriptor.bmAttributes != 0x03)
continue;
endpoint_index = i;
break;
}
if (endpoint_index >= m_interface.endpoints.size())
{
dwarnln("HID device does not contain IN interrupt endpoint");
return BAN::Error::from_errno(EFAULT);
}
bool hid_descriptor_invalid = false;
size_t hid_descriptor_index = static_cast<size_t>(-1);
for (size_t i = 0; i < m_interface.misc_descriptors.size(); i++)
{
if (static_cast<HIDDescriptorType>(m_interface.misc_descriptors[i][1]) != HIDDescriptorType::HID)
continue;
if (m_interface.misc_descriptors[i].size() < sizeof(HIDDescriptor))
hid_descriptor_invalid = true;
const auto& hid_descriptor = *reinterpret_cast<const HIDDescriptor*>(m_interface.misc_descriptors[i].data());
if (hid_descriptor.bLength != m_interface.misc_descriptors[i].size())
hid_descriptor_invalid = true;
if (hid_descriptor.bLength != sizeof(HIDDescriptor) + hid_descriptor.bNumDescriptors * 3)
hid_descriptor_invalid = true;
hid_descriptor_index = i;
break;
}
if (hid_descriptor_index >= m_interface.misc_descriptors.size())
{
dwarnln("HID device does not contain HID descriptor");
return BAN::Error::from_errno(EFAULT);
}
if (hid_descriptor_invalid)
{
dwarnln("HID device contains an invalid HID descriptor");
return BAN::Error::from_errno(EFAULT);
}
// If this device supports boot protocol, make sure it is not used
if (m_interface.endpoints.front().descriptor.bDescriptorType & 0x80)
{
USBDeviceRequest request;
request.bmRequestType = USB::RequestType::HostToDevice | USB::RequestType::Class | USB::RequestType::Interface;
request.bRequest = USB::Request::SET_INTERFACE;
request.wValue = 1; // report protocol
request.wIndex = m_interface_index;
request.wLength = 0;
TRY(m_device.send_request(request, 0));
}
Collection collection {};
const auto& hid_descriptor = *reinterpret_cast<const HIDDescriptor*>(m_interface.misc_descriptors[hid_descriptor_index].data());
dprintln_if(DEBUG_HID, "HID descriptor ({} bytes)", m_interface.misc_descriptors[hid_descriptor_index].size());
dprintln_if(DEBUG_HID, " bLength: {}", hid_descriptor.bLength);
dprintln_if(DEBUG_HID, " bDescriptorType: {}", hid_descriptor.bDescriptorType);
dprintln_if(DEBUG_HID, " bcdHID: {H}.{2H}", hid_descriptor.bcdHID >> 8, hid_descriptor.bcdHID & 0xFF);
dprintln_if(DEBUG_HID, " bCountryCode: {}", hid_descriptor.bCountryCode);
dprintln_if(DEBUG_HID, " bNumDescriptors: {}", hid_descriptor.bNumDescriptors);
bool report_descriptor_parsed = false;
for (size_t i = 0; i < hid_descriptor.bNumDescriptors; i++)
{
auto descriptor = hid_descriptor.descriptors[i];
if (static_cast<HIDDescriptorType>(descriptor.bDescriptorType) != HIDDescriptorType::Report)
{
dprintln_if(DEBUG_HID, "Skipping HID descriptor type 0x{2H}", descriptor.bDescriptorType);
continue;
}
if (report_descriptor_parsed)
{
dwarnln("Multiple report descriptors specified");
return BAN::Error::from_errno(ENOTSUP);
}
if (descriptor.wItemLength > dma_buffer->size())
{
dwarnln("Too big report descriptor size {} bytes ({} supported)", +descriptor.wItemLength, dma_buffer->size());
return BAN::Error::from_errno(ENOBUFS);
}
{
USBDeviceRequest request;
request.bmRequestType = USB::RequestType::DeviceToHost | USB::RequestType::Standard | USB::RequestType::Interface;
request.bRequest = USB::Request::GET_DESCRIPTOR;
request.wValue = static_cast<uint16_t>(HIDDescriptorType::Report) << 8;
request.wIndex = m_interface_index;
request.wLength = descriptor.wItemLength;
auto transferred = TRY(m_device.send_request(request, dma_buffer->paddr()));
if (transferred < descriptor.wItemLength)
{
dwarnln("HID device did not respond with full report descriptor");
return BAN::Error::from_errno(EFAULT);
}
}
dprintln_if(DEBUG_HID, "Parsing {} byte report descriptor", +descriptor.wItemLength);
auto report_data = BAN::ConstByteSpan(reinterpret_cast<uint8_t*>(dma_buffer->vaddr()), descriptor.wItemLength);
collection = TRY(parse_report_descriptor(report_data));
report_descriptor_parsed = true;
}
if (!report_descriptor_parsed)
{
dwarnln("No report descriptors specified");
return BAN::Error::from_errno(EFAULT);
}
if (collection.usage_page != 0x01)
{
dwarnln("Top most collection is not generic desktop page");
return BAN::Error::from_errno(EFAULT);
}
#if DEBUG_HID
{
SpinLockGuard _(Debug::s_debug_lock);
dump_hid_collection(collection, 0);
}
#endif
switch (collection.usage_id)
{
case 0x02:
m_hid_device = TRY(BAN::RefPtr<USBMouse>::create());
break;
case 0x06:
m_hid_device = TRY(BAN::RefPtr<USBKeyboard>::create());
break;
default:
dwarnln("Unsupported generic descript page usage 0x{2H}", collection.usage_id);
return BAN::Error::from_errno(ENOTSUP);
}
DevFileSystem::get().add_device(m_hid_device);
const auto& endpoint_descriptor = m_interface.endpoints[endpoint_index].descriptor;
m_endpoint_id = (endpoint_descriptor.bEndpointAddress & 0x0F) * 2 + !!(endpoint_descriptor.bEndpointAddress & 0x80);
m_collection = BAN::move(collection);
TRY(m_device.initialize_endpoint(endpoint_descriptor));
return {};
}
void USBHIDDriver::forward_collection_inputs(const Collection& collection, BAN::ConstByteSpan& data, size_t bit_offset)
{
const auto extract_bits =
[data](size_t bit_offset, size_t bit_count, bool as_unsigned) -> int64_t
{
if (bit_offset >= data.size() * 8)
return 0;
if (bit_count + bit_offset > data.size() * 8)
bit_count = data.size() * 8 - bit_offset;
uint32_t result = 0;
uint32_t result_offset = 0;
while (result_offset < bit_count)
{
const uint32_t byte = bit_offset / 8;
const uint32_t bit = bit_offset % 8;
const uint32_t count = BAN::Math::min<uint32_t>(bit_count - result_offset, 8 - bit);
const uint32_t mask = (1 << count) - 1;
result |= static_cast<uint32_t>((data[byte] >> bit) & mask) << result_offset;
bit_offset += count;
result_offset += count;
}
if (!as_unsigned && (result & (1u << (bit_count - 1))))
{
const uint32_t mask = (1u << bit_count) - 1;
return -(static_cast<int64_t>(~result & mask) + 1);
}
return result;
};
for (const auto& entry : collection.entries)
{
if (entry.has<Collection>())
{
forward_collection_inputs(entry.get<Collection>(), data, bit_offset);
continue;
}
ASSERT(entry.has<Report>());
const auto& input = entry.get<Report>();
if (input.type != Report::Type::Input)
continue;
ASSERT(input.report_size <= 32);
if (input.usage_id == 0 && input.usage_minimum == 0 && input.usage_maximum == 0)
{
bit_offset += input.report_size * input.report_count;
continue;
}
for (uint32_t i = 0; i < input.report_count; i++)
{
const int64_t logical = extract_bits(bit_offset, input.report_size, input.logical_minimum >= 0);
if (logical < input.logical_minimum || logical > input.logical_maximum)
{
bit_offset += input.report_size;
continue;
}
const int64_t physical =
(input.physical_maximum - input.physical_minimum) *
(logical - input.logical_minimum) /
(input.logical_maximum - input.logical_minimum) +
input.physical_minimum;
const uint32_t usage_base = input.usage_id ? input.usage_id : input.usage_minimum;
if (input.flags & 0x02)
m_hid_device->handle_variable(input.usage_page, usage_base + i, physical);
else
m_hid_device->handle_array(input.usage_page, usage_base + physical);
bit_offset += input.report_size;
}
}
}
void USBHIDDriver::handle_input_data(BAN::ConstByteSpan data, uint8_t endpoint_id)
{
ASSERT(m_endpoint_id == endpoint_id);
if constexpr(DEBUG_HID)
{
const auto nibble_to_hex = [](uint8_t x) -> char { return x + (x < 10 ? '0' : 'A' - 10); };
char buffer[512];
char* ptr = buffer;
for (size_t i = 0; i < BAN::Math::min<size_t>((sizeof(buffer) - 1) / 3, data.size()); i++)
{
*ptr++ = nibble_to_hex(data[i] >> 4);
*ptr++ = nibble_to_hex(data[i] & 0xF);
*ptr++ = ' ';
}
*ptr = '\0';
dprintln_if(DEBUG_HID, "Received {} bytes from endpoint {}: {}", data.size(), endpoint_id, buffer);
}
m_hid_device->start_report();
forward_collection_inputs(m_collection, data, 0);
m_hid_device->stop_report();
}
BAN::ErrorOr<Collection> parse_report_descriptor(BAN::ConstByteSpan report_data)
{
BAN::Vector<GlobalState> global_stack;
GlobalState global_state;
LocalState local_state;
BAN::Optional<Collection> result;
BAN::Vector<Collection> collection_stack;
const auto extract_report_item =
[&](bool as_unsigned) -> int64_t
{
uint32_t value = 0;
auto value_data = report_data.slice(1);
switch (report_data[0] & 0x03)
{
case 1: value = as_unsigned ? value_data.as<const uint8_t>() : value_data.as<const int8_t>(); break;
case 2: value = as_unsigned ? value_data.as<const uint16_t>() : value_data.as<const int16_t>(); break;
case 3: value = as_unsigned ? value_data.as<const uint32_t>() : value_data.as<const int32_t>(); break;
}
return value;
};
constexpr auto get_correct_sign =
[](int64_t min, int64_t max_signed, int64_t max_unsigned) -> int64_t
{
if (min < 0 || max_signed >= 0)
return max_signed;
return max_unsigned;
};
const auto add_data_item =
[&](Report::Type type, uint32_t item_data, BAN::Vector<BAN::Variant<Collection, Report>>& container) -> BAN::ErrorOr<void>
{
if (!global_state.report_count.has_value() || !global_state.report_size.has_value())
{
dwarnln("Report count and/or report size is not defined");
return BAN::Error::from_errno(EFAULT);
}
if (!global_state.usage_page.has_value())
{
dwarnln("Usage page is not defined");
return BAN::Error::from_errno(EFAULT);
}
if (!global_state.logical_minimum.has_value() || !global_state.logical_maximum_signed.has_value())
{
dwarnln("Logical minimum and/or logical maximum is not defined");
return BAN::Error::from_errno(EFAULT);
}
if (global_state.physical_minimum.has_value() != global_state.physical_minimum.has_value())
{
dwarnln("Only one of physical minimum and physical maximum is defined");
return BAN::Error::from_errno(EFAULT);
}
if (local_state.usage_minimum.has_value() != local_state.usage_maximum.has_value())
{
dwarnln("Only one of logical minimum and logical maximum is defined");
return BAN::Error::from_errno(EFAULT);
}
const int64_t logical_minimum = global_state.logical_minimum.value();
const int64_t logical_maximum = get_correct_sign(
global_state.logical_minimum.value(),
global_state.logical_maximum_signed.value(),
global_state.logical_maximum_unsigned.value()
);
int64_t physical_minimum = logical_minimum;
int64_t physical_maximum = logical_maximum;
if (global_state.physical_minimum.has_value() && (global_state.physical_minimum.value() || global_state.physical_maximum.value()))
{
physical_minimum = global_state.physical_minimum.value();
physical_maximum = global_state.physical_maximum.value();
}
if (local_state.usage_stack.empty())
{
if (local_state.usage_minimum.has_value() && local_state.usage_maximum.has_value())
{
Report item;
item.usage_page = global_state.usage_page.value();
item.usage_id = 0;
item.usage_minimum = local_state.usage_minimum.value();
item.usage_maximum = local_state.usage_maximum.value();
item.type = type;
item.report_count = global_state.report_count.value();
item.report_size = global_state.report_size.value();
item.logical_minimum = logical_minimum;
item.logical_maximum = logical_maximum;
item.physical_minimum = physical_minimum;
item.physical_maximum = physical_maximum;
item.flags = item_data;
TRY(container.push_back(item));
return {};
}
Report item;
item.usage_page = global_state.usage_page.value();
item.usage_id = 0;
item.usage_minimum = 0;
item.usage_maximum = 0;
item.type = type;
item.report_count = global_state.report_count.value();
item.report_size = global_state.report_size.value();
item.logical_minimum = 0;
item.logical_maximum = 0;
item.physical_minimum = 0;
item.physical_maximum = 0;
item.flags = item_data;
TRY(container.push_back(item));
return {};
}
for (size_t i = 0; i < global_state.report_count.value(); i++)
{
const uint32_t usage = local_state.usage_stack[BAN::Math::min<size_t>(i, local_state.usage_stack.size() - 1)];
Report item;
item.usage_page = (usage >> 16) ? (usage >> 16) : global_state.usage_page.value();
item.usage_id = usage & 0xFFFF;
item.usage_minimum = 0;
item.usage_maximum = 0;
item.type = type;
item.report_count = 1;
item.report_size = global_state.report_size.value();
item.logical_minimum = logical_minimum;
item.logical_maximum = logical_maximum;
item.physical_minimum = physical_minimum;
item.physical_maximum = physical_maximum;
item.flags = item_data;
TRY(container.push_back(item));
}
return {};
};
while (report_data.size() > 0)
{
const uint8_t item_size = report_data[0] & 0x03;
const uint8_t item_type = (report_data[0] >> 2) & 0x03;
const uint8_t item_tag = (report_data[0] >> 4) & 0x0F;
if (item_type == 0)
{
switch (item_tag)
{
case 0b1000: // input
if (collection_stack.empty())
{
dwarnln("Invalid input item outside of collection");
return BAN::Error::from_errno(EFAULT);
}
TRY(add_data_item(Report::Type::Input, extract_report_item(true), collection_stack.back().entries));
break;
case 0b1001: // output
if (collection_stack.empty())
{
dwarnln("Invalid input item outside of collection");
return BAN::Error::from_errno(EFAULT);
}
TRY(add_data_item(Report::Type::Output, extract_report_item(true), collection_stack.back().entries));
break;
case 0b1011: // feature
if (collection_stack.empty())
{
dwarnln("Invalid input item outside of collection");
return BAN::Error::from_errno(EFAULT);
}
TRY(add_data_item(Report::Type::Feature, extract_report_item(true), collection_stack.back().entries));
break;
case 0b1010: // collection
{
if (local_state.usage_stack.size() != 1)
{
dwarnln("{} usages specified for collection", local_state.usage_stack.empty() ? "No" : "Multiple");
return BAN::Error::from_errno(EFAULT);
}
uint16_t usage_page = 0;
if (global_state.usage_page.has_value())
usage_page = global_state.usage_page.value();
if (local_state.usage_stack.front() >> 16)
usage_page = local_state.usage_stack.front() >> 16;
if (usage_page == 0)
{
dwarnln("Usage page not specified for a collection");
return BAN::Error::from_errno(EFAULT);
}
TRY(collection_stack.emplace_back());
collection_stack.back().usage_page = usage_page;
collection_stack.back().usage_id = local_state.usage_stack.front();
break;
}
case 0b1100: // end collection
if (collection_stack.empty())
{
dwarnln("End collection outside of collection");
return BAN::Error::from_errno(EFAULT);
}
if (collection_stack.size() == 1)
{
if (result.has_value())
{
dwarnln("Multiple top-level collections not supported");
return BAN::Error::from_errno(ENOTSUP);
}
result = BAN::move(collection_stack.back());
collection_stack.pop_back();
}
else
{
TRY(collection_stack[collection_stack.size() - 2].entries.push_back(BAN::move(collection_stack.back())));
collection_stack.pop_back();
}
break;
default:
dwarnln("Report has reserved main item tag 0b{4b}", item_tag);
return BAN::Error::from_errno(EFAULT);
}
local_state = LocalState();
}
else if (item_type == 1)
{
switch (item_tag)
{
case 0b0000: // usage page
global_state.usage_page = extract_report_item(true);
break;
case 0b0001: // logical minimum
global_state.logical_minimum = extract_report_item(false);
break;
case 0b0010: // logical maximum
global_state.logical_maximum_signed = extract_report_item(false);
global_state.logical_maximum_unsigned = extract_report_item(true);
break;
case 0b0011: // physical minimum
global_state.physical_minimum = extract_report_item(false);
break;
case 0b0100: // physical maximum
global_state.physical_maximum = extract_report_item(false);
break;
case 0b0101: // unit exponent
dwarnln("Report units are not supported");
return BAN::Error::from_errno(ENOTSUP);
case 0b0110: // unit
dwarnln("Report units are not supported");
return BAN::Error::from_errno(ENOTSUP);
case 0b0111: // report size
global_state.report_size = extract_report_item(true);
break;
case 0b1000: // report id
dwarnln("Report IDs are not supported");
return BAN::Error::from_errno(ENOTSUP);
case 0b1001: // report count
global_state.report_count = extract_report_item(true);
break;
case 0b1010: // push
TRY(global_stack.push_back(global_state));
break;
case 0b1011: // pop
if (global_stack.empty())
{
dwarnln("Report pop from empty stack");
return BAN::Error::from_errno(EFAULT);
}
global_state = global_stack.back();
global_stack.pop_back();
break;
default:
dwarnln("Report has reserved global item tag 0b{4b}", item_tag);
return BAN::Error::from_errno(EFAULT);
}
}
else if (item_type == 2)
{
switch (item_tag)
{
case 0b0000: // usage
TRY(local_state.usage_stack.emplace_back(extract_report_item(true)));
break;
case 0b0001: // usage minimum
local_state.usage_minimum = extract_report_item(true);
break;
case 0b0010: // usage maximum
local_state.usage_maximum = extract_report_item(true);
break;
case 0b0011: // designator index
case 0b0100: // designator minimum
case 0b0101: // designator maximum
case 0b0111: // string index
case 0b1000: // string minimum
case 0b1001: // string maximum
case 0b1010: // delimeter
dwarnln("Unsupported local item tag 0b{4b}", item_tag);
return BAN::Error::from_errno(ENOTSUP);
default:
dwarnln("Report has reserved local item tag 0b{4b}", item_tag);
return BAN::Error::from_errno(EFAULT);
}
}
else
{
dwarnln("Report has reserved item type 0b{2b}", item_type);
return BAN::Error::from_errno(EFAULT);
}
report_data = report_data.slice(1 + item_size);
}
if (!result.has_value())
{
dwarnln("No collection defined in report descriptor");
return BAN::Error::from_errno(EFAULT);
}
return result.release_value();
}
#if DEBUG_HID
static void print_indent(size_t indent)
{
for (size_t i = 0; i < indent; i++)
Debug::putchar(' ');
}
static void dump_hid_report(const Report& report, size_t indent)
{
const char* report_type = "";
switch (report.type)
{
case Report::Type::Input: report_type = "input"; break;
case Report::Type::Output: report_type = "output"; break;
case Report::Type::Feature: report_type = "feature"; break;
}
print_indent(indent);
BAN::Formatter::println(Debug::putchar, "report {}", report_type);
print_indent(indent + 4);
BAN::Formatter::println(Debug::putchar, "usage page: {2H}", report.usage_page);
if (report.usage_id || report.usage_minimum || report.usage_maximum)
{
print_indent(indent + 4);
if (report.usage_id)
BAN::Formatter::println(Debug::putchar, "usage: {2H}", report.usage_id);
else
BAN::Formatter::println(Debug::putchar, "usage: {2H}->{2H}", report.usage_minimum, report.usage_maximum);
}
print_indent(indent + 4);
BAN::Formatter::println(Debug::putchar, "flags: 0b{8b}", report.flags);
print_indent(indent + 4);
BAN::Formatter::println(Debug::putchar, "size: {}", report.report_size);
print_indent(indent + 4);
BAN::Formatter::println(Debug::putchar, "count: {}", report.report_count);
print_indent(indent + 4);
BAN::Formatter::println(Debug::putchar, "lminimum: {}", report.logical_minimum);
print_indent(indent + 4);
BAN::Formatter::println(Debug::putchar, "lmaximum: {}", report.logical_maximum);
print_indent(indent + 4);
BAN::Formatter::println(Debug::putchar, "pminimum: {}", report.physical_minimum);
print_indent(indent + 4);
BAN::Formatter::println(Debug::putchar, "pmaximum: {}", report.physical_maximum);
}
static void dump_hid_collection(const Collection& collection, size_t indent)
{
print_indent(indent);
BAN::Formatter::println(Debug::putchar, "collection {}", collection.type);
print_indent(indent);
BAN::Formatter::println(Debug::putchar, "usage {H}:{H}", collection.usage_page, collection.usage_id);
for (const auto& entry : collection.entries)
{
if (entry.has<Collection>())
dump_hid_collection(entry.get<Collection>(), indent + 4);
if (entry.has<Report>())
dump_hid_report(entry.get<Report>(), indent + 4);
}
}
#endif
}

View File

@ -0,0 +1,212 @@
#include <kernel/USB/HID/Keyboard.h>
#include <LibInput/KeyEvent.h>
#define DEBUG_KEYBOARD 0
namespace Kernel
{
static BAN::Optional<uint8_t> s_scancode_to_keycode[0x100] {};
static bool s_scancode_to_keycode_initialized = false;
static void initialize_scancode_to_keycode();
void USBKeyboard::start_report()
{
for (auto& val : m_keyboard_state_temp)
val = false;
}
void USBKeyboard::stop_report()
{
using KeyModifier = LibInput::KeyEvent::Modifier;
if (!s_scancode_to_keycode_initialized)
initialize_scancode_to_keycode();
// FIXME: RawKeyEvent probably should only contain keycode.
// Modifier should be determined when converting to KeyEvent.
uint8_t modifier = 0;
if (m_keyboard_state_temp[0xE1])
modifier |= KeyModifier::LShift;
if (m_keyboard_state_temp[0xE5])
modifier |= KeyModifier::RShift;
if (m_keyboard_state_temp[0xE0])
modifier |= KeyModifier::LCtrl;
if (m_keyboard_state_temp[0xE4])
modifier |= KeyModifier::RCtrl;
if (m_keyboard_state_temp[0xE2])
modifier |= KeyModifier::LAlt;
if (m_keyboard_state_temp[0xE6])
modifier |= KeyModifier::RAlt;
if (m_keyboard_state_temp[0x39] && !m_keyboard_state[0x39])
m_toggle_mask ^= KeyModifier::CapsLock;
if (m_keyboard_state_temp[0x47] && !m_keyboard_state[0x47])
m_toggle_mask ^= KeyModifier::ScrollLock;
if (m_keyboard_state_temp[0x53] && !m_keyboard_state[0x53])
m_toggle_mask ^= KeyModifier::NumLock;
modifier |= m_toggle_mask;
for (size_t i = 0; i < m_keyboard_state.size(); i++)
{
if (m_keyboard_state[i] == m_keyboard_state_temp[i])
continue;
const bool pressed = m_keyboard_state_temp[i];
if (pressed)
dprintln_if(DEBUG_KEYBOARD, "{2H}", i);
auto opt_keycode = s_scancode_to_keycode[i];
if (opt_keycode.has_value())
{
LibInput::RawKeyEvent event;
event.keycode = opt_keycode.value();
event.modifier = modifier | (pressed ? KeyModifier::Pressed : 0);
add_event(BAN::ConstByteSpan::from(event));
}
m_keyboard_state[i] = m_keyboard_state_temp[i];
}
}
void USBKeyboard::handle_variable(uint16_t usage_page, uint16_t usage, int64_t state)
{
if (usage_page != 0x07)
{
dprintln_if(DEBUG_KEYBOARD, "Unsupported keyboard usage page {2H}", usage_page);
return;
}
if (usage >= 4 && usage < m_keyboard_state_temp.size())
m_keyboard_state_temp[usage] = state;
}
void USBKeyboard::handle_array(uint16_t usage_page, uint16_t usage)
{
if (usage_page != 0x07)
{
dprintln_if(DEBUG_KEYBOARD, "Unsupported keyboard usage page {2H}", usage_page);
return;
}
if (usage >= 4 && usage < m_keyboard_state_temp.size())
m_keyboard_state_temp[usage] = true;
}
void initialize_scancode_to_keycode()
{
using LibInput::keycode_function;
using LibInput::keycode_normal;
using LibInput::keycode_numpad;
s_scancode_to_keycode[0x35] = keycode_normal(0, 0);
s_scancode_to_keycode[0x1E] = keycode_normal(0, 1);
s_scancode_to_keycode[0x1F] = keycode_normal(0, 2);
s_scancode_to_keycode[0x20] = keycode_normal(0, 3);
s_scancode_to_keycode[0x21] = keycode_normal(0, 4);
s_scancode_to_keycode[0x22] = keycode_normal(0, 5);
s_scancode_to_keycode[0x23] = keycode_normal(0, 6);
s_scancode_to_keycode[0x24] = keycode_normal(0, 7);
s_scancode_to_keycode[0x25] = keycode_normal(0, 8);
s_scancode_to_keycode[0x26] = keycode_normal(0, 9);
s_scancode_to_keycode[0x27] = keycode_normal(0, 10);
s_scancode_to_keycode[0x2D] = keycode_normal(0, 11);
s_scancode_to_keycode[0x2E] = keycode_normal(0, 12);
s_scancode_to_keycode[0x2A] = keycode_normal(0, 13);
s_scancode_to_keycode[0x2B] = keycode_normal(1, 0);
s_scancode_to_keycode[0x14] = keycode_normal(1, 1);
s_scancode_to_keycode[0x1A] = keycode_normal(1, 2);
s_scancode_to_keycode[0x08] = keycode_normal(1, 3);
s_scancode_to_keycode[0x15] = keycode_normal(1, 4);
s_scancode_to_keycode[0x17] = keycode_normal(1, 5);
s_scancode_to_keycode[0x1C] = keycode_normal(1, 6);
s_scancode_to_keycode[0x18] = keycode_normal(1, 7);
s_scancode_to_keycode[0x0C] = keycode_normal(1, 8);
s_scancode_to_keycode[0x12] = keycode_normal(1, 9);
s_scancode_to_keycode[0x13] = keycode_normal(1, 10);
s_scancode_to_keycode[0x2F] = keycode_normal(1, 11);
s_scancode_to_keycode[0x30] = keycode_normal(1, 12);
s_scancode_to_keycode[0x39] = keycode_normal(2, 0);
s_scancode_to_keycode[0x04] = keycode_normal(2, 1);
s_scancode_to_keycode[0x16] = keycode_normal(2, 2);
s_scancode_to_keycode[0x07] = keycode_normal(2, 3);
s_scancode_to_keycode[0x09] = keycode_normal(2, 4);
s_scancode_to_keycode[0x0A] = keycode_normal(2, 5);
s_scancode_to_keycode[0x0B] = keycode_normal(2, 6);
s_scancode_to_keycode[0x0D] = keycode_normal(2, 7);
s_scancode_to_keycode[0x0E] = keycode_normal(2, 8);
s_scancode_to_keycode[0x0F] = keycode_normal(2, 9);
s_scancode_to_keycode[0x33] = keycode_normal(2, 10);
s_scancode_to_keycode[0x34] = keycode_normal(2, 11);
s_scancode_to_keycode[0x31] = keycode_normal(2, 12);
s_scancode_to_keycode[0x28] = keycode_normal(2, 13);
s_scancode_to_keycode[0xE1] = keycode_normal(3, 0);
s_scancode_to_keycode[0x64] = keycode_normal(3, 1);
s_scancode_to_keycode[0x1D] = keycode_normal(3, 2);
s_scancode_to_keycode[0x1B] = keycode_normal(3, 3);
s_scancode_to_keycode[0x06] = keycode_normal(3, 4);
s_scancode_to_keycode[0x19] = keycode_normal(3, 5);
s_scancode_to_keycode[0x05] = keycode_normal(3, 6);
s_scancode_to_keycode[0x11] = keycode_normal(3, 7);
s_scancode_to_keycode[0x10] = keycode_normal(3, 8);
s_scancode_to_keycode[0x36] = keycode_normal(3, 9);
s_scancode_to_keycode[0x37] = keycode_normal(3, 10);
s_scancode_to_keycode[0x38] = keycode_normal(3, 11);
s_scancode_to_keycode[0xE5] = keycode_normal(3, 12);
s_scancode_to_keycode[0xE0] = keycode_normal(4, 1);
s_scancode_to_keycode[0xE3] = keycode_normal(4, 2);
s_scancode_to_keycode[0xE2] = keycode_normal(4, 3);
s_scancode_to_keycode[0x2C] = keycode_normal(4, 4);
s_scancode_to_keycode[0xE6] = keycode_normal(4, 5);
s_scancode_to_keycode[0xE4] = keycode_normal(4, 6);
s_scancode_to_keycode[0x52] = keycode_normal(5, 0);
s_scancode_to_keycode[0x50] = keycode_normal(5, 1);
s_scancode_to_keycode[0x51] = keycode_normal(5, 2);
s_scancode_to_keycode[0x4F] = keycode_normal(5, 3);
s_scancode_to_keycode[0x29] = keycode_function( 0);
s_scancode_to_keycode[0x3A] = keycode_function( 1);
s_scancode_to_keycode[0x3B] = keycode_function( 2);
s_scancode_to_keycode[0x3C] = keycode_function( 3);
s_scancode_to_keycode[0x3D] = keycode_function( 4);
s_scancode_to_keycode[0x3E] = keycode_function( 5);
s_scancode_to_keycode[0x3F] = keycode_function( 6);
s_scancode_to_keycode[0x40] = keycode_function( 7);
s_scancode_to_keycode[0x41] = keycode_function( 8);
s_scancode_to_keycode[0x42] = keycode_function( 9);
s_scancode_to_keycode[0x43] = keycode_function(10);
s_scancode_to_keycode[0x44] = keycode_function(11);
s_scancode_to_keycode[0x45] = keycode_function(12);
s_scancode_to_keycode[0x49] = keycode_function(13);
s_scancode_to_keycode[0x46] = keycode_function(14);
s_scancode_to_keycode[0x4C] = keycode_function(15);
s_scancode_to_keycode[0x4A] = keycode_function(16);
s_scancode_to_keycode[0x4D] = keycode_function(17);
s_scancode_to_keycode[0x4B] = keycode_function(18);
s_scancode_to_keycode[0x4E] = keycode_function(19);
s_scancode_to_keycode[0x53] = keycode_numpad(0, 0);
s_scancode_to_keycode[0x54] = keycode_numpad(0, 1);
s_scancode_to_keycode[0x55] = keycode_numpad(0, 2);
s_scancode_to_keycode[0x56] = keycode_numpad(0, 3);
s_scancode_to_keycode[0x5F] = keycode_numpad(1, 0);
s_scancode_to_keycode[0x60] = keycode_numpad(1, 1);
s_scancode_to_keycode[0x61] = keycode_numpad(1, 2);
s_scancode_to_keycode[0x57] = keycode_numpad(1, 3);
s_scancode_to_keycode[0x5C] = keycode_numpad(2, 0);
s_scancode_to_keycode[0x5D] = keycode_numpad(2, 1);
s_scancode_to_keycode[0x5E] = keycode_numpad(2, 2);
s_scancode_to_keycode[0x59] = keycode_numpad(3, 0);
s_scancode_to_keycode[0x5A] = keycode_numpad(3, 1);
s_scancode_to_keycode[0x5B] = keycode_numpad(3, 2);
s_scancode_to_keycode[0x58] = keycode_numpad(3, 3);
s_scancode_to_keycode[0x62] = keycode_numpad(4, 0);
s_scancode_to_keycode[0x63] = keycode_numpad(4, 1);
s_scancode_to_keycode_initialized = true;
}
}

View File

@ -0,0 +1,99 @@
#include <kernel/USB/HID/Mouse.h>
#include <LibInput/MouseEvent.h>
#define DEBUG_MOUSE 0
namespace Kernel
{
void USBMouse::start_report()
{
for (auto& val : m_button_state_temp)
val = false;
}
void USBMouse::stop_report()
{
if (m_pointer_x || m_pointer_y)
{
dprintln_if(DEBUG_MOUSE, "Mouse move event {}, {}", m_pointer_x, m_pointer_y);
LibInput::MouseEvent event;
event.type = LibInput::MouseEventType::MouseMoveEvent;
event.move_event.rel_x = m_pointer_x;
event.move_event.rel_y = -m_pointer_y;
add_event(BAN::ConstByteSpan::from(event));
m_pointer_x = 0;
m_pointer_y = 0;
}
if (m_wheel)
{
dprintln_if(DEBUG_MOUSE, "Mouse scroll event {}", m_wheel);
LibInput::MouseEvent event;
event.type = LibInput::MouseEventType::MouseScrollEvent;
event.scroll_event.scroll = m_wheel;
add_event(BAN::ConstByteSpan::from(event));
m_wheel = 0;
}
for (size_t i = 0; i < m_button_state.size(); i++)
{
if (m_button_state[i] == m_button_state_temp[i])
continue;
const bool pressed = m_button_state_temp[i];
dprintln_if(DEBUG_MOUSE, "Mouse button event {}: {}", i, pressed);
LibInput::MouseEvent event;
event.type = LibInput::MouseEventType::MouseButtonEvent;
event.button_event.pressed = pressed;
event.button_event.button = static_cast<LibInput::MouseButton>(i);
add_event(BAN::ConstByteSpan::from(event));
m_button_state[i] = m_button_state_temp[i];
}
}
void USBMouse::handle_variable(uint16_t usage_page, uint16_t usage, int64_t state)
{
switch (usage_page)
{
case 0x01: // pointer
switch (usage)
{
case 0x30:
m_pointer_x = state;
break;
case 0x31:
m_pointer_y = state;
break;
case 0x38:
m_wheel = state;
break;
default:
dprintln_if(DEBUG_MOUSE, "Unsupported mouse usage {2H} on page {2H}", usage, usage_page);
break;
}
break;
case 0x09: // button
if (usage == 0 || usage >= m_button_state_temp.size())
break;
m_button_state_temp[usage - 1] = state;
break;
default:
dprintln_if(DEBUG_MOUSE, "Unsupported mouse usage page {2H}", usage_page);
break;
}
}
void USBMouse::handle_array(uint16_t usage_page, uint16_t usage)
{
dprintln_if(DEBUG_MOUSE, "Unhandled array report {2H}:{2H}", usage_page, usage);
}
}

View File

@ -0,0 +1,57 @@
#include <BAN/UniqPtr.h>
#include <kernel/USB/USBManager.h>
#include <kernel/USB/XHCI/Controller.h>
namespace Kernel
{
static BAN::UniqPtr<USBManager> s_instance;
BAN::ErrorOr<void> USBManager::initialize()
{
ASSERT(!s_instance);
auto manager = TRY(BAN::UniqPtr<USBManager>::create());
s_instance = BAN::move(manager);
return {};
}
USBManager& USBManager::get()
{
ASSERT(s_instance);
return *s_instance;
}
BAN::ErrorOr<void> USBManager::add_controller(PCI::Device& pci_device)
{
ASSERT(pci_device.class_code() == 0x0C);
ASSERT(pci_device.subclass() == 0x03);
BAN::UniqPtr<USBController> controller;
switch (pci_device.prog_if())
{
case 0x00:
dprintln("Unsupported UHCI controller");
return BAN::Error::from_errno(ENOTSUP);
case 0x10:
dprintln("Unsupported OHCI controller");
return BAN::Error::from_errno(ENOTSUP);
case 0x20:
dprintln("Unsupported EHCI controller");
return BAN::Error::from_errno(ENOTSUP);
case 0x30:
if (auto ret = XHCIController::initialize(pci_device); ret.is_error())
dprintln("Could not initialize XHCI controller: {}", ret.error());
else
controller = ret.release_value();
break;
default:
return BAN::Error::from_errno(EINVAL);
}
TRY(m_controllers.push_back(BAN::move(controller)));
return {};
}
}

View File

@ -0,0 +1,506 @@
#include <BAN/Bitcast.h>
#include <BAN/StringView.h>
#include <kernel/Lock/LockGuard.h>
#include <kernel/Process.h>
#include <kernel/Timer/Timer.h>
#include <kernel/USB/XHCI/Controller.h>
#include <kernel/USB/XHCI/Device.h>
#define DEBUG_XHCI 0
namespace Kernel
{
XHCIController::XHCIController(PCI::Device& pci_device)
: m_pci_device(pci_device)
{ }
XHCIController::~XHCIController()
{
if (m_port_updater)
m_port_updater->exit(0, SIGKILL);
}
BAN::ErrorOr<BAN::UniqPtr<XHCIController>> XHCIController::initialize(PCI::Device& pci_device)
{
auto controller = TRY(BAN::UniqPtr<XHCIController>::create(pci_device));
TRY(controller->initialize_impl());
return controller;
}
BAN::ErrorOr<void> XHCIController::initialize_impl()
{
dprintln_if(DEBUG_XHCI, "XHCI controller at PCI {2H}:{2H}:{2H}", m_pci_device.bus(), m_pci_device.dev(), m_pci_device.func());
m_pci_device.enable_bus_mastering();
m_pci_device.enable_memory_space();
m_configuration_bar = TRY(m_pci_device.allocate_bar_region(0));
if (m_configuration_bar->type() != PCI::BarType::MEM)
{
dwarnln("XHCI controller with non-memory configuration space");
return BAN::Error::from_errno(EINVAL);
}
if (auto ret = reset_controller(); ret.is_error())
{
dwarnln("Could not reset XHCI Controller: {}", ret.error());
return ret.release_error();
}
auto& capabilities = capability_regs();
dprintln_if(DEBUG_XHCI, " version {H}.{H}.{H}",
+capabilities.major_revision,
capabilities.minor_revision >> 4,
capabilities.minor_revision & 0x0F
);
dprintln_if(DEBUG_XHCI, " max slots {}", +capabilities.hcsparams1.max_slots);
dprintln_if(DEBUG_XHCI, " max intrs {}", +capabilities.hcsparams1.max_interrupters);
dprintln_if(DEBUG_XHCI, " max ports {}", +capabilities.hcsparams1.max_ports);
TRY(m_slots.resize(capabilities.hcsparams1.max_slots));
TRY(m_ports.resize(capabilities.hcsparams1.max_ports));
TRY(initialize_ports());
auto& operational = operational_regs();
// allocate and program dcbaa
m_dcbaa_region = TRY(DMARegion::create(capabilities.hcsparams1.max_slots * 8));
memset(reinterpret_cast<void*>(m_dcbaa_region->vaddr()), 0, m_dcbaa_region->size());
operational.dcbaap_lo = m_dcbaa_region->paddr() & 0xFFFFFFFF;
operational.dcbaap_hi = m_dcbaa_region->paddr() >> 32;
// allocate and program crcr
TRY(m_command_completions.resize(m_command_ring_trb_count));
m_command_ring_region = TRY(DMARegion::create(m_command_ring_trb_count * sizeof(XHCI::TRB)));
memset(reinterpret_cast<void*>(m_command_ring_region->vaddr()), 0, m_command_ring_region->size());
operational.crcr_lo = m_command_ring_region->paddr() | XHCI::CRCR::RingCycleState;
operational.crcr_hi = m_command_ring_region->paddr() >> 32;
TRY(initialize_primary_interrupter());
// enable the controller
operational.usbcmd.run_stop = 1;
while (operational.usbsts & XHCI::USBSTS::HCHalted)
continue;
m_port_updater = Process::create_kernel([](void* data) { reinterpret_cast<XHCIController*>(data)->port_updater_task(); }, this);
if (m_port_updater == nullptr)
return BAN::Error::from_errno(ENOMEM);
return {};
}
BAN::ErrorOr<void> XHCIController::initialize_ports()
{
auto& capabilities = capability_regs();
uint8_t max_ports = capabilities.hcsparams1.max_ports;
ASSERT(m_ports.size() == max_ports);
{
uint16_t ext_offset = capabilities.hccparams1.xhci_extended_capabilities_pointer;
if (ext_offset == 0)
{
dwarnln("XHCI controller does not have extended capabilities");
return BAN::Error::from_errno(EFAULT);
}
vaddr_t ext_addr = m_configuration_bar->vaddr() + ext_offset * 4;
while (true)
{
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);
if (protocol.name_string != *reinterpret_cast<const uint32_t*>("USB "))
{
dwarnln("Invalid port protocol name string");
return BAN::Error::from_errno(EFAULT);
}
if (protocol.compatible_port_offset == 0 || protocol.compatible_port_offset + protocol.compatible_port_count - 1 > max_ports)
{
dwarnln("Invalid port specified in SupportedProtocols");
return BAN::Error::from_errno(EFAULT);
}
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;
}
}
}
if (ext_cap.next_capability == 0)
break;
ext_addr += ext_cap.next_capability * 4;
}
}
// set max slots enabled
auto& operational = operational_regs();
operational.config.max_device_slots_enabled = capabilities.hcsparams1.max_slots;
return {};
}
BAN::ErrorOr<void> XHCIController::initialize_primary_interrupter()
{
TRY(m_pci_device.reserve_irqs(1));
auto& runtime = runtime_regs();
static constexpr size_t event_ring_table_offset = m_event_ring_trb_count * sizeof(XHCI::TRB);
m_event_ring_region = TRY(DMARegion::create(m_event_ring_trb_count * sizeof(XHCI::TRB) + sizeof(XHCI::EventRingTableEntry)));
memset(reinterpret_cast<void*>(m_event_ring_region->vaddr()), 0, m_event_ring_region->size());
auto& event_ring_table_entry = *reinterpret_cast<XHCI::EventRingTableEntry*>(m_event_ring_region->vaddr() + event_ring_table_offset);
event_ring_table_entry.rsba = m_event_ring_region->paddr();
event_ring_table_entry.rsz = m_event_ring_trb_count;
auto& primary_interrupter = runtime.irs[0];
primary_interrupter.erstsz = 1;
primary_interrupter.erdp = m_event_ring_region->paddr();
primary_interrupter.erstba = m_event_ring_region->paddr() + event_ring_table_offset;
auto& operational = operational_regs();
operational.usbcmd.interrupter_enable = 1;
primary_interrupter.iman = primary_interrupter.iman | XHCI::IMAN::InterruptPending | XHCI::IMAN::InterruptEnable;
set_irq(m_pci_device.get_irq(0));
enable_interrupt();
return {};
}
static Mutex s_port_mutex;
void XHCIController::port_updater_task()
{
// allow initial pass of port iteration because controller
// does not send Port Status Change event for already
// attached ports
m_port_changed = true;
while (true)
{
{
bool expected { true };
while (!m_port_changed.compare_exchange(expected, false))
{
m_port_semaphore.block_with_timeout(100);
expected = true;
}
}
for (size_t i = 0; i < m_ports.size(); i++)
{
LockGuard _(s_port_mutex);
auto& my_port = m_ports[i];
if (my_port.revision_major == 0)
continue;
auto& op_port = operational_regs().ports[i];
if (!(op_port.portsc & XHCI::PORTSC::PP))
continue;
// read and clear needed change flags
const bool reset_change = op_port.portsc & XHCI::PORTSC::PRC;
const bool connection_change = op_port.portsc & XHCI::PORTSC::CSC;
op_port.portsc = XHCI::PORTSC::CSC | XHCI::PORTSC::PRC | XHCI::PORTSC::PP;
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();
my_port.slot_id = 0;
}
continue;
}
switch (my_port.revision_major)
{
case 2:
if (!reset_change)
{
if (connection_change)
op_port.portsc = XHCI::PORTSC::PR | XHCI::PORTSC::PP;
continue;
}
break;
case 3:
if (!connection_change)
continue;
dprintln_if(DEBUG_XHCI, "USB 3 devices not supported");
continue;
default:
continue;
}
if (auto ret = initialize_slot(i); ret.is_error())
{
dwarnln("Could not initialize USB {H}.{H} device: {}",
my_port.revision_major,
my_port.revision_minor >> 4,
ret.error()
);
}
}
}
}
BAN::ErrorOr<void> XHCIController::initialize_slot(int port_index)
{
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;
auto result = TRY(send_command(enable_slot));
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);
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 (auto ret = m_slots[slot_id - 1]->initialize(); ret.is_error())
{
dwarnln("Could not initialize device on slot {}: {}", slot_id, ret.error());
m_slots[slot_id - 1].clear();
return ret.release_error();
}
my_port.slot_id = slot_id;
dprintln_if(DEBUG_XHCI, "device on slot {} initialized", slot_id);
return {};
}
BAN::ErrorOr<void> XHCIController::reset_controller()
{
auto& operational = operational_regs();
const uint64_t timeout_ms = SystemTimer::get().ms_since_boot() + 500;
// wait until controller not ready clears
while (operational.usbsts & XHCI::USBSTS::ControllerNotReady)
if (SystemTimer::get().ms_since_boot() > timeout_ms)
return BAN::Error::from_errno(ETIMEDOUT);
// issue software reset and wait for it to clear
operational.usbcmd.host_controller_reset = 1;
while (operational.usbcmd.host_controller_reset)
if (SystemTimer::get().ms_since_boot() > timeout_ms)
return BAN::Error::from_errno(ETIMEDOUT);
return {};
}
BAN::ErrorOr<XHCI::TRB> XHCIController::send_command(const XHCI::TRB& trb)
{
LockGuard _(m_mutex);
auto& command_trb = reinterpret_cast<volatile XHCI::TRB*>(m_command_ring_region->vaddr())[m_command_enqueue];
command_trb.raw.dword0 = trb.raw.dword0;
command_trb.raw.dword1 = trb.raw.dword1;
command_trb.raw.dword2 = trb.raw.dword2;
command_trb.raw.dword3 = trb.raw.dword3;
command_trb.cycle = m_command_cycle;
auto& completion_trb = const_cast<volatile XHCI::TRB&>(m_command_completions[m_command_enqueue]);
completion_trb.raw.dword0 = 0;
completion_trb.raw.dword1 = 0;
completion_trb.raw.dword2 = 0;
completion_trb.raw.dword3 = 0;
advance_command_enqueue();
doorbell_reg(0) = 0;
uint64_t timeout_ms = SystemTimer::get().ms_since_boot() + 1000;
while ((__atomic_load_n(&completion_trb.raw.dword2, __ATOMIC_SEQ_CST) >> 24) == 0)
if (SystemTimer::get().ms_since_boot() > timeout_ms)
return BAN::Error::from_errno(ETIMEDOUT);
if (completion_trb.command_completion_event.completion_code != 1)
{
dwarnln("Completion error: {}", +completion_trb.command_completion_event.completion_code);
return BAN::Error::from_errno(EFAULT);
}
return BAN::bit_cast<XHCI::TRB>(completion_trb);
}
void XHCIController::advance_command_enqueue()
{
m_command_enqueue++;
if (m_command_enqueue < m_command_ring_trb_count - 1)
return;
auto& link_trb = reinterpret_cast<volatile XHCI::TRB*>(m_command_ring_region->vaddr())[m_command_enqueue].link_trb;
link_trb.trb_type = XHCI::TRBType::Link;
link_trb.ring_segment_ponter = m_command_ring_region->paddr();
link_trb.interrupter_target = 0;
link_trb.cycle_bit = m_command_cycle;
link_trb.toggle_cycle = 1;
link_trb.chain_bit = 0;
link_trb.interrupt_on_completion = 0;
m_command_enqueue = 0;
m_command_cycle = !m_command_cycle;
}
void XHCIController::handle_irq()
{
auto& operational = operational_regs();
if (!(operational.usbsts & XHCI::USBSTS::EventInterrupt))
return;
operational.usbsts = XHCI::USBSTS::EventInterrupt;
auto& primary_interrupter = runtime_regs().irs[0];
primary_interrupter.iman = primary_interrupter.iman | XHCI::IMAN::InterruptPending | XHCI::IMAN::InterruptEnable;
if (current_event_trb().cycle == m_event_cycle)
{
for (;;)
{
auto& trb = current_event_trb();
if (trb.cycle != m_event_cycle)
break;
switch (trb.trb_type)
{
case XHCI::TRBType::TransferEvent:
{
dprintln_if(DEBUG_XHCI, "TransferEvent");
const uint32_t slot_id = trb.transfer_event.slot_id;
if (slot_id == 0 || slot_id > m_slots.size() || !m_slots[slot_id - 1])
{
dwarnln("TransferEvent for invalid slot {}", slot_id);
dwarnln("Completion error: {}", +trb.transfer_event.completion_code);
break;
}
m_slots[slot_id - 1]->on_transfer_event(trb);
break;
}
case XHCI::TRBType::CommandCompletionEvent:
{
dprintln_if(DEBUG_XHCI, "CommandCompletionEvent");
const uint32_t trb_index = (trb.command_completion_event.command_trb_pointer - m_command_ring_region->paddr()) / sizeof(XHCI::TRB);
// NOTE: dword2 is last (and atomic) as that is what send_command is waiting for
auto& completion_trb = const_cast<volatile XHCI::TRB&>(m_command_completions[trb_index]);
completion_trb.raw.dword0 = trb.raw.dword0;
completion_trb.raw.dword1 = trb.raw.dword1;
completion_trb.raw.dword3 = trb.raw.dword3;
__atomic_store_n(&completion_trb.raw.dword2, trb.raw.dword2, __ATOMIC_SEQ_CST);
break;
}
case XHCI::TRBType::PortStatusChangeEvent:
{
dprintln_if(DEBUG_XHCI, "PortStatusChangeEvent");
uint8_t port_id = trb.port_status_chage_event.port_id;
if (port_id > capability_regs().hcsparams1.max_ports)
{
dwarnln("PortStatusChangeEvent on non-existent port {}", port_id);
break;
}
m_port_changed = true;
m_port_semaphore.unblock();
break;
}
case XHCI::TRBType::BandwidthRequestEvent:
dwarnln("Unhandled BandwidthRequestEvent");
break;
case XHCI::TRBType::DoorbellEvent:
dwarnln("Unhandled DoorbellEvent");
break;
case XHCI::TRBType::HostControllerEvent:
dwarnln("Unhandled HostControllerEvent");
break;
case XHCI::TRBType::DeviceNotificationEvent:
dwarnln("Unhandled DeviceNotificationEvent");
break;
case XHCI::TRBType::MFINDEXWrapEvent:
dwarnln("Unhandled MFINDEXWrapEvent");
break;
default:
dwarnln("Unrecognized event TRB type {}", +trb.trb_type);
break;
}
m_event_dequeue++;
if (m_event_dequeue >= m_event_ring_trb_count)
{
m_event_dequeue = 0;
m_event_cycle = !m_event_cycle;
}
}
primary_interrupter.erdp = (m_event_ring_region->paddr() + (m_event_dequeue * sizeof(XHCI::TRB))) | XHCI::ERDP::EventHandlerBusy;
}
}
volatile XHCI::CapabilityRegs& XHCIController::capability_regs()
{
return *reinterpret_cast<volatile XHCI::CapabilityRegs*>(m_configuration_bar->vaddr());
}
volatile XHCI::OperationalRegs& XHCIController::operational_regs()
{
return *reinterpret_cast<volatile XHCI::OperationalRegs*>(m_configuration_bar->vaddr() + capability_regs().caplength);
}
volatile XHCI::RuntimeRegs& XHCIController::runtime_regs()
{
return *reinterpret_cast<volatile XHCI::RuntimeRegs*>(m_configuration_bar->vaddr() + (capability_regs().rstoff & ~0x1Fu));
}
volatile uint32_t& XHCIController::doorbell_reg(uint32_t slot_id)
{
return reinterpret_cast<volatile uint32_t*>(m_configuration_bar->vaddr() + capability_regs().dboff)[slot_id];
}
const volatile XHCI::TRB& XHCIController::current_event_trb()
{
return reinterpret_cast<const volatile XHCI::TRB*>(m_event_ring_region->vaddr())[m_event_dequeue];;
}
volatile uint64_t& XHCIController::dcbaa_reg(uint32_t slot_id)
{
return reinterpret_cast<volatile uint64_t*>(m_dcbaa_region->vaddr())[slot_id];
}
}

View File

@ -0,0 +1,447 @@
#include <BAN/Bitcast.h>
#include <BAN/ByteSpan.h>
#include <kernel/Lock/LockGuard.h>
#include <kernel/Timer/Timer.h>
#include <kernel/USB/XHCI/Device.h>
#define DEBUG_XHCI 0
namespace Kernel
{
BAN::ErrorOr<BAN::UniqPtr<XHCIDevice>> XHCIDevice::create(XHCIController& controller, uint32_t port_id, uint32_t slot_id)
{
return TRY(BAN::UniqPtr<XHCIDevice>::create(controller, port_id, slot_id));
}
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;
if (auto ret = m_controller.send_command(disable_slot); ret.is_error())
dwarnln("Could not disable slot {}: {}", m_slot_id, ret.error());
else
dprintln_if(DEBUG_XHCI, "Slot {} disabled", m_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;
const uint32_t bits_per_second = m_controller.port(m_port_id).speed_id_to_speed[speed_id];
const auto speed_class = determine_speed_class(bits_per_second);
m_endpoints[0].max_packet_size = 0;
switch (speed_class)
{
case USB::SpeedClass::LowSpeed:
case USB::SpeedClass::FullSpeed:
m_endpoints[0].max_packet_size = 8;
break;
case USB::SpeedClass::HighSpeed:
m_endpoints[0].max_packet_size = 64;
break;
case USB::SpeedClass::SuperSpeed:
m_endpoints[0].max_packet_size = 512;
break;
default: ASSERT_NOT_REACHED();
}
m_input_context = TRY(DMARegion::create(33 * context_size));
memset(reinterpret_cast<void*>(m_input_context->vaddr()), 0, m_input_context->size());
m_output_context = TRY(DMARegion::create(32 * context_size));
memset(reinterpret_cast<void*>(m_output_context->vaddr()), 0, m_output_context->size());
m_endpoints[0].transfer_ring = TRY(DMARegion::create(m_transfer_ring_trb_count * sizeof(XHCI::TRB)));
memset(reinterpret_cast<void*>(m_endpoints[0].transfer_ring->vaddr()), 0, m_endpoints[0].transfer_ring->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);
memset(&input_control_context, 0, context_size);
input_control_context.add_context_flags = 0b11;
memset(&slot_context, 0, context_size);
slot_context.route_string = 0;
slot_context.root_hub_port_number = m_port_id;
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;
}
m_controller.dcbaa_reg(m_slot_id) = m_output_context->paddr();
for (int i = 0; i < 2; i++)
{
XHCI::TRB address_device { .address_device_command = {} };
address_device.address_device_command.trb_type = XHCI::TRBType::AddressDeviceCommand;
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;
TRY(m_controller.send_command(address_device));
}
// NOTE: Full speed devices can have other max packet sizes than 8
if (speed_class == USB::SpeedClass::FullSpeed)
TRY(update_actual_max_packet_size());
return {};
}
BAN::ErrorOr<void> XHCIDevice::update_actual_max_packet_size()
{
// FIXME: This is more or less generic USB code
dprintln_if(DEBUG_XHCI, "Retrieving actual max packet size of full speed device");
BAN::Vector<uint8_t> buffer;
TRY(buffer.resize(8, 0));
USBDeviceRequest request;
request.bmRequestType = USB::RequestType::DeviceToHost | USB::RequestType::Standard | USB::RequestType::Device;
request.bRequest = USB::Request::GET_DESCRIPTOR;
request.wValue = 0x0100;
request.wIndex = 0;
request.wLength = 8;
TRY(send_request(request, kmalloc_paddr_of((vaddr_t)buffer.data()).value()));
m_endpoints[0].max_packet_size = buffer.back();
const uint32_t context_size = m_controller.context_size_set() ? 64 : 32;
{
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;
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;
}
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;
TRY(m_controller.send_command(evaluate_context));
dprintln_if(DEBUG_XHCI, "successfully updated max packet size to {}", m_endpoints[0].max_packet_size);
return {};
}
BAN::ErrorOr<void> XHCIDevice::initialize_endpoint(const USBEndpointDescriptor& endpoint_descriptor)
{
const uint32_t endpoint_id = (endpoint_descriptor.bEndpointAddress & 0x0F) * 2 + !!(endpoint_descriptor.bEndpointAddress & 0x80);
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;
endpoint.transfer_ring = TRY(DMARegion::create(m_transfer_ring_trb_count * sizeof(XHCI::TRB)));
endpoint.max_packet_size = endpoint_descriptor.wMaxPacketSize & 0x07FF;
endpoint.dequeue_index = 0;
endpoint.enqueue_index = 0;
endpoint.cycle_bit = 1;
endpoint.callback = &XHCIDevice::on_interrupt_endpoint_event;
endpoint.data_region = TRY(DMARegion::create(endpoint.max_packet_size));
memset(reinterpret_cast<void*>(endpoint.transfer_ring->vaddr()), 0, endpoint.transfer_ring->size());
{
const uint32_t context_size = m_controller.context_size_set() ? 64 : 32;
auto& input_control_context = *reinterpret_cast<XHCI::InputControlContext*>(m_input_context->vaddr());
auto& slot_context = *reinterpret_cast<XHCI::SlotContext*> (m_input_context->vaddr() + 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);
input_control_context.add_context_flags = (1u << endpoint_id) | 1;
memset(&slot_context, 0, context_size);
slot_context.context_entries = last_valid_endpoint_id;
// FIXME: 4.5.2 hub
ASSERT(endpoint_descriptor.bEndpointAddress & 0x80);
ASSERT((endpoint_descriptor.bmAttributes & 0x03) == 3);
ASSERT(m_controller.port(m_port_id).revision_major == 2);
memset(&endpoint_context, 0, context_size);
endpoint_context.endpoint_type = XHCI::EndpointType::InterruptIn;
endpoint_context.max_packet_size = endpoint.max_packet_size;
endpoint_context.max_burst_size = (endpoint_descriptor.wMaxPacketSize >> 11) & 0x0003;
endpoint_context.mult = 0;
endpoint_context.error_count = 3;
endpoint_context.tr_dequeue_pointer = endpoint.transfer_ring->paddr() | 1;
const uint32_t max_esit_payload = endpoint_context.max_packet_size * (endpoint_context.max_burst_size + 1);
endpoint_context.max_esit_payload_lo = max_esit_payload & 0xFFFF;
endpoint_context.max_esit_payload_hi = max_esit_payload >> 16;
}
XHCI::TRB configure_endpoint { .configure_endpoint_command = {} };
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;
TRY(m_controller.send_command(configure_endpoint));
auto& trb = *reinterpret_cast<volatile XHCI::TRB*>(endpoint.transfer_ring->vaddr());
memset(const_cast<XHCI::TRB*>(&trb), 0, sizeof(XHCI::TRB));
trb.normal.trb_type = XHCI::TRBType::Normal;
trb.normal.data_buffer_pointer = endpoint.data_region->paddr();
trb.normal.trb_transfer_length = endpoint.data_region->size();
trb.normal.td_size = 0;
trb.normal.interrupt_target = 0;
trb.normal.cycle_bit = 1;
trb.normal.interrupt_on_completion = 1;
trb.normal.interrupt_on_short_packet = 1;
advance_endpoint_enqueue(endpoint, false);
m_controller.doorbell_reg(m_slot_id) = endpoint_id;
return {};
}
void XHCIDevice::on_interrupt_endpoint_event(XHCI::TRB trb)
{
ASSERT(trb.trb_type == XHCI::TRBType::TransferEvent);
if (trb.transfer_event.completion_code != 1 && trb.transfer_event.completion_code != 13)
{
dwarnln("Interrupt endpoint got transfer event with completion code {}", +trb.transfer_event.completion_code);
return;
}
const uint32_t endpoint_id = trb.transfer_event.endpoint_id;
auto& endpoint = m_endpoints[endpoint_id - 1];
ASSERT(endpoint.transfer_ring && endpoint.data_region);
const uint32_t transfer_length = endpoint.max_packet_size - trb.transfer_event.trb_transfer_length;
auto received_data = BAN::ConstByteSpan(reinterpret_cast<uint8_t*>(endpoint.data_region->vaddr()), transfer_length);
handle_input_data(received_data, endpoint_id);
auto& new_trb = *reinterpret_cast<volatile XHCI::TRB*>(endpoint.transfer_ring->vaddr() + endpoint.enqueue_index * sizeof(XHCI::TRB));
memset(const_cast<XHCI::TRB*>(&new_trb), 0, sizeof(XHCI::TRB));
new_trb.normal.trb_type = XHCI::TRBType::Normal;
new_trb.normal.data_buffer_pointer = endpoint.data_region->paddr();
new_trb.normal.trb_transfer_length = endpoint.max_packet_size;
new_trb.normal.td_size = 0;
new_trb.normal.interrupt_target = 0;
new_trb.normal.cycle_bit = endpoint.cycle_bit;
new_trb.normal.interrupt_on_completion = 1;
new_trb.normal.interrupt_on_short_packet = 1;
advance_endpoint_enqueue(endpoint, false);
m_controller.doorbell_reg(m_slot_id) = endpoint_id;
}
void XHCIDevice::on_transfer_event(const volatile XHCI::TRB& trb)
{
ASSERT(trb.trb_type == XHCI::TRBType::TransferEvent);
if (trb.transfer_event.endpoint_id == 0)
{
dwarnln("TransferEvent for endpoint id 0");
return;
}
auto& endpoint = m_endpoints[trb.transfer_event.endpoint_id - 1];
if (endpoint.callback)
{
XHCI::TRB copy;
copy.raw.dword0 = trb.raw.dword0;
copy.raw.dword1 = trb.raw.dword1;
copy.raw.dword2 = trb.raw.dword2;
copy.raw.dword3 = trb.raw.dword3;
(this->*endpoint.callback)(copy);
return;
}
// Get received bytes from short packet
if (trb.transfer_event.completion_code == 13)
{
auto* transfer_trb_arr = reinterpret_cast<volatile XHCI::TRB*>(endpoint.transfer_ring->vaddr());
const uint32_t trb_index = (trb.transfer_event.trb_pointer - endpoint.transfer_ring->paddr()) / sizeof(XHCI::TRB);
const uint32_t full_trbs_transferred = (trb_index >= endpoint.dequeue_index)
? trb_index - 1 - endpoint.dequeue_index
: trb_index + m_transfer_ring_trb_count - 2 - endpoint.dequeue_index;
const uint32_t full_trb_data = full_trbs_transferred * endpoint.max_packet_size;
const uint32_t short_data = transfer_trb_arr[trb_index].data_stage.trb_transfer_length - trb.transfer_event.trb_transfer_length;
endpoint.transfer_count = full_trb_data + short_data;
ASSERT(trb_index >= endpoint.dequeue_index);
return;
}
// NOTE: dword2 is last (and atomic) as that is what send_request is waiting for
auto& completion_trb = endpoint.completion_trb;
completion_trb.raw.dword0 = trb.raw.dword0;
completion_trb.raw.dword1 = trb.raw.dword1;
completion_trb.raw.dword3 = trb.raw.dword3;
__atomic_store_n(&completion_trb.raw.dword2, trb.raw.dword2, __ATOMIC_SEQ_CST);
}
BAN::ErrorOr<size_t> XHCIDevice::send_request(const USBDeviceRequest& request, paddr_t buffer_paddr)
{
// FIXME: This is more or less generic USB code
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 =
[&request]() -> uint8_t
{
if (request.wLength == 0)
return 0;
if (request.bmRequestType & USB::RequestType::DeviceToHost)
return 3;
return 2;
}();
auto* transfer_trb_arr = reinterpret_cast<volatile XHCI::TRB*>(endpoint.transfer_ring->vaddr());
{
auto& trb = transfer_trb_arr[endpoint.enqueue_index];
memset(const_cast<XHCI::TRB*>(&trb), 0, sizeof(XHCI::TRB));
trb.setup_stage.trb_type = XHCI::TRBType::SetupStage;
trb.setup_stage.transfer_type = transfer_type;
trb.setup_stage.trb_transfer_length = 8;
trb.setup_stage.interrupt_on_completion = 0;
trb.setup_stage.immediate_data = 1;
trb.setup_stage.cycle_bit = endpoint.cycle_bit;
trb.setup_stage.bmRequestType = request.bmRequestType;
trb.setup_stage.bRequest = request.bRequest;
trb.setup_stage.wValue = request.wValue;
trb.setup_stage.wIndex = request.wIndex;
trb.setup_stage.wLength = request.wLength;
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)
{
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.interrupt_on_completion = 0;
trb.data_stage.interrupt_on_short_packet = 1;
trb.data_stage.immediate_data = 0;
trb.data_stage.data_buffer_pointer = buffer_paddr + bytes_handled;
trb.data_stage.cycle_bit = endpoint.cycle_bit;
bytes_handled += to_handle;
packets_transferred++;
advance_endpoint_enqueue(endpoint, trb.data_stage.chain_bit);
}
{
auto& trb = transfer_trb_arr[endpoint.enqueue_index];
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.chain_bit = 0;
trb.status_stage.interrupt_on_completion = 1;
trb.data_stage.cycle_bit = endpoint.cycle_bit;
advance_endpoint_enqueue(endpoint, false);
}
auto& completion_trb = endpoint.completion_trb;
completion_trb.raw.dword0 = 0;
completion_trb.raw.dword1 = 0;
completion_trb.raw.dword2 = 0;
completion_trb.raw.dword3 = 0;
endpoint.transfer_count = request.wLength;
m_controller.doorbell_reg(m_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)
if (SystemTimer::get().ms_since_boot() > timeout_ms)
return BAN::Error::from_errno(ETIMEDOUT);
endpoint.dequeue_index = endpoint.enqueue_index;
if (completion_trb.transfer_event.completion_code != 1)
{
dwarnln("Completion error: {}", +completion_trb.transfer_event.completion_code);
return BAN::Error::from_errno(EFAULT);
}
return endpoint.transfer_count;
}
void XHCIDevice::advance_endpoint_enqueue(Endpoint& endpoint, bool chain)
{
endpoint.enqueue_index++;
if (endpoint.enqueue_index < m_transfer_ring_trb_count - 1)
return;
// This is the last TRB in transfer ring. Make it link to the beginning of the ring
auto& link_trb = reinterpret_cast<volatile XHCI::TRB*>(endpoint.transfer_ring->vaddr())[endpoint.enqueue_index].link_trb;
link_trb.trb_type = XHCI::TRBType::Link;
link_trb.ring_segment_ponter = endpoint.transfer_ring->paddr();
link_trb.interrupter_target = 0;
link_trb.cycle_bit = endpoint.cycle_bit;
link_trb.toggle_cycle = 1;
link_trb.chain_bit = chain;
link_trb.interrupt_on_completion = 0;
endpoint.enqueue_index = 0;
endpoint.cycle_bit = !endpoint.cycle_bit;
}
}

View File

@ -27,6 +27,7 @@
#include <kernel/Terminal/Serial.h>
#include <kernel/Terminal/VirtualTTY.h>
#include <kernel/Timer/Timer.h>
#include <kernel/USB/USBManager.h>
#include <LibInput/KeyboardLayout.h>
@ -200,16 +201,23 @@ static void init2(void*)
// Initialize empty keymap
MUST(LibInput::KeyboardLayout::initialize());
if (auto res = PS2Controller::initialize(); res.is_error())
dprintln("{}", res.error());
// FIXME: initialize PS/2 after USB
//if (auto res = PS2Controller::initialize(); res.is_error())
// dprintln("{}", res.error());
MUST(NetworkManager::initialize());
MUST(USBManager::initialize());
// NOTE: PCI devices are the last ones to be initialized
// so other devices can reserve predefined interrupts
PCI::PCIManager::get().initialize_devices();
dprintln("PCI devices initialized");
// FIXME: This is very hacky way to wait until USB stack is initialized
SystemTimer::get().sleep(500);
VirtualFileSystem::initialize(cmdline.root);
dprintln("VFS initialized");

View File

@ -31,5 +31,6 @@ qemu-system-$QEMU_ARCH \
-drive format=raw,id=disk,file=${BANAN_DISK_IMAGE_PATH},if=none \
-device e1000e,netdev=net \
-netdev user,id=net \
-device qemu-xhci -device usb-kbd \
$DISK_ARGS \
$@ \

View File

@ -36,7 +36,7 @@ BAN::Optional<BAN::String> parse_dollar(BAN::StringView command, size_t& i)
ASSERT(command[i] == '$');
if (++i >= command.size())
return "$"_sv;
return BAN::String("$"_sv);
if (command[i] == '?')
{
@ -53,8 +53,8 @@ BAN::Optional<BAN::String> parse_dollar(BAN::StringView command, size_t& i)
i += len - 1;
if (const char* value = getenv(name.data()))
return BAN::StringView(value);
return ""_sv;
return BAN::String(value);
return BAN::String();
}
else if (command[i] == '{')
{
@ -74,8 +74,8 @@ BAN::Optional<BAN::String> parse_dollar(BAN::StringView command, size_t& i)
i += len;
if (const char* value = getenv(name.data()))
return BAN::StringView(value);
return ""_sv;
return BAN::String(value);
return BAN::String();
}
else if (command[i] == '[')
{

View File

@ -158,11 +158,11 @@ int main()
MUST(LibInput::KeyboardLayout::initialize());
MUST(LibInput::KeyboardLayout::get().load_from_file("/usr/share/keymaps/us.keymap"_sv));
int keyboard_fd = open("/dev/input0", O_RDONLY);
int keyboard_fd = open("/dev/keyboard0", O_RDONLY);
if (keyboard_fd == -1)
perror("open");
int mouse_fd = open("/dev/input1", O_RDONLY);
int mouse_fd = open("/dev/mouse0", O_RDONLY);
if (mouse_fd == -1)
perror("open");

View File

@ -50,7 +50,7 @@ void cleanup()
int main(int argc, char** argv)
{
const char* fb_path = "/dev/fb0";
const char* mouse_path = "/dev/input1";
const char* mouse_path = "/dev/mouse0";
if (argc == 1)
;