Compare commits
7 Commits
86e9d92ecb
...
a5cb4057f9
Author | SHA1 | Date |
---|---|---|
Bananymous | a5cb4057f9 | |
Bananymous | 9d7f97ccd5 | |
Bananymous | 0578d41500 | |
Bananymous | 42c3fa24f0 | |
Bananymous | 60b396fee5 | |
Bananymous | 4cd9252ff6 | |
Bananymous | 75875d3a8f |
|
@ -20,6 +20,7 @@ namespace Kernel
|
||||||
static PageTable* s_kernel = nullptr;
|
static PageTable* s_kernel = nullptr;
|
||||||
static bool s_has_nxe = false;
|
static bool s_has_nxe = false;
|
||||||
static bool s_has_pge = false;
|
static bool s_has_pge = false;
|
||||||
|
static bool s_has_pat = false;
|
||||||
|
|
||||||
static paddr_t s_global_pdpte = 0;
|
static paddr_t s_global_pdpte = 0;
|
||||||
|
|
||||||
|
@ -32,8 +33,6 @@ namespace Kernel
|
||||||
result |= Flags::Execute;
|
result |= Flags::Execute;
|
||||||
if (entry & Flags::Reserved)
|
if (entry & Flags::Reserved)
|
||||||
result |= Flags::Reserved;
|
result |= Flags::Reserved;
|
||||||
if (entry & Flags::CacheDisable)
|
|
||||||
result |= Flags::CacheDisable;
|
|
||||||
if (entry & Flags::UserSupervisor)
|
if (entry & Flags::UserSupervisor)
|
||||||
result |= Flags::UserSupervisor;
|
result |= Flags::UserSupervisor;
|
||||||
if (entry & Flags::ReadWrite)
|
if (entry & Flags::ReadWrite)
|
||||||
|
@ -51,6 +50,9 @@ namespace Kernel
|
||||||
if (CPUID::has_pge())
|
if (CPUID::has_pge())
|
||||||
s_has_pge = true;
|
s_has_pge = true;
|
||||||
|
|
||||||
|
if (CPUID::has_pat())
|
||||||
|
s_has_pat = true;
|
||||||
|
|
||||||
ASSERT(s_kernel == nullptr);
|
ASSERT(s_kernel == nullptr);
|
||||||
s_kernel = new PageTable();
|
s_kernel = new PageTable();
|
||||||
ASSERT(s_kernel);
|
ASSERT(s_kernel);
|
||||||
|
@ -82,6 +84,17 @@ namespace Kernel
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (s_has_pat)
|
||||||
|
{
|
||||||
|
asm volatile(
|
||||||
|
"movl $0x277, %%ecx;"
|
||||||
|
"rdmsr;"
|
||||||
|
"movw $0x0401, %%dx;"
|
||||||
|
"wrmsr;"
|
||||||
|
::: "eax", "ecx", "edx", "memory"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// enable write protect
|
// enable write protect
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"movl %%cr0, %%eax;"
|
"movl %%cr0, %%eax;"
|
||||||
|
@ -316,7 +329,7 @@ namespace Kernel
|
||||||
unmap_page(page * PAGE_SIZE);
|
unmap_page(page * PAGE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags)
|
void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags, MemoryType memory_type)
|
||||||
{
|
{
|
||||||
ASSERT(vaddr);
|
ASSERT(vaddr);
|
||||||
ASSERT(vaddr != fast_page());
|
ASSERT(vaddr != fast_page());
|
||||||
|
@ -338,8 +351,14 @@ namespace Kernel
|
||||||
extra_flags |= 1ull << 63;
|
extra_flags |= 1ull << 63;
|
||||||
if (flags & Flags::Reserved)
|
if (flags & Flags::Reserved)
|
||||||
extra_flags |= Flags::Reserved;
|
extra_flags |= Flags::Reserved;
|
||||||
if (flags & Flags::CacheDisable)
|
|
||||||
extra_flags |= Flags::CacheDisable;
|
if (s_has_pat)
|
||||||
|
{
|
||||||
|
if (memory_type == MemoryType::WriteCombining)
|
||||||
|
extra_flags |= (1ull << 7);
|
||||||
|
if (memory_type == MemoryType::WriteThrough)
|
||||||
|
extra_flags |= (1ull << 7) | (1ull << 3);
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: we add present here, since it has to be available in higher level structures
|
// NOTE: we add present here, since it has to be available in higher level structures
|
||||||
flags_t uwr_flags = (flags & (Flags::UserSupervisor | Flags::ReadWrite)) | Flags::Present;
|
flags_t uwr_flags = (flags & (Flags::UserSupervisor | Flags::ReadWrite)) | Flags::Present;
|
||||||
|
@ -367,7 +386,7 @@ namespace Kernel
|
||||||
invalidate(vaddr);
|
invalidate(vaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags)
|
void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags, MemoryType memory_type)
|
||||||
{
|
{
|
||||||
ASSERT(vaddr);
|
ASSERT(vaddr);
|
||||||
ASSERT(paddr % PAGE_SIZE == 0);
|
ASSERT(paddr % PAGE_SIZE == 0);
|
||||||
|
@ -377,7 +396,7 @@ namespace Kernel
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
for (size_t page = 0; page < page_count; page++)
|
for (size_t page = 0; page < page_count; page++)
|
||||||
map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags);
|
map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags, memory_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t PageTable::get_page_data(vaddr_t vaddr) const
|
uint64_t PageTable::get_page_data(vaddr_t vaddr) const
|
||||||
|
|
|
@ -56,8 +56,6 @@ namespace Kernel
|
||||||
result |= Flags::Execute;
|
result |= Flags::Execute;
|
||||||
if (entry & Flags::Reserved)
|
if (entry & Flags::Reserved)
|
||||||
result |= Flags::Reserved;
|
result |= Flags::Reserved;
|
||||||
if (entry & Flags::CacheDisable)
|
|
||||||
result |= Flags::CacheDisable;
|
|
||||||
if (entry & Flags::UserSupervisor)
|
if (entry & Flags::UserSupervisor)
|
||||||
result |= Flags::UserSupervisor;
|
result |= Flags::UserSupervisor;
|
||||||
if (entry & Flags::ReadWrite)
|
if (entry & Flags::ReadWrite)
|
||||||
|
@ -106,6 +104,15 @@ namespace Kernel
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 64-bit always has PAT, set PAT4 = WC, PAT5 = WT
|
||||||
|
asm volatile(
|
||||||
|
"movl $0x277, %%ecx;"
|
||||||
|
"rdmsr;"
|
||||||
|
"movw $0x0401, %%dx;"
|
||||||
|
"wrmsr;"
|
||||||
|
::: "eax", "ecx", "edx", "memory"
|
||||||
|
);
|
||||||
|
|
||||||
// enable write protect
|
// enable write protect
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"movq %%cr0, %%rax;"
|
"movq %%cr0, %%rax;"
|
||||||
|
@ -367,7 +374,7 @@ namespace Kernel
|
||||||
unmap_page(page * PAGE_SIZE);
|
unmap_page(page * PAGE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags)
|
void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags, MemoryType memory_type)
|
||||||
{
|
{
|
||||||
ASSERT(vaddr);
|
ASSERT(vaddr);
|
||||||
ASSERT(vaddr != fast_page());
|
ASSERT(vaddr != fast_page());
|
||||||
|
@ -393,8 +400,11 @@ namespace Kernel
|
||||||
extra_flags |= 1ull << 63;
|
extra_flags |= 1ull << 63;
|
||||||
if (flags & Flags::Reserved)
|
if (flags & Flags::Reserved)
|
||||||
extra_flags |= Flags::Reserved;
|
extra_flags |= Flags::Reserved;
|
||||||
if (flags & Flags::CacheDisable)
|
|
||||||
extra_flags |= Flags::CacheDisable;
|
if (memory_type == MemoryType::WriteCombining)
|
||||||
|
extra_flags |= (1ull << 7);
|
||||||
|
if (memory_type == MemoryType::WriteThrough)
|
||||||
|
extra_flags |= (1ull << 7) | (1ull << 3);
|
||||||
|
|
||||||
// NOTE: we add present here, since it has to be available in higher level structures
|
// NOTE: we add present here, since it has to be available in higher level structures
|
||||||
flags_t uwr_flags = (flags & (Flags::UserSupervisor | Flags::ReadWrite)) | Flags::Present;
|
flags_t uwr_flags = (flags & (Flags::UserSupervisor | Flags::ReadWrite)) | Flags::Present;
|
||||||
|
@ -434,7 +444,7 @@ namespace Kernel
|
||||||
invalidate(vaddr);
|
invalidate(vaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags)
|
void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags, MemoryType memory_type)
|
||||||
{
|
{
|
||||||
ASSERT(is_canonical(vaddr));
|
ASSERT(is_canonical(vaddr));
|
||||||
|
|
||||||
|
@ -446,7 +456,7 @@ namespace Kernel
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
for (size_t page = 0; page < page_count; page++)
|
for (size_t page = 0; page < page_count; page++)
|
||||||
map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags);
|
map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags, memory_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t PageTable::get_page_data(vaddr_t vaddr) const
|
uint64_t PageTable::get_page_data(vaddr_t vaddr) const
|
||||||
|
|
|
@ -79,5 +79,6 @@ namespace CPUID
|
||||||
bool is_64_bit();
|
bool is_64_bit();
|
||||||
bool has_nxe();
|
bool has_nxe();
|
||||||
bool has_pge();
|
bool has_pge();
|
||||||
|
bool has_pat();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@ namespace Kernel
|
||||||
void initialize_device_updater();
|
void initialize_device_updater();
|
||||||
|
|
||||||
void add_device(BAN::RefPtr<Device>);
|
void add_device(BAN::RefPtr<Device>);
|
||||||
|
void remove_device(BAN::RefPtr<Device>);
|
||||||
|
|
||||||
void add_inode(BAN::StringView path, BAN::RefPtr<TmpInode>);
|
void add_inode(BAN::StringView path, BAN::RefPtr<TmpInode>);
|
||||||
|
|
||||||
void initiate_sync(bool should_block);
|
void initiate_sync(bool should_block);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
class InputDevice : public CharacterDevice
|
class InputDevice : public CharacterDevice, public BAN::Weakable<InputDevice>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum class Type
|
enum class Type
|
||||||
|
@ -19,6 +19,9 @@ namespace Kernel
|
||||||
public:
|
public:
|
||||||
InputDevice(Type type);
|
InputDevice(Type type);
|
||||||
|
|
||||||
|
BAN::StringView name() const final override { return m_name; }
|
||||||
|
dev_t rdev() const final override { return m_rdev; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void add_event(BAN::ConstByteSpan);
|
void add_event(BAN::ConstByteSpan);
|
||||||
|
|
||||||
|
@ -28,13 +31,16 @@ namespace Kernel
|
||||||
bool can_write_impl() const override { return false; }
|
bool can_write_impl() const override { return false; }
|
||||||
bool has_error_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:
|
||||||
|
BAN::ErrorOr<size_t> read_non_block(BAN::ByteSpan);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const dev_t m_rdev;
|
const dev_t m_rdev;
|
||||||
const BAN::String m_name;
|
const BAN::String m_name;
|
||||||
|
|
||||||
|
const Type m_type;
|
||||||
|
|
||||||
mutable SpinLock m_event_lock;
|
mutable SpinLock m_event_lock;
|
||||||
Semaphore m_event_semaphore;
|
Semaphore m_event_semaphore;
|
||||||
|
|
||||||
|
@ -45,6 +51,63 @@ namespace Kernel
|
||||||
size_t m_event_tail { 0 };
|
size_t m_event_tail { 0 };
|
||||||
size_t m_event_head { 0 };
|
size_t m_event_head { 0 };
|
||||||
size_t m_event_count { 0 };
|
size_t m_event_count { 0 };
|
||||||
|
|
||||||
|
friend class KeyboardDevice;
|
||||||
|
friend class MouseDevice;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class KeyboardDevice : public CharacterDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static BAN::ErrorOr<BAN::RefPtr<KeyboardDevice>> create(mode_t mode, uid_t uid, gid_t gid);
|
||||||
|
|
||||||
|
void notify() { m_semaphore.unblock(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
KeyboardDevice(mode_t mode, uid_t uid, gid_t gid);
|
||||||
|
BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
|
||||||
|
|
||||||
|
bool can_read_impl() const override;
|
||||||
|
bool can_write_impl() const override { return false; }
|
||||||
|
bool has_error_impl() const override { return false; }
|
||||||
|
|
||||||
|
BAN::StringView name() const final override { return m_name; }
|
||||||
|
dev_t rdev() const final override { return m_rdev; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const dev_t m_rdev;
|
||||||
|
const BAN::StringView m_name;
|
||||||
|
Semaphore m_semaphore;
|
||||||
|
|
||||||
|
friend class BAN::RefPtr<KeyboardDevice>;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MouseDevice : public CharacterDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static BAN::ErrorOr<BAN::RefPtr<MouseDevice>> create(mode_t mode, uid_t uid, gid_t gid);
|
||||||
|
|
||||||
|
void notify() { m_semaphore.unblock(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
MouseDevice(mode_t mode, uid_t uid, gid_t gid);
|
||||||
|
BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
|
||||||
|
|
||||||
|
bool can_read_impl() const override;
|
||||||
|
bool can_write_impl() const override { return false; }
|
||||||
|
bool has_error_impl() const override { return false; }
|
||||||
|
|
||||||
|
BAN::StringView name() const final override { return m_name; }
|
||||||
|
dev_t rdev() const final override { return m_rdev; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const dev_t m_rdev;
|
||||||
|
const BAN::StringView m_name;
|
||||||
|
Semaphore m_semaphore;
|
||||||
|
|
||||||
|
friend class BAN::RefPtr<MouseDevice>;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,12 +29,17 @@ namespace Kernel
|
||||||
Present = (1 << 0),
|
Present = (1 << 0),
|
||||||
ReadWrite = (1 << 1),
|
ReadWrite = (1 << 1),
|
||||||
UserSupervisor = (1 << 2),
|
UserSupervisor = (1 << 2),
|
||||||
CacheDisable = (1 << 4),
|
|
||||||
Reserved = (1 << 9),
|
Reserved = (1 << 9),
|
||||||
|
|
||||||
Execute = (1 << 15),
|
Execute = (1 << 15),
|
||||||
Used = Present | Reserved,
|
Used = Present | Reserved,
|
||||||
};
|
};
|
||||||
|
enum MemoryType
|
||||||
|
{
|
||||||
|
Normal,
|
||||||
|
WriteCombining,
|
||||||
|
WriteThrough,
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void initialize();
|
static void initialize();
|
||||||
|
@ -93,8 +98,8 @@ namespace Kernel
|
||||||
void unmap_page(vaddr_t);
|
void unmap_page(vaddr_t);
|
||||||
void unmap_range(vaddr_t, size_t bytes);
|
void unmap_range(vaddr_t, size_t bytes);
|
||||||
|
|
||||||
void map_range_at(paddr_t, vaddr_t, size_t bytes, flags_t);
|
void map_range_at(paddr_t, vaddr_t, size_t bytes, flags_t, MemoryType = MemoryType::Normal);
|
||||||
void map_page_at(paddr_t, vaddr_t, flags_t);
|
void map_page_at(paddr_t, vaddr_t, flags_t, MemoryType = MemoryType::Normal);
|
||||||
|
|
||||||
paddr_t physical_address_of(vaddr_t) const;
|
paddr_t physical_address_of(vaddr_t) const;
|
||||||
flags_t get_page_flags(vaddr_t) const;
|
flags_t get_page_flags(vaddr_t) const;
|
||||||
|
|
|
@ -10,13 +10,20 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
enum class SpeedClass
|
enum class SpeedClass
|
||||||
{
|
{
|
||||||
None,
|
|
||||||
LowSpeed,
|
LowSpeed,
|
||||||
FullSpeed,
|
FullSpeed,
|
||||||
HighSpeed,
|
HighSpeed,
|
||||||
SuperSpeed,
|
SuperSpeed,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class EndpointType
|
||||||
|
{
|
||||||
|
Control = 0b00,
|
||||||
|
Isochronous = 0b01,
|
||||||
|
Bulk = 0b10,
|
||||||
|
Interrupt = 0b11,
|
||||||
|
};
|
||||||
|
|
||||||
enum class DeviceBaseClass : uint8_t
|
enum class DeviceBaseClass : uint8_t
|
||||||
{
|
{
|
||||||
CommunicationAndCDCControl = 0x02,
|
CommunicationAndCDCControl = 0x02,
|
||||||
|
|
|
@ -53,7 +53,9 @@ namespace Kernel
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
USBDevice() = default;
|
USBDevice(USB::SpeedClass speed_class)
|
||||||
|
: m_speed_class(speed_class)
|
||||||
|
{}
|
||||||
virtual ~USBDevice() = default;
|
virtual ~USBDevice() = default;
|
||||||
|
|
||||||
BAN::ErrorOr<void> initialize();
|
BAN::ErrorOr<void> initialize();
|
||||||
|
@ -72,12 +74,14 @@ namespace Kernel
|
||||||
private:
|
private:
|
||||||
BAN::ErrorOr<ConfigurationDescriptor> parse_configuration(size_t index);
|
BAN::ErrorOr<ConfigurationDescriptor> parse_configuration(size_t index);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const USB::SpeedClass m_speed_class;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DeviceDescriptor m_descriptor;
|
DeviceDescriptor m_descriptor;
|
||||||
BAN::UniqPtr<DMARegion> m_dma_buffer;
|
BAN::UniqPtr<DMARegion> m_dma_buffer;
|
||||||
|
|
||||||
// FIXME: support more than one interface from a configuration
|
BAN::Vector<BAN::UniqPtr<USBClassDriver>> m_class_drivers;
|
||||||
BAN::UniqPtr<USBClassDriver> m_class_driver;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ namespace Kernel
|
||||||
uint16_t usage_id;
|
uint16_t usage_id;
|
||||||
Type type;
|
Type type;
|
||||||
|
|
||||||
|
uint8_t report_id;
|
||||||
uint32_t report_count;
|
uint32_t report_count;
|
||||||
uint32_t report_size;
|
uint32_t report_size;
|
||||||
|
|
||||||
|
@ -77,15 +78,17 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<void> initialize();
|
BAN::ErrorOr<void> initialize();
|
||||||
|
|
||||||
void forward_collection_inputs(const USBHID::Collection&, BAN::ConstByteSpan& data, size_t bit_offset);
|
void forward_collection_inputs(const USBHID::Collection&, BAN::Optional<uint8_t> report_id, BAN::ConstByteSpan& data, size_t bit_offset);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
USBDevice& m_device;
|
USBDevice& m_device;
|
||||||
USBDevice::InterfaceDescriptor m_interface;
|
USBDevice::InterfaceDescriptor m_interface;
|
||||||
const uint8_t m_interface_index;
|
const uint8_t m_interface_index;
|
||||||
|
|
||||||
|
bool m_uses_report_id { false };
|
||||||
|
|
||||||
uint8_t m_endpoint_id { 0 };
|
uint8_t m_endpoint_id { 0 };
|
||||||
USBHID::Collection m_collection;
|
BAN::Vector<USBHID::Collection> m_collections;
|
||||||
BAN::RefPtr<USBHIDDevice> m_hid_device;
|
BAN::RefPtr<USBHIDDevice> m_hid_device;
|
||||||
|
|
||||||
friend class BAN::UniqPtr<USBHIDDriver>;
|
friend class BAN::UniqPtr<USBHIDDriver>;
|
||||||
|
|
|
@ -43,11 +43,7 @@ namespace Kernel
|
||||||
BAN::ErrorOr<void> initialize_control_endpoint() override;
|
BAN::ErrorOr<void> initialize_control_endpoint() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
XHCIDevice(XHCIController& controller, uint32_t port_id, uint32_t slot_id)
|
XHCIDevice(XHCIController& controller, uint32_t port_id, uint32_t slot_id);
|
||||||
: m_controller(controller)
|
|
||||||
, m_port_id(port_id)
|
|
||||||
, m_slot_id(slot_id)
|
|
||||||
{}
|
|
||||||
~XHCIDevice();
|
~XHCIDevice();
|
||||||
BAN::ErrorOr<void> update_actual_max_packet_size();
|
BAN::ErrorOr<void> update_actual_max_packet_size();
|
||||||
|
|
||||||
|
@ -55,6 +51,8 @@ namespace Kernel
|
||||||
|
|
||||||
void advance_endpoint_enqueue(Endpoint&, bool chain);
|
void advance_endpoint_enqueue(Endpoint&, bool chain);
|
||||||
|
|
||||||
|
static uint64_t calculate_port_bits_per_second(XHCIController&, uint32_t port_id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr uint32_t m_transfer_ring_trb_count = PAGE_SIZE / sizeof(XHCI::TRB);
|
static constexpr uint32_t m_transfer_ring_trb_count = PAGE_SIZE / sizeof(XHCI::TRB);
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,13 @@ namespace CPUID
|
||||||
return edx & CPUID::EDX_PGE;
|
return edx & CPUID::EDX_PGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool has_pat()
|
||||||
|
{
|
||||||
|
uint32_t ecx, edx;
|
||||||
|
get_features(ecx, edx);
|
||||||
|
return edx & CPUID::EDX_PAT;
|
||||||
|
}
|
||||||
|
|
||||||
const char* feature_string_ecx(uint32_t feat)
|
const char* feature_string_ecx(uint32_t feat)
|
||||||
{
|
{
|
||||||
switch (feat)
|
switch (feat)
|
||||||
|
|
|
@ -68,7 +68,8 @@ namespace Kernel
|
||||||
m_video_memory_paddr & PAGE_ADDR_MASK,
|
m_video_memory_paddr & PAGE_ADDR_MASK,
|
||||||
m_video_memory_vaddr,
|
m_video_memory_vaddr,
|
||||||
video_memory_pages * PAGE_SIZE,
|
video_memory_pages * PAGE_SIZE,
|
||||||
PageTable::Flags::ReadWrite | PageTable::Flags::Present
|
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
||||||
|
PageTable::WriteCombining
|
||||||
);
|
);
|
||||||
|
|
||||||
m_video_buffer = TRY(VirtualRange::create_to_vaddr_range(
|
m_video_buffer = TRY(VirtualRange::create_to_vaddr_range(
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <kernel/Device/ZeroDevice.h>
|
#include <kernel/Device/ZeroDevice.h>
|
||||||
#include <kernel/FS/DevFS/FileSystem.h>
|
#include <kernel/FS/DevFS/FileSystem.h>
|
||||||
#include <kernel/FS/TmpFS/Inode.h>
|
#include <kernel/FS/TmpFS/Inode.h>
|
||||||
|
#include <kernel/Input/InputDevice.h>
|
||||||
#include <kernel/Lock/LockGuard.h>
|
#include <kernel/Lock/LockGuard.h>
|
||||||
#include <kernel/Process.h>
|
#include <kernel/Process.h>
|
||||||
#include <kernel/Scheduler.h>
|
#include <kernel/Scheduler.h>
|
||||||
|
@ -26,6 +27,8 @@ namespace Kernel
|
||||||
s_instance->add_device(MUST(DebugDevice::create(0666, 0, 0)));
|
s_instance->add_device(MUST(DebugDevice::create(0666, 0, 0)));
|
||||||
s_instance->add_device(MUST(NullDevice::create(0666, 0, 0)));
|
s_instance->add_device(MUST(NullDevice::create(0666, 0, 0)));
|
||||||
s_instance->add_device(MUST(ZeroDevice::create(0666, 0, 0)));
|
s_instance->add_device(MUST(ZeroDevice::create(0666, 0, 0)));
|
||||||
|
s_instance->add_device(MUST(KeyboardDevice::create(0440, 0, 901)));
|
||||||
|
s_instance->add_device(MUST(MouseDevice::create(0440, 0, 901)));
|
||||||
}
|
}
|
||||||
|
|
||||||
DevFileSystem& DevFileSystem::get()
|
DevFileSystem& DevFileSystem::get()
|
||||||
|
@ -112,6 +115,21 @@ namespace Kernel
|
||||||
MUST(m_devices.push_back(device));
|
MUST(m_devices.push_back(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DevFileSystem::remove_device(BAN::RefPtr<Device> device)
|
||||||
|
{
|
||||||
|
LockGuard _(m_device_lock);
|
||||||
|
ASSERT(!device->name().contains('/'));
|
||||||
|
MUST(static_cast<TmpDirectoryInode*>(root_inode().ptr())->unlink(device->name()));
|
||||||
|
for (size_t i = 0; i < m_devices.size(); i++)
|
||||||
|
{
|
||||||
|
if (m_devices[i] == device)
|
||||||
|
{
|
||||||
|
m_devices.remove(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DevFileSystem::add_inode(BAN::StringView path, BAN::RefPtr<TmpInode> inode)
|
void DevFileSystem::add_inode(BAN::StringView path, BAN::RefPtr<TmpInode> inode)
|
||||||
{
|
{
|
||||||
ASSERT(!inode->is_device());
|
ASSERT(!inode->is_device());
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include <kernel/Device/DeviceNumbers.h>
|
#include <kernel/Device/DeviceNumbers.h>
|
||||||
|
#include <kernel/FS/DevFS/FileSystem.h>
|
||||||
#include <kernel/Input/InputDevice.h>
|
#include <kernel/Input/InputDevice.h>
|
||||||
#include <kernel/Lock/LockGuard.h>
|
#include <kernel/Lock/LockGuard.h>
|
||||||
|
|
||||||
|
@ -10,8 +11,11 @@
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
static BAN::Atomic<uint16_t> s_next_keyboard { 0 };
|
static BAN::Vector<BAN::WeakPtr<InputDevice>> s_keyboards;
|
||||||
static BAN::Atomic<uint16_t> s_next_mouse { 0 };
|
static BAN::RefPtr<KeyboardDevice> s_keyboard_device;
|
||||||
|
|
||||||
|
static BAN::Vector<BAN::WeakPtr<InputDevice>> s_mice;
|
||||||
|
static BAN::RefPtr<MouseDevice> s_mouse_device;
|
||||||
|
|
||||||
static const char* get_name_format(InputDevice::Type type)
|
static const char* get_name_format(InputDevice::Type type)
|
||||||
{
|
{
|
||||||
|
@ -30,9 +34,15 @@ namespace Kernel
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case InputDevice::Type::Keyboard:
|
case InputDevice::Type::Keyboard:
|
||||||
return makedev(DeviceNumber::Keyboard, s_next_keyboard++);
|
for (size_t i = 0; i < s_keyboards.size(); i++)
|
||||||
|
if (!s_keyboards[i].valid())
|
||||||
|
return makedev(DeviceNumber::Keyboard, i + 1);
|
||||||
|
return makedev(DeviceNumber::Keyboard, s_keyboards.size() + 1);
|
||||||
case InputDevice::Type::Mouse:
|
case InputDevice::Type::Mouse:
|
||||||
return makedev(DeviceNumber::Mouse, s_next_mouse++);
|
for (size_t i = 0; i < s_mice.size(); i++)
|
||||||
|
if (!s_mice[i].valid())
|
||||||
|
return makedev(DeviceNumber::Mouse, i + 1);
|
||||||
|
return makedev(DeviceNumber::Mouse, s_mice.size() + 1);
|
||||||
}
|
}
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
@ -52,10 +62,25 @@ namespace Kernel
|
||||||
InputDevice::InputDevice(Type type)
|
InputDevice::InputDevice(Type type)
|
||||||
: CharacterDevice(0440, 0, 901)
|
: CharacterDevice(0440, 0, 901)
|
||||||
, m_rdev(get_rdev(type))
|
, m_rdev(get_rdev(type))
|
||||||
, m_name(MUST(BAN::String::formatted(get_name_format(type), minor(m_rdev))))
|
, m_name(MUST(BAN::String::formatted(get_name_format(type), minor(m_rdev) - 1)))
|
||||||
|
, m_type(type)
|
||||||
, m_event_size(get_event_size(type))
|
, m_event_size(get_event_size(type))
|
||||||
{
|
{
|
||||||
MUST(m_event_buffer.resize(m_event_size * m_max_event_count, 0));
|
MUST(m_event_buffer.resize(m_event_size * m_max_event_count, 0));
|
||||||
|
|
||||||
|
if (m_type == Type::Keyboard)
|
||||||
|
{
|
||||||
|
if (s_keyboards.size() < minor(m_rdev))
|
||||||
|
MUST(s_keyboards.resize(minor(m_rdev)));
|
||||||
|
s_keyboards[minor(m_rdev) - 1] = MUST(get_weak_ptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_type == Type::Mouse)
|
||||||
|
{
|
||||||
|
if (s_mice.size() < minor(m_rdev))
|
||||||
|
MUST(s_mice.resize(minor(m_rdev)));
|
||||||
|
s_mice[minor(m_rdev) - 1] = MUST(get_weak_ptr());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputDevice::add_event(BAN::ConstByteSpan event)
|
void InputDevice::add_event(BAN::ConstByteSpan event)
|
||||||
|
@ -63,6 +88,25 @@ namespace Kernel
|
||||||
SpinLockGuard _(m_event_lock);
|
SpinLockGuard _(m_event_lock);
|
||||||
ASSERT(event.size() == m_event_size);
|
ASSERT(event.size() == m_event_size);
|
||||||
|
|
||||||
|
if (m_type == Type::Mouse && m_event_count > 0)
|
||||||
|
{
|
||||||
|
const size_t last_index = (m_event_head + m_max_event_count - 1) % m_max_event_count;
|
||||||
|
|
||||||
|
auto& last_event = *reinterpret_cast<LibInput::MouseEvent*>(&m_event_buffer[last_index * m_event_size]);
|
||||||
|
auto& curr_event = event.as<const LibInput::MouseEvent>();
|
||||||
|
if (last_event.type == LibInput::MouseEventType::MouseMoveEvent && curr_event.type == LibInput::MouseEventType::MouseMoveEvent)
|
||||||
|
{
|
||||||
|
last_event.move_event.rel_x += curr_event.move_event.rel_x;
|
||||||
|
last_event.move_event.rel_y += curr_event.move_event.rel_y;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (last_event.type == LibInput::MouseEventType::MouseScrollEvent && curr_event.type == LibInput::MouseEventType::MouseScrollEvent)
|
||||||
|
{
|
||||||
|
last_event.scroll_event.scroll += curr_event.scroll_event.scroll;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (m_event_count == m_max_event_count)
|
if (m_event_count == m_max_event_count)
|
||||||
{
|
{
|
||||||
m_event_tail = (m_event_tail + 1) % m_max_event_count;
|
m_event_tail = (m_event_tail + 1) % m_max_event_count;
|
||||||
|
@ -74,6 +118,10 @@ namespace Kernel
|
||||||
m_event_count++;
|
m_event_count++;
|
||||||
|
|
||||||
m_event_semaphore.unblock();
|
m_event_semaphore.unblock();
|
||||||
|
if (m_type == Type::Keyboard && s_keyboard_device)
|
||||||
|
s_keyboard_device->notify();
|
||||||
|
if (m_type == Type::Mouse && s_mouse_device)
|
||||||
|
s_mouse_device->notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<size_t> InputDevice::read_impl(off_t, BAN::ByteSpan buffer)
|
BAN::ErrorOr<size_t> InputDevice::read_impl(off_t, BAN::ByteSpan buffer)
|
||||||
|
@ -101,4 +149,113 @@ namespace Kernel
|
||||||
return m_event_size;
|
return m_event_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<size_t> InputDevice::read_non_block(BAN::ByteSpan buffer)
|
||||||
|
{
|
||||||
|
if (buffer.size() < m_event_size)
|
||||||
|
return BAN::Error::from_errno(ENOBUFS);
|
||||||
|
|
||||||
|
SpinLockGuard _(m_event_lock);
|
||||||
|
|
||||||
|
if (m_event_count == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
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--;
|
||||||
|
|
||||||
|
return m_event_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
BAN::ErrorOr<BAN::RefPtr<KeyboardDevice>> KeyboardDevice::create(mode_t mode, uid_t uid, gid_t gid)
|
||||||
|
{
|
||||||
|
s_keyboard_device = TRY(BAN::RefPtr<KeyboardDevice>::create(mode, uid, gid));
|
||||||
|
return s_keyboard_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyboardDevice::KeyboardDevice(mode_t mode, uid_t uid, gid_t gid)
|
||||||
|
: CharacterDevice(mode, uid, gid)
|
||||||
|
, m_rdev(makedev(DeviceNumber::Keyboard, 0))
|
||||||
|
, m_name("keyboard"_sv)
|
||||||
|
{}
|
||||||
|
|
||||||
|
BAN::ErrorOr<size_t> KeyboardDevice::read_impl(off_t, BAN::ByteSpan buffer)
|
||||||
|
{
|
||||||
|
if (buffer.size() < sizeof(LibInput::RawKeyEvent))
|
||||||
|
return BAN::Error::from_errno(ENOBUFS);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
for (auto& weak_keyboard : s_keyboards)
|
||||||
|
{
|
||||||
|
auto keyboard = weak_keyboard.lock();
|
||||||
|
if (!keyboard)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto bytes = TRY(keyboard->read_non_block(buffer));
|
||||||
|
if (bytes > 0)
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
LockFreeGuard _(m_mutex);
|
||||||
|
TRY(Thread::current().block_or_eintr_indefinite(m_semaphore));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KeyboardDevice::can_read_impl() const
|
||||||
|
{
|
||||||
|
for (auto& weak_keyboard : s_keyboards)
|
||||||
|
if (auto keyboard = weak_keyboard.lock())
|
||||||
|
if (keyboard->can_read())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
BAN::ErrorOr<BAN::RefPtr<MouseDevice>> MouseDevice::create(mode_t mode, uid_t uid, gid_t gid)
|
||||||
|
{
|
||||||
|
s_mouse_device = TRY(BAN::RefPtr<MouseDevice>::create(mode, uid, gid));
|
||||||
|
return s_mouse_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseDevice::MouseDevice(mode_t mode, uid_t uid, gid_t gid)
|
||||||
|
: CharacterDevice(mode, uid, gid)
|
||||||
|
, m_rdev(makedev(DeviceNumber::Mouse, 0))
|
||||||
|
, m_name("mouse"_sv)
|
||||||
|
{}
|
||||||
|
|
||||||
|
BAN::ErrorOr<size_t> MouseDevice::read_impl(off_t, BAN::ByteSpan buffer)
|
||||||
|
{
|
||||||
|
if (buffer.size() < sizeof(LibInput::MouseEvent))
|
||||||
|
return BAN::Error::from_errno(ENOBUFS);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
for (auto& weak_mouse : s_mice)
|
||||||
|
{
|
||||||
|
auto mouse = weak_mouse.lock();
|
||||||
|
if (!mouse)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto bytes = TRY(mouse->read_non_block(buffer));
|
||||||
|
if (bytes > 0)
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
LockFreeGuard _(m_mutex);
|
||||||
|
TRY(Thread::current().block_or_eintr_indefinite(m_semaphore));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MouseDevice::can_read_impl() const
|
||||||
|
{
|
||||||
|
for (auto& weak_mouse : s_mice)
|
||||||
|
if (auto mouse = weak_mouse.lock())
|
||||||
|
if (mouse->can_read())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ namespace Kernel
|
||||||
vaddr_guard.disable();
|
vaddr_guard.disable();
|
||||||
paddr_guard.disable();
|
paddr_guard.disable();
|
||||||
|
|
||||||
PageTable::kernel().map_range_at(paddr, vaddr, size, PageTable::Flags::CacheDisable | PageTable::Flags::ReadWrite | PageTable::Flags::Present);
|
PageTable::kernel().map_range_at(paddr, vaddr, size, PageTable::Flags::ReadWrite | PageTable::Flags::Present);
|
||||||
|
|
||||||
return BAN::UniqPtr<DMARegion>::adopt(region_ptr);
|
return BAN::UniqPtr<DMARegion>::adopt(region_ptr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -652,7 +652,8 @@ namespace Kernel::PCI
|
||||||
m_vaddr = PageTable::kernel().reserve_free_contiguous_pages(needed_pages, KERNEL_OFFSET);
|
m_vaddr = PageTable::kernel().reserve_free_contiguous_pages(needed_pages, KERNEL_OFFSET);
|
||||||
if (m_vaddr == 0)
|
if (m_vaddr == 0)
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
PageTable::kernel().map_range_at(m_paddr, m_vaddr, m_size, PageTable::Flags::CacheDisable | PageTable::Flags::ReadWrite | PageTable::Flags::Present);
|
|
||||||
|
PageTable::kernel().map_range_at(m_paddr, m_vaddr, m_size, PageTable::Flags::ReadWrite | PageTable::Flags::Present);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,10 +83,10 @@ namespace Kernel
|
||||||
Process::create_kernel(
|
Process::create_kernel(
|
||||||
[](void*)
|
[](void*)
|
||||||
{
|
{
|
||||||
auto file_or_error = VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, "/dev/keyboard0"_sv, O_RDONLY);
|
auto file_or_error = VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, "/dev/keyboard"_sv, O_RDONLY);
|
||||||
if (file_or_error.is_error())
|
if (file_or_error.is_error())
|
||||||
{
|
{
|
||||||
dprintln("no input device found");
|
dprintln("no keyboard found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -154,7 +154,7 @@ namespace Kernel
|
||||||
break;
|
break;
|
||||||
case USB::InterfaceBaseClass::HID:
|
case USB::InterfaceBaseClass::HID:
|
||||||
if (auto result = USBHIDDriver::create(*this, interface, j); !result.is_error())
|
if (auto result = USBHIDDriver::create(*this, interface, j); !result.is_error())
|
||||||
m_class_driver = result.release_value();
|
TRY(m_class_drivers.push_back(result.release_value()));
|
||||||
break;
|
break;
|
||||||
case USB::InterfaceBaseClass::Physical:
|
case USB::InterfaceBaseClass::Physical:
|
||||||
dprintln_if(DEBUG_USB, "Found Physical interface");
|
dprintln_if(DEBUG_USB, "Found Physical interface");
|
||||||
|
@ -218,7 +218,7 @@ namespace Kernel
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_class_driver)
|
if (!m_class_drivers.empty())
|
||||||
{
|
{
|
||||||
dprintln("Successfully initialized USB interface");
|
dprintln("Successfully initialized USB interface");
|
||||||
return {};
|
return {};
|
||||||
|
@ -309,8 +309,8 @@ namespace Kernel
|
||||||
|
|
||||||
void USBDevice::handle_input_data(BAN::ConstByteSpan data, uint8_t endpoint_id)
|
void USBDevice::handle_input_data(BAN::ConstByteSpan data, uint8_t endpoint_id)
|
||||||
{
|
{
|
||||||
if (m_class_driver)
|
for (auto& driver : m_class_drivers)
|
||||||
m_class_driver->handle_input_data(data, endpoint_id);
|
driver->handle_input_data(data, endpoint_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
USB::SpeedClass USBDevice::determine_speed_class(uint64_t bits_per_second)
|
USB::SpeedClass USBDevice::determine_speed_class(uint64_t bits_per_second)
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <kernel/USB/HID/Mouse.h>
|
#include <kernel/USB/HID/Mouse.h>
|
||||||
|
|
||||||
#define DEBUG_HID 0
|
#define DEBUG_HID 0
|
||||||
|
#define DUMP_HID_REPORT 0
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
@ -42,8 +43,8 @@ namespace Kernel
|
||||||
BAN::Optional<int32_t> physical_minimum;
|
BAN::Optional<int32_t> physical_minimum;
|
||||||
BAN::Optional<int32_t> physical_maximum;
|
BAN::Optional<int32_t> physical_maximum;
|
||||||
// FIXME: support units
|
// FIXME: support units
|
||||||
|
BAN::Optional<uint8_t> report_id;
|
||||||
BAN::Optional<uint32_t> report_size;
|
BAN::Optional<uint32_t> report_size;
|
||||||
// FIXME: support report id
|
|
||||||
BAN::Optional<uint32_t> report_count;
|
BAN::Optional<uint32_t> report_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -57,11 +58,11 @@ namespace Kernel
|
||||||
|
|
||||||
using namespace USBHID;
|
using namespace USBHID;
|
||||||
|
|
||||||
#if DEBUG_HID
|
#if DUMP_HID_REPORT
|
||||||
static void dump_hid_collection(const Collection& collection, size_t indent);
|
static void dump_hid_collection(const Collection& collection, size_t indent, bool use_report_id);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static BAN::ErrorOr<Collection> parse_report_descriptor(BAN::ConstByteSpan report_data);
|
static BAN::ErrorOr<BAN::Vector<Collection>> parse_report_descriptor(BAN::ConstByteSpan report_data, bool& out_use_report_id);
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::UniqPtr<USBHIDDriver>> USBHIDDriver::create(USBDevice& device, const USBDevice::InterfaceDescriptor& interface, uint8_t interface_index)
|
BAN::ErrorOr<BAN::UniqPtr<USBHIDDriver>> USBHIDDriver::create(USBDevice& device, const USBDevice::InterfaceDescriptor& interface, uint8_t interface_index)
|
||||||
{
|
{
|
||||||
|
@ -77,7 +78,10 @@ namespace Kernel
|
||||||
{}
|
{}
|
||||||
|
|
||||||
USBHIDDriver::~USBHIDDriver()
|
USBHIDDriver::~USBHIDDriver()
|
||||||
{}
|
{
|
||||||
|
if (m_hid_device)
|
||||||
|
DevFileSystem::get().remove_device(m_hid_device);
|
||||||
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> USBHIDDriver::initialize()
|
BAN::ErrorOr<void> USBHIDDriver::initialize()
|
||||||
{
|
{
|
||||||
|
@ -143,7 +147,6 @@ namespace Kernel
|
||||||
TRY(m_device.send_request(request, 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());
|
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, "HID descriptor ({} bytes)", m_interface.misc_descriptors[hid_descriptor_index].size());
|
||||||
|
@ -153,7 +156,7 @@ namespace Kernel
|
||||||
dprintln_if(DEBUG_HID, " bCountryCode: {}", hid_descriptor.bCountryCode);
|
dprintln_if(DEBUG_HID, " bCountryCode: {}", hid_descriptor.bCountryCode);
|
||||||
dprintln_if(DEBUG_HID, " bNumDescriptors: {}", hid_descriptor.bNumDescriptors);
|
dprintln_if(DEBUG_HID, " bNumDescriptors: {}", hid_descriptor.bNumDescriptors);
|
||||||
|
|
||||||
bool report_descriptor_parsed = false;
|
BAN::Vector<Collection> collections;
|
||||||
for (size_t i = 0; i < hid_descriptor.bNumDescriptors; i++)
|
for (size_t i = 0; i < hid_descriptor.bNumDescriptors; i++)
|
||||||
{
|
{
|
||||||
auto descriptor = hid_descriptor.descriptors[i];
|
auto descriptor = hid_descriptor.descriptors[i];
|
||||||
|
@ -163,11 +166,6 @@ namespace Kernel
|
||||||
dprintln_if(DEBUG_HID, "Skipping HID descriptor type 0x{2H}", descriptor.bDescriptorType);
|
dprintln_if(DEBUG_HID, "Skipping HID descriptor type 0x{2H}", descriptor.bDescriptorType);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (report_descriptor_parsed)
|
|
||||||
{
|
|
||||||
dwarnln("Multiple report descriptors specified");
|
|
||||||
return BAN::Error::from_errno(ENOTSUP);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (descriptor.wItemLength > dma_buffer->size())
|
if (descriptor.wItemLength > dma_buffer->size())
|
||||||
{
|
{
|
||||||
|
@ -194,40 +192,37 @@ namespace Kernel
|
||||||
dprintln_if(DEBUG_HID, "Parsing {} byte report descriptor", +descriptor.wItemLength);
|
dprintln_if(DEBUG_HID, "Parsing {} byte report descriptor", +descriptor.wItemLength);
|
||||||
|
|
||||||
auto report_data = BAN::ConstByteSpan(reinterpret_cast<uint8_t*>(dma_buffer->vaddr()), descriptor.wItemLength);
|
auto report_data = BAN::ConstByteSpan(reinterpret_cast<uint8_t*>(dma_buffer->vaddr()), descriptor.wItemLength);
|
||||||
collection = TRY(parse_report_descriptor(report_data));
|
auto new_collections = TRY(parse_report_descriptor(report_data, m_uses_report_id));
|
||||||
|
for (auto& collection : new_collections)
|
||||||
report_descriptor_parsed = true;
|
TRY(collections.push_back(BAN::move(collection)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!report_descriptor_parsed)
|
if (collections.empty())
|
||||||
{
|
{
|
||||||
dwarnln("No report descriptors specified");
|
dwarnln("No collections specified for HID device");
|
||||||
return BAN::Error::from_errno(EFAULT);
|
return BAN::Error::from_errno(EFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (collection.usage_page != 0x01)
|
// FIXME: Handle other collections?
|
||||||
|
|
||||||
|
if (collections.front().usage_page != 0x01)
|
||||||
{
|
{
|
||||||
dwarnln("Top most collection is not generic desktop page");
|
dwarnln("Top most collection is not generic desktop page");
|
||||||
return BAN::Error::from_errno(EFAULT);
|
return BAN::Error::from_errno(EFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG_HID
|
switch (collections.front().usage_id)
|
||||||
{
|
|
||||||
SpinLockGuard _(Debug::s_debug_lock);
|
|
||||||
dump_hid_collection(collection, 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
switch (collection.usage_id)
|
|
||||||
{
|
{
|
||||||
case 0x02:
|
case 0x02:
|
||||||
m_hid_device = TRY(BAN::RefPtr<USBMouse>::create());
|
m_hid_device = TRY(BAN::RefPtr<USBMouse>::create());
|
||||||
|
dprintln("Initialized an USB Mouse");
|
||||||
break;
|
break;
|
||||||
case 0x06:
|
case 0x06:
|
||||||
m_hid_device = TRY(BAN::RefPtr<USBKeyboard>::create());
|
m_hid_device = TRY(BAN::RefPtr<USBKeyboard>::create());
|
||||||
|
dprintln("Initialized an USB Keyboard");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dwarnln("Unsupported generic descript page usage 0x{2H}", collection.usage_id);
|
dwarnln("Unsupported generic descript page usage 0x{2H}", collections.front().usage_id);
|
||||||
return BAN::Error::from_errno(ENOTSUP);
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
}
|
}
|
||||||
DevFileSystem::get().add_device(m_hid_device);
|
DevFileSystem::get().add_device(m_hid_device);
|
||||||
|
@ -235,14 +230,14 @@ namespace Kernel
|
||||||
const auto& endpoint_descriptor = m_interface.endpoints[endpoint_index].descriptor;
|
const auto& endpoint_descriptor = m_interface.endpoints[endpoint_index].descriptor;
|
||||||
|
|
||||||
m_endpoint_id = (endpoint_descriptor.bEndpointAddress & 0x0F) * 2 + !!(endpoint_descriptor.bEndpointAddress & 0x80);
|
m_endpoint_id = (endpoint_descriptor.bEndpointAddress & 0x0F) * 2 + !!(endpoint_descriptor.bEndpointAddress & 0x80);
|
||||||
m_collection = BAN::move(collection);
|
m_collections = BAN::move(collections);
|
||||||
|
|
||||||
TRY(m_device.initialize_endpoint(endpoint_descriptor));
|
TRY(m_device.initialize_endpoint(endpoint_descriptor));
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBHIDDriver::forward_collection_inputs(const Collection& collection, BAN::ConstByteSpan& data, size_t bit_offset)
|
void USBHIDDriver::forward_collection_inputs(const Collection& collection, BAN::Optional<uint8_t> report_id, BAN::ConstByteSpan& data, size_t bit_offset)
|
||||||
{
|
{
|
||||||
const auto extract_bits =
|
const auto extract_bits =
|
||||||
[data](size_t bit_offset, size_t bit_count, bool as_unsigned) -> int64_t
|
[data](size_t bit_offset, size_t bit_count, bool as_unsigned) -> int64_t
|
||||||
|
@ -281,7 +276,7 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
if (entry.has<Collection>())
|
if (entry.has<Collection>())
|
||||||
{
|
{
|
||||||
forward_collection_inputs(entry.get<Collection>(), data, bit_offset);
|
forward_collection_inputs(entry.get<Collection>(), report_id, data, bit_offset);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,6 +284,8 @@ namespace Kernel
|
||||||
const auto& input = entry.get<Report>();
|
const auto& input = entry.get<Report>();
|
||||||
if (input.type != Report::Type::Input)
|
if (input.type != Report::Type::Input)
|
||||||
continue;
|
continue;
|
||||||
|
if (report_id.value_or(input.report_id) != input.report_id)
|
||||||
|
continue;
|
||||||
|
|
||||||
ASSERT(input.report_size <= 32);
|
ASSERT(input.report_size <= 32);
|
||||||
|
|
||||||
|
@ -326,7 +323,9 @@ namespace Kernel
|
||||||
|
|
||||||
void USBHIDDriver::handle_input_data(BAN::ConstByteSpan data, uint8_t endpoint_id)
|
void USBHIDDriver::handle_input_data(BAN::ConstByteSpan data, uint8_t endpoint_id)
|
||||||
{
|
{
|
||||||
ASSERT(m_endpoint_id == endpoint_id);
|
// If this packet is not for us, skip it
|
||||||
|
if (m_endpoint_id != endpoint_id)
|
||||||
|
return;
|
||||||
|
|
||||||
if constexpr(DEBUG_HID)
|
if constexpr(DEBUG_HID)
|
||||||
{
|
{
|
||||||
|
@ -345,21 +344,32 @@ namespace Kernel
|
||||||
dprintln_if(DEBUG_HID, "Received {} bytes from endpoint {}: {}", data.size(), endpoint_id, buffer);
|
dprintln_if(DEBUG_HID, "Received {} bytes from endpoint {}: {}", data.size(), endpoint_id, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::Optional<uint8_t> report_id;
|
||||||
|
if (m_uses_report_id)
|
||||||
|
{
|
||||||
|
report_id = data[0];
|
||||||
|
data = data.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
m_hid_device->start_report();
|
m_hid_device->start_report();
|
||||||
forward_collection_inputs(m_collection, data, 0);
|
// FIXME: Handle other collections?
|
||||||
|
forward_collection_inputs(m_collections.front(), report_id, data, 0);
|
||||||
m_hid_device->stop_report();
|
m_hid_device->stop_report();
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<Collection> parse_report_descriptor(BAN::ConstByteSpan report_data)
|
BAN::ErrorOr<BAN::Vector<Collection>> parse_report_descriptor(BAN::ConstByteSpan report_data, bool& out_use_report_id)
|
||||||
{
|
{
|
||||||
BAN::Vector<GlobalState> global_stack;
|
BAN::Vector<GlobalState> global_stack;
|
||||||
GlobalState global_state;
|
GlobalState global_state;
|
||||||
|
|
||||||
LocalState local_state;
|
LocalState local_state;
|
||||||
|
|
||||||
BAN::Optional<Collection> result;
|
BAN::Vector<Collection> result_stack;
|
||||||
BAN::Vector<Collection> collection_stack;
|
BAN::Vector<Collection> collection_stack;
|
||||||
|
|
||||||
|
bool one_has_report_id = false;
|
||||||
|
bool all_has_report_id = true;
|
||||||
|
|
||||||
const auto extract_report_item =
|
const auto extract_report_item =
|
||||||
[&](bool as_unsigned) -> int64_t
|
[&](bool as_unsigned) -> int64_t
|
||||||
{
|
{
|
||||||
|
@ -411,6 +421,11 @@ namespace Kernel
|
||||||
return BAN::Error::from_errno(EFAULT);
|
return BAN::Error::from_errno(EFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (global_state.report_id.has_value())
|
||||||
|
one_has_report_id = true;
|
||||||
|
else
|
||||||
|
all_has_report_id = false;
|
||||||
|
|
||||||
const int64_t logical_minimum = global_state.logical_minimum.value();
|
const int64_t logical_minimum = global_state.logical_minimum.value();
|
||||||
const int64_t logical_maximum = get_correct_sign(
|
const int64_t logical_maximum = get_correct_sign(
|
||||||
global_state.logical_minimum.value(),
|
global_state.logical_minimum.value(),
|
||||||
|
@ -436,6 +451,7 @@ namespace Kernel
|
||||||
item.usage_minimum = local_state.usage_minimum.value();
|
item.usage_minimum = local_state.usage_minimum.value();
|
||||||
item.usage_maximum = local_state.usage_maximum.value();
|
item.usage_maximum = local_state.usage_maximum.value();
|
||||||
item.type = type;
|
item.type = type;
|
||||||
|
item.report_id = global_state.report_id.value_or(0);
|
||||||
item.report_count = global_state.report_count.value();
|
item.report_count = global_state.report_count.value();
|
||||||
item.report_size = global_state.report_size.value();
|
item.report_size = global_state.report_size.value();
|
||||||
item.logical_minimum = logical_minimum;
|
item.logical_minimum = logical_minimum;
|
||||||
|
@ -454,6 +470,7 @@ namespace Kernel
|
||||||
item.usage_minimum = 0;
|
item.usage_minimum = 0;
|
||||||
item.usage_maximum = 0;
|
item.usage_maximum = 0;
|
||||||
item.type = type;
|
item.type = type;
|
||||||
|
item.report_id = global_state.report_id.value_or(0);
|
||||||
item.report_count = global_state.report_count.value();
|
item.report_count = global_state.report_count.value();
|
||||||
item.report_size = global_state.report_size.value();
|
item.report_size = global_state.report_size.value();
|
||||||
item.logical_minimum = 0;
|
item.logical_minimum = 0;
|
||||||
|
@ -466,9 +483,10 @@ namespace Kernel
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < global_state.report_count.value(); i++)
|
for (size_t i = 0; i < local_state.usage_stack.size(); i++)
|
||||||
{
|
{
|
||||||
const uint32_t usage = local_state.usage_stack[BAN::Math::min<size_t>(i, local_state.usage_stack.size() - 1)];
|
const uint32_t usage = local_state.usage_stack[i];
|
||||||
|
const uint32_t count = (i + 1 < local_state.usage_stack.size()) ? 1 : global_state.report_count.value() - i;
|
||||||
|
|
||||||
Report item;
|
Report item;
|
||||||
item.usage_page = (usage >> 16) ? (usage >> 16) : global_state.usage_page.value();
|
item.usage_page = (usage >> 16) ? (usage >> 16) : global_state.usage_page.value();
|
||||||
|
@ -476,7 +494,8 @@ namespace Kernel
|
||||||
item.usage_minimum = 0;
|
item.usage_minimum = 0;
|
||||||
item.usage_maximum = 0;
|
item.usage_maximum = 0;
|
||||||
item.type = type;
|
item.type = type;
|
||||||
item.report_count = 1;
|
item.report_id = global_state.report_id.value_or(0);
|
||||||
|
item.report_count = count;
|
||||||
item.report_size = global_state.report_size.value();
|
item.report_size = global_state.report_size.value();
|
||||||
item.logical_minimum = logical_minimum;
|
item.logical_minimum = logical_minimum;
|
||||||
item.logical_maximum = logical_maximum;
|
item.logical_maximum = logical_maximum;
|
||||||
|
@ -554,12 +573,7 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
if (collection_stack.size() == 1)
|
if (collection_stack.size() == 1)
|
||||||
{
|
{
|
||||||
if (result.has_value())
|
TRY(result_stack.push_back(BAN::move(collection_stack.back())));
|
||||||
{
|
|
||||||
dwarnln("Multiple top-level collections not supported");
|
|
||||||
return BAN::Error::from_errno(ENOTSUP);
|
|
||||||
}
|
|
||||||
result = BAN::move(collection_stack.back());
|
|
||||||
collection_stack.pop_back();
|
collection_stack.pop_back();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -605,8 +619,16 @@ namespace Kernel
|
||||||
global_state.report_size = extract_report_item(true);
|
global_state.report_size = extract_report_item(true);
|
||||||
break;
|
break;
|
||||||
case 0b1000: // report id
|
case 0b1000: // report id
|
||||||
dwarnln("Report IDs are not supported");
|
{
|
||||||
return BAN::Error::from_errno(ENOTSUP);
|
auto report_id = extract_report_item(true);
|
||||||
|
if (report_id > 0xFF)
|
||||||
|
{
|
||||||
|
dwarnln("Multi-byte report id");
|
||||||
|
return BAN::Error::from_errno(EFAULT);
|
||||||
|
}
|
||||||
|
global_state.report_id = report_id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 0b1001: // report count
|
case 0b1001: // report count
|
||||||
global_state.report_count = extract_report_item(true);
|
global_state.report_count = extract_report_item(true);
|
||||||
break;
|
break;
|
||||||
|
@ -663,23 +685,38 @@ namespace Kernel
|
||||||
report_data = report_data.slice(1 + item_size);
|
report_data = report_data.slice(1 + item_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result.has_value())
|
if (result_stack.empty())
|
||||||
{
|
{
|
||||||
dwarnln("No collection defined in report descriptor");
|
dwarnln("No collection defined in report descriptor");
|
||||||
return BAN::Error::from_errno(EFAULT);
|
return BAN::Error::from_errno(EFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.release_value();
|
if (one_has_report_id != all_has_report_id)
|
||||||
|
{
|
||||||
|
dwarnln("Some but not all reports have report id");
|
||||||
|
return BAN::Error::from_errno(EFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DUMP_HID_REPORT
|
||||||
|
{
|
||||||
|
SpinLockGuard _(Debug::s_debug_lock);
|
||||||
|
for (const auto& collection : result_stack)
|
||||||
|
dump_hid_collection(collection, 0, one_has_report_id);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
out_use_report_id = one_has_report_id;
|
||||||
|
return BAN::move(result_stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG_HID
|
#if DUMP_HID_REPORT
|
||||||
static void print_indent(size_t indent)
|
static void print_indent(size_t indent)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < indent; i++)
|
for (size_t i = 0; i < indent; i++)
|
||||||
Debug::putchar(' ');
|
Debug::putchar(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_hid_report(const Report& report, size_t indent)
|
static void dump_hid_report(const Report& report, size_t indent, bool use_report_id)
|
||||||
{
|
{
|
||||||
const char* report_type = "";
|
const char* report_type = "";
|
||||||
switch (report.type)
|
switch (report.type)
|
||||||
|
@ -691,6 +728,12 @@ namespace Kernel
|
||||||
print_indent(indent);
|
print_indent(indent);
|
||||||
BAN::Formatter::println(Debug::putchar, "report {}", report_type);
|
BAN::Formatter::println(Debug::putchar, "report {}", report_type);
|
||||||
|
|
||||||
|
if (use_report_id)
|
||||||
|
{
|
||||||
|
print_indent(indent + 4);
|
||||||
|
BAN::Formatter::println(Debug::putchar, "report id: {2H}", report.report_id);
|
||||||
|
}
|
||||||
|
|
||||||
print_indent(indent + 4);
|
print_indent(indent + 4);
|
||||||
BAN::Formatter::println(Debug::putchar, "usage page: {2H}", report.usage_page);
|
BAN::Formatter::println(Debug::putchar, "usage page: {2H}", report.usage_page);
|
||||||
|
|
||||||
|
@ -722,7 +765,7 @@ namespace Kernel
|
||||||
BAN::Formatter::println(Debug::putchar, "pmaximum: {}", report.physical_maximum);
|
BAN::Formatter::println(Debug::putchar, "pmaximum: {}", report.physical_maximum);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_hid_collection(const Collection& collection, size_t indent)
|
static void dump_hid_collection(const Collection& collection, size_t indent, bool use_report_id)
|
||||||
{
|
{
|
||||||
print_indent(indent);
|
print_indent(indent);
|
||||||
BAN::Formatter::println(Debug::putchar, "collection {}", collection.type);
|
BAN::Formatter::println(Debug::putchar, "collection {}", collection.type);
|
||||||
|
@ -732,9 +775,9 @@ namespace Kernel
|
||||||
for (const auto& entry : collection.entries)
|
for (const auto& entry : collection.entries)
|
||||||
{
|
{
|
||||||
if (entry.has<Collection>())
|
if (entry.has<Collection>())
|
||||||
dump_hid_collection(entry.get<Collection>(), indent + 4);
|
dump_hid_collection(entry.get<Collection>(), indent + 4, use_report_id);
|
||||||
if (entry.has<Report>())
|
if (entry.has<Report>())
|
||||||
dump_hid_report(entry.get<Report>(), indent + 4);
|
dump_hid_report(entry.get<Report>(), indent + 4, use_report_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -155,10 +155,10 @@ namespace Kernel
|
||||||
s_scancode_to_keycode[0x37] = keycode_normal(3, 10);
|
s_scancode_to_keycode[0x37] = keycode_normal(3, 10);
|
||||||
s_scancode_to_keycode[0x38] = keycode_normal(3, 11);
|
s_scancode_to_keycode[0x38] = keycode_normal(3, 11);
|
||||||
s_scancode_to_keycode[0xE5] = keycode_normal(3, 12);
|
s_scancode_to_keycode[0xE5] = keycode_normal(3, 12);
|
||||||
s_scancode_to_keycode[0xE0] = keycode_normal(4, 1);
|
s_scancode_to_keycode[0xE0] = keycode_normal(4, 0);
|
||||||
s_scancode_to_keycode[0xE3] = keycode_normal(4, 2);
|
s_scancode_to_keycode[0xE3] = keycode_normal(4, 1);
|
||||||
s_scancode_to_keycode[0xE2] = keycode_normal(4, 3);
|
s_scancode_to_keycode[0xE2] = keycode_normal(4, 2);
|
||||||
s_scancode_to_keycode[0x2C] = keycode_normal(4, 4);
|
s_scancode_to_keycode[0x2C] = keycode_normal(4, 3);
|
||||||
s_scancode_to_keycode[0xE6] = keycode_normal(4, 5);
|
s_scancode_to_keycode[0xE6] = keycode_normal(4, 5);
|
||||||
s_scancode_to_keycode[0xE4] = keycode_normal(4, 6);
|
s_scancode_to_keycode[0xE4] = keycode_normal(4, 6);
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,21 @@ namespace Kernel
|
||||||
return TRY(BAN::UniqPtr<XHCIDevice>::create(controller, port_id, slot_id));
|
return TRY(BAN::UniqPtr<XHCIDevice>::create(controller, port_id, slot_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint64_t XHCIDevice::calculate_port_bits_per_second(XHCIController& controller, uint32_t port_id)
|
||||||
|
{
|
||||||
|
const uint32_t portsc = controller.operational_regs().ports[port_id - 1].portsc;
|
||||||
|
const uint32_t speed_id = (portsc >> XHCI::PORTSC::PORT_SPEED_SHIFT) & XHCI::PORTSC::PORT_SPEED_MASK;
|
||||||
|
return controller.port(port_id).speed_id_to_speed[speed_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
XHCIDevice::XHCIDevice(XHCIController& controller, uint32_t port_id, uint32_t slot_id)
|
||||||
|
: USBDevice(determine_speed_class(calculate_port_bits_per_second(controller, port_id)))
|
||||||
|
, m_controller(controller)
|
||||||
|
, m_port_id(port_id)
|
||||||
|
, m_slot_id(slot_id)
|
||||||
|
{}
|
||||||
|
|
||||||
XHCIDevice::~XHCIDevice()
|
XHCIDevice::~XHCIDevice()
|
||||||
{
|
{
|
||||||
XHCI::TRB disable_slot { .disable_slot_command {} };
|
XHCI::TRB disable_slot { .disable_slot_command {} };
|
||||||
|
@ -32,11 +47,9 @@ namespace Kernel
|
||||||
|
|
||||||
const uint32_t portsc = m_controller.operational_regs().ports[m_port_id - 1].portsc;
|
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 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;
|
m_endpoints[0].max_packet_size = 0;
|
||||||
switch (speed_class)
|
switch (m_speed_class)
|
||||||
{
|
{
|
||||||
case USB::SpeedClass::LowSpeed:
|
case USB::SpeedClass::LowSpeed:
|
||||||
case USB::SpeedClass::FullSpeed:
|
case USB::SpeedClass::FullSpeed:
|
||||||
|
@ -97,7 +110,7 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Full speed devices can have other max packet sizes than 8
|
// NOTE: Full speed devices can have other max packet sizes than 8
|
||||||
if (speed_class == USB::SpeedClass::FullSpeed)
|
if (m_speed_class == USB::SpeedClass::FullSpeed)
|
||||||
TRY(update_actual_max_packet_size());
|
TRY(update_actual_max_packet_size());
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
@ -155,6 +168,39 @@ namespace Kernel
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 6.2.3.6 Interval
|
||||||
|
static uint32_t determine_interval(const USBEndpointDescriptor& endpoint_descriptor, USB::SpeedClass speed_class)
|
||||||
|
{
|
||||||
|
auto ep_type = static_cast<USB::EndpointType>(endpoint_descriptor.bDescriptorType & 0x03);
|
||||||
|
|
||||||
|
switch (speed_class)
|
||||||
|
{
|
||||||
|
case USB::SpeedClass::HighSpeed:
|
||||||
|
// maximum NAK rate
|
||||||
|
if (ep_type == USB::EndpointType::Control || ep_type == USB::EndpointType::Bulk)
|
||||||
|
return (endpoint_descriptor.bInterval == 0) ? 0 : BAN::Math::clamp<uint32_t>(
|
||||||
|
BAN::Math::ilog2<uint32_t>(endpoint_descriptor.bInterval), 0, 15
|
||||||
|
);
|
||||||
|
// fall through
|
||||||
|
case USB::SpeedClass::SuperSpeed:
|
||||||
|
if (ep_type == USB::EndpointType::Isochronous || ep_type == USB::EndpointType::Interrupt)
|
||||||
|
return BAN::Math::clamp<uint32_t>(endpoint_descriptor.bInterval - 1, 0, 15);
|
||||||
|
return 0;
|
||||||
|
case USB::SpeedClass::FullSpeed:
|
||||||
|
if (ep_type == USB::EndpointType::Isochronous)
|
||||||
|
return BAN::Math::clamp<uint32_t>(endpoint_descriptor.bInterval + 2, 3, 18);
|
||||||
|
// fall through
|
||||||
|
case USB::SpeedClass::LowSpeed:
|
||||||
|
if (ep_type == USB::EndpointType::Isochronous || ep_type == USB::EndpointType::Interrupt)
|
||||||
|
return (endpoint_descriptor.bInterval == 0) ? 0 : BAN::Math::clamp<uint32_t>(
|
||||||
|
BAN::Math::ilog2<uint32_t>(endpoint_descriptor.bInterval * 8), 3, 10
|
||||||
|
);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> XHCIDevice::initialize_endpoint(const USBEndpointDescriptor& endpoint_descriptor)
|
BAN::ErrorOr<void> XHCIDevice::initialize_endpoint(const USBEndpointDescriptor& endpoint_descriptor)
|
||||||
{
|
{
|
||||||
const uint32_t endpoint_id = (endpoint_descriptor.bEndpointAddress & 0x0F) * 2 + !!(endpoint_descriptor.bEndpointAddress & 0x80);
|
const uint32_t endpoint_id = (endpoint_descriptor.bEndpointAddress & 0x0F) * 2 + !!(endpoint_descriptor.bEndpointAddress & 0x80);
|
||||||
|
@ -195,6 +241,9 @@ namespace Kernel
|
||||||
ASSERT((endpoint_descriptor.bmAttributes & 0x03) == 3);
|
ASSERT((endpoint_descriptor.bmAttributes & 0x03) == 3);
|
||||||
ASSERT(m_controller.port(m_port_id).revision_major == 2);
|
ASSERT(m_controller.port(m_port_id).revision_major == 2);
|
||||||
|
|
||||||
|
const uint32_t max_esit_payload = endpoint_context.max_packet_size * (endpoint_context.max_burst_size + 1);
|
||||||
|
const uint32_t interval = determine_interval(endpoint_descriptor, m_speed_class);
|
||||||
|
|
||||||
memset(&endpoint_context, 0, context_size);
|
memset(&endpoint_context, 0, context_size);
|
||||||
endpoint_context.endpoint_type = XHCI::EndpointType::InterruptIn;
|
endpoint_context.endpoint_type = XHCI::EndpointType::InterruptIn;
|
||||||
endpoint_context.max_packet_size = endpoint.max_packet_size;
|
endpoint_context.max_packet_size = endpoint.max_packet_size;
|
||||||
|
@ -202,9 +251,10 @@ namespace Kernel
|
||||||
endpoint_context.mult = 0;
|
endpoint_context.mult = 0;
|
||||||
endpoint_context.error_count = 3;
|
endpoint_context.error_count = 3;
|
||||||
endpoint_context.tr_dequeue_pointer = endpoint.transfer_ring->paddr() | 1;
|
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_lo = max_esit_payload & 0xFFFF;
|
||||||
endpoint_context.max_esit_payload_hi = max_esit_payload >> 16;
|
endpoint_context.max_esit_payload_hi = max_esit_payload >> 16;
|
||||||
|
endpoint_context.average_trb_length = max_esit_payload;
|
||||||
|
endpoint_context.interval = interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
XHCI::TRB configure_endpoint { .configure_endpoint_command = {} };
|
XHCI::TRB configure_endpoint { .configure_endpoint_command = {} };
|
||||||
|
|
|
@ -205,9 +205,8 @@ static void init2(void*)
|
||||||
// Initialize empty keymap
|
// Initialize empty keymap
|
||||||
MUST(LibInput::KeyboardLayout::initialize());
|
MUST(LibInput::KeyboardLayout::initialize());
|
||||||
|
|
||||||
// FIXME: implement device hot plugging, so multiple devices is possible
|
if (auto res = PS2Controller::initialize(); res.is_error())
|
||||||
//if (auto res = PS2Controller::initialize(); res.is_error())
|
dprintln("{}", res.error());
|
||||||
// dprintln("{}", res.error());
|
|
||||||
|
|
||||||
MUST(NetworkManager::initialize());
|
MUST(NetworkManager::initialize());
|
||||||
|
|
||||||
|
@ -216,9 +215,6 @@ static void init2(void*)
|
||||||
PCI::PCIManager::get().initialize_devices();
|
PCI::PCIManager::get().initialize_devices();
|
||||||
dprintln("PCI devices initialized");
|
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);
|
VirtualFileSystem::initialize(cmdline.root);
|
||||||
dprintln("VFS initialized");
|
dprintln("VFS initialized");
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,6 @@ qemu-system-$QEMU_ARCH \
|
||||||
-drive format=raw,id=disk,file=${BANAN_DISK_IMAGE_PATH},if=none \
|
-drive format=raw,id=disk,file=${BANAN_DISK_IMAGE_PATH},if=none \
|
||||||
-device e1000e,netdev=net \
|
-device e1000e,netdev=net \
|
||||||
-netdev user,id=net \
|
-netdev user,id=net \
|
||||||
-device qemu-xhci -device usb-kbd \
|
-device qemu-xhci -device usb-kbd -device usb-mouse \
|
||||||
$DISK_ARGS \
|
$DISK_ARGS \
|
||||||
$@ \
|
$@ \
|
||||||
|
|
|
@ -158,11 +158,11 @@ int main()
|
||||||
MUST(LibInput::KeyboardLayout::initialize());
|
MUST(LibInput::KeyboardLayout::initialize());
|
||||||
MUST(LibInput::KeyboardLayout::get().load_from_file("/usr/share/keymaps/us.keymap"_sv));
|
MUST(LibInput::KeyboardLayout::get().load_from_file("/usr/share/keymaps/us.keymap"_sv));
|
||||||
|
|
||||||
int keyboard_fd = open("/dev/keyboard0", O_RDONLY);
|
int keyboard_fd = open("/dev/keyboard", O_RDONLY);
|
||||||
if (keyboard_fd == -1)
|
if (keyboard_fd == -1)
|
||||||
perror("open");
|
perror("open");
|
||||||
|
|
||||||
int mouse_fd = open("/dev/mouse0", O_RDONLY);
|
int mouse_fd = open("/dev/mouse", O_RDONLY);
|
||||||
if (mouse_fd == -1)
|
if (mouse_fd == -1)
|
||||||
perror("open");
|
perror("open");
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ void cleanup()
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
const char* fb_path = "/dev/fb0";
|
const char* fb_path = "/dev/fb0";
|
||||||
const char* mouse_path = "/dev/mouse0";
|
const char* mouse_path = "/dev/mouse";
|
||||||
|
|
||||||
if (argc == 1)
|
if (argc == 1)
|
||||||
;
|
;
|
||||||
|
|
Loading…
Reference in New Issue