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 bool s_has_nxe = false;
|
||||
static bool s_has_pge = false;
|
||||
static bool s_has_pat = false;
|
||||
|
||||
static paddr_t s_global_pdpte = 0;
|
||||
|
||||
|
@ -32,8 +33,6 @@ namespace Kernel
|
|||
result |= Flags::Execute;
|
||||
if (entry & Flags::Reserved)
|
||||
result |= Flags::Reserved;
|
||||
if (entry & Flags::CacheDisable)
|
||||
result |= Flags::CacheDisable;
|
||||
if (entry & Flags::UserSupervisor)
|
||||
result |= Flags::UserSupervisor;
|
||||
if (entry & Flags::ReadWrite)
|
||||
|
@ -51,6 +50,9 @@ namespace Kernel
|
|||
if (CPUID::has_pge())
|
||||
s_has_pge = true;
|
||||
|
||||
if (CPUID::has_pat())
|
||||
s_has_pat = true;
|
||||
|
||||
ASSERT(s_kernel == nullptr);
|
||||
s_kernel = new PageTable();
|
||||
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
|
||||
asm volatile(
|
||||
"movl %%cr0, %%eax;"
|
||||
|
@ -316,7 +329,7 @@ namespace Kernel
|
|||
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 != fast_page());
|
||||
|
@ -338,8 +351,14 @@ namespace Kernel
|
|||
extra_flags |= 1ull << 63;
|
||||
if (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
|
||||
flags_t uwr_flags = (flags & (Flags::UserSupervisor | Flags::ReadWrite)) | Flags::Present;
|
||||
|
@ -367,7 +386,7 @@ namespace Kernel
|
|||
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(paddr % PAGE_SIZE == 0);
|
||||
|
@ -377,7 +396,7 @@ namespace Kernel
|
|||
|
||||
SpinLockGuard _(m_lock);
|
||||
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
|
||||
|
|
|
@ -56,8 +56,6 @@ namespace Kernel
|
|||
result |= Flags::Execute;
|
||||
if (entry & Flags::Reserved)
|
||||
result |= Flags::Reserved;
|
||||
if (entry & Flags::CacheDisable)
|
||||
result |= Flags::CacheDisable;
|
||||
if (entry & Flags::UserSupervisor)
|
||||
result |= Flags::UserSupervisor;
|
||||
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
|
||||
asm volatile(
|
||||
"movq %%cr0, %%rax;"
|
||||
|
@ -367,7 +374,7 @@ namespace Kernel
|
|||
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 != fast_page());
|
||||
|
@ -393,8 +400,11 @@ namespace Kernel
|
|||
extra_flags |= 1ull << 63;
|
||||
if (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
|
||||
flags_t uwr_flags = (flags & (Flags::UserSupervisor | Flags::ReadWrite)) | Flags::Present;
|
||||
|
@ -434,7 +444,7 @@ namespace Kernel
|
|||
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));
|
||||
|
||||
|
@ -446,7 +456,7 @@ namespace Kernel
|
|||
|
||||
SpinLockGuard _(m_lock);
|
||||
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
|
||||
|
|
|
@ -79,5 +79,6 @@ namespace CPUID
|
|||
bool is_64_bit();
|
||||
bool has_nxe();
|
||||
bool has_pge();
|
||||
bool has_pat();
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ namespace Kernel
|
|||
void initialize_device_updater();
|
||||
|
||||
void add_device(BAN::RefPtr<Device>);
|
||||
void remove_device(BAN::RefPtr<Device>);
|
||||
|
||||
void add_inode(BAN::StringView path, BAN::RefPtr<TmpInode>);
|
||||
|
||||
void initiate_sync(bool should_block);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
class InputDevice : public CharacterDevice
|
||||
class InputDevice : public CharacterDevice, public BAN::Weakable<InputDevice>
|
||||
{
|
||||
public:
|
||||
enum class Type
|
||||
|
@ -19,6 +19,9 @@ namespace Kernel
|
|||
public:
|
||||
InputDevice(Type type);
|
||||
|
||||
BAN::StringView name() const final override { return m_name; }
|
||||
dev_t rdev() const final override { return m_rdev; }
|
||||
|
||||
protected:
|
||||
void add_event(BAN::ConstByteSpan);
|
||||
|
||||
|
@ -28,13 +31,16 @@ namespace Kernel
|
|||
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:
|
||||
BAN::ErrorOr<size_t> read_non_block(BAN::ByteSpan);
|
||||
|
||||
private:
|
||||
const dev_t m_rdev;
|
||||
const BAN::String m_name;
|
||||
|
||||
const Type m_type;
|
||||
|
||||
mutable SpinLock m_event_lock;
|
||||
Semaphore m_event_semaphore;
|
||||
|
||||
|
@ -45,6 +51,63 @@ namespace Kernel
|
|||
size_t m_event_tail { 0 };
|
||||
size_t m_event_head { 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),
|
||||
ReadWrite = (1 << 1),
|
||||
UserSupervisor = (1 << 2),
|
||||
CacheDisable = (1 << 4),
|
||||
Reserved = (1 << 9),
|
||||
|
||||
Execute = (1 << 15),
|
||||
Used = Present | Reserved,
|
||||
};
|
||||
enum MemoryType
|
||||
{
|
||||
Normal,
|
||||
WriteCombining,
|
||||
WriteThrough,
|
||||
};
|
||||
|
||||
public:
|
||||
static void initialize();
|
||||
|
@ -93,8 +98,8 @@ namespace Kernel
|
|||
void unmap_page(vaddr_t);
|
||||
void unmap_range(vaddr_t, size_t bytes);
|
||||
|
||||
void map_range_at(paddr_t, vaddr_t, size_t bytes, flags_t);
|
||||
void map_page_at(paddr_t, vaddr_t, 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, MemoryType = MemoryType::Normal);
|
||||
|
||||
paddr_t physical_address_of(vaddr_t) const;
|
||||
flags_t get_page_flags(vaddr_t) const;
|
||||
|
|
|
@ -10,13 +10,20 @@ namespace Kernel
|
|||
{
|
||||
enum class SpeedClass
|
||||
{
|
||||
None,
|
||||
LowSpeed,
|
||||
FullSpeed,
|
||||
HighSpeed,
|
||||
SuperSpeed,
|
||||
};
|
||||
|
||||
enum class EndpointType
|
||||
{
|
||||
Control = 0b00,
|
||||
Isochronous = 0b01,
|
||||
Bulk = 0b10,
|
||||
Interrupt = 0b11,
|
||||
};
|
||||
|
||||
enum class DeviceBaseClass : uint8_t
|
||||
{
|
||||
CommunicationAndCDCControl = 0x02,
|
||||
|
|
|
@ -53,7 +53,9 @@ namespace Kernel
|
|||
};
|
||||
|
||||
public:
|
||||
USBDevice() = default;
|
||||
USBDevice(USB::SpeedClass speed_class)
|
||||
: m_speed_class(speed_class)
|
||||
{}
|
||||
virtual ~USBDevice() = default;
|
||||
|
||||
BAN::ErrorOr<void> initialize();
|
||||
|
@ -72,12 +74,14 @@ namespace Kernel
|
|||
private:
|
||||
BAN::ErrorOr<ConfigurationDescriptor> parse_configuration(size_t index);
|
||||
|
||||
protected:
|
||||
const USB::SpeedClass m_speed_class;
|
||||
|
||||
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;
|
||||
BAN::Vector<BAN::UniqPtr<USBClassDriver>> m_class_drivers;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace Kernel
|
|||
uint16_t usage_id;
|
||||
Type type;
|
||||
|
||||
uint8_t report_id;
|
||||
uint32_t report_count;
|
||||
uint32_t report_size;
|
||||
|
||||
|
@ -77,15 +78,17 @@ namespace Kernel
|
|||
|
||||
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:
|
||||
USBDevice& m_device;
|
||||
USBDevice::InterfaceDescriptor m_interface;
|
||||
const uint8_t m_interface_index;
|
||||
|
||||
bool m_uses_report_id { false };
|
||||
|
||||
uint8_t m_endpoint_id { 0 };
|
||||
USBHID::Collection m_collection;
|
||||
BAN::Vector<USBHID::Collection> m_collections;
|
||||
BAN::RefPtr<USBHIDDevice> m_hid_device;
|
||||
|
||||
friend class BAN::UniqPtr<USBHIDDriver>;
|
||||
|
|
|
@ -43,11 +43,7 @@ namespace Kernel
|
|||
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(XHCIController& controller, uint32_t port_id, uint32_t slot_id);
|
||||
~XHCIDevice();
|
||||
BAN::ErrorOr<void> update_actual_max_packet_size();
|
||||
|
||||
|
@ -55,6 +51,8 @@ namespace Kernel
|
|||
|
||||
void advance_endpoint_enqueue(Endpoint&, bool chain);
|
||||
|
||||
static uint64_t calculate_port_bits_per_second(XHCIController&, uint32_t port_id);
|
||||
|
||||
private:
|
||||
static constexpr uint32_t m_transfer_ring_trb_count = PAGE_SIZE / sizeof(XHCI::TRB);
|
||||
|
||||
|
|
|
@ -57,6 +57,13 @@ namespace CPUID
|
|||
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)
|
||||
{
|
||||
switch (feat)
|
||||
|
|
|
@ -68,7 +68,8 @@ namespace Kernel
|
|||
m_video_memory_paddr & PAGE_ADDR_MASK,
|
||||
m_video_memory_vaddr,
|
||||
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(
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <kernel/Device/ZeroDevice.h>
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/FS/TmpFS/Inode.h>
|
||||
#include <kernel/Input/InputDevice.h>
|
||||
#include <kernel/Lock/LockGuard.h>
|
||||
#include <kernel/Process.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(NullDevice::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()
|
||||
|
@ -112,6 +115,21 @@ namespace Kernel
|
|||
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)
|
||||
{
|
||||
ASSERT(!inode->is_device());
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <kernel/Device/DeviceNumbers.h>
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/Input/InputDevice.h>
|
||||
#include <kernel/Lock/LockGuard.h>
|
||||
|
||||
|
@ -10,8 +11,11 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
static BAN::Atomic<uint16_t> s_next_keyboard { 0 };
|
||||
static BAN::Atomic<uint16_t> s_next_mouse { 0 };
|
||||
static BAN::Vector<BAN::WeakPtr<InputDevice>> s_keyboards;
|
||||
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)
|
||||
{
|
||||
|
@ -30,9 +34,15 @@ namespace Kernel
|
|||
switch (type)
|
||||
{
|
||||
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:
|
||||
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();
|
||||
}
|
||||
|
@ -52,10 +62,25 @@ namespace Kernel
|
|||
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_name(MUST(BAN::String::formatted(get_name_format(type), minor(m_rdev) - 1)))
|
||||
, m_type(type)
|
||||
, m_event_size(get_event_size(type))
|
||||
{
|
||||
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)
|
||||
|
@ -63,6 +88,25 @@ namespace Kernel
|
|||
SpinLockGuard _(m_event_lock);
|
||||
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)
|
||||
{
|
||||
m_event_tail = (m_event_tail + 1) % m_max_event_count;
|
||||
|
@ -74,6 +118,10 @@ namespace Kernel
|
|||
m_event_count++;
|
||||
|
||||
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)
|
||||
|
@ -101,4 +149,113 @@ namespace Kernel
|
|||
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();
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -652,7 +652,8 @@ namespace Kernel::PCI
|
|||
m_vaddr = PageTable::kernel().reserve_free_contiguous_pages(needed_pages, KERNEL_OFFSET);
|
||||
if (m_vaddr == 0)
|
||||
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 {};
|
||||
}
|
||||
|
|
|
@ -83,10 +83,10 @@ namespace Kernel
|
|||
Process::create_kernel(
|
||||
[](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())
|
||||
{
|
||||
dprintln("no input device found");
|
||||
dprintln("no keyboard found");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -154,7 +154,7 @@ namespace Kernel
|
|||
break;
|
||||
case USB::InterfaceBaseClass::HID:
|
||||
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;
|
||||
case USB::InterfaceBaseClass::Physical:
|
||||
dprintln_if(DEBUG_USB, "Found Physical interface");
|
||||
|
@ -218,7 +218,7 @@ namespace Kernel
|
|||
break;
|
||||
}
|
||||
|
||||
if (m_class_driver)
|
||||
if (!m_class_drivers.empty())
|
||||
{
|
||||
dprintln("Successfully initialized USB interface");
|
||||
return {};
|
||||
|
@ -309,8 +309,8 @@ namespace Kernel
|
|||
|
||||
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);
|
||||
for (auto& driver : m_class_drivers)
|
||||
driver->handle_input_data(data, endpoint_id);
|
||||
}
|
||||
|
||||
USB::SpeedClass USBDevice::determine_speed_class(uint64_t bits_per_second)
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <kernel/USB/HID/Mouse.h>
|
||||
|
||||
#define DEBUG_HID 0
|
||||
#define DUMP_HID_REPORT 0
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
@ -42,8 +43,8 @@ namespace Kernel
|
|||
BAN::Optional<int32_t> physical_minimum;
|
||||
BAN::Optional<int32_t> physical_maximum;
|
||||
// FIXME: support units
|
||||
BAN::Optional<uint8_t> report_id;
|
||||
BAN::Optional<uint32_t> report_size;
|
||||
// FIXME: support report id
|
||||
BAN::Optional<uint32_t> report_count;
|
||||
};
|
||||
|
||||
|
@ -57,11 +58,11 @@ namespace Kernel
|
|||
|
||||
using namespace USBHID;
|
||||
|
||||
#if DEBUG_HID
|
||||
static void dump_hid_collection(const Collection& collection, size_t indent);
|
||||
#if DUMP_HID_REPORT
|
||||
static void dump_hid_collection(const Collection& collection, size_t indent, bool use_report_id);
|
||||
#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)
|
||||
{
|
||||
|
@ -77,7 +78,10 @@ namespace Kernel
|
|||
{}
|
||||
|
||||
USBHIDDriver::~USBHIDDriver()
|
||||
{}
|
||||
{
|
||||
if (m_hid_device)
|
||||
DevFileSystem::get().remove_device(m_hid_device);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> USBHIDDriver::initialize()
|
||||
{
|
||||
|
@ -143,7 +147,6 @@ namespace Kernel
|
|||
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());
|
||||
|
@ -153,7 +156,7 @@ namespace Kernel
|
|||
dprintln_if(DEBUG_HID, " bCountryCode: {}", hid_descriptor.bCountryCode);
|
||||
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++)
|
||||
{
|
||||
auto descriptor = hid_descriptor.descriptors[i];
|
||||
|
@ -163,11 +166,6 @@ namespace Kernel
|
|||
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())
|
||||
{
|
||||
|
@ -194,40 +192,37 @@ namespace Kernel
|
|||
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;
|
||||
auto new_collections = TRY(parse_report_descriptor(report_data, m_uses_report_id));
|
||||
for (auto& collection : new_collections)
|
||||
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);
|
||||
}
|
||||
|
||||
if (collection.usage_page != 0x01)
|
||||
// FIXME: Handle other collections?
|
||||
|
||||
if (collections.front().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)
|
||||
switch (collections.front().usage_id)
|
||||
{
|
||||
case 0x02:
|
||||
m_hid_device = TRY(BAN::RefPtr<USBMouse>::create());
|
||||
dprintln("Initialized an USB Mouse");
|
||||
break;
|
||||
case 0x06:
|
||||
m_hid_device = TRY(BAN::RefPtr<USBKeyboard>::create());
|
||||
dprintln("Initialized an USB Keyboard");
|
||||
break;
|
||||
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);
|
||||
}
|
||||
DevFileSystem::get().add_device(m_hid_device);
|
||||
|
@ -235,14 +230,14 @@ namespace Kernel
|
|||
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);
|
||||
m_collections = BAN::move(collections);
|
||||
|
||||
TRY(m_device.initialize_endpoint(endpoint_descriptor));
|
||||
|
||||
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 =
|
||||
[data](size_t bit_offset, size_t bit_count, bool as_unsigned) -> int64_t
|
||||
|
@ -281,7 +276,7 @@ namespace Kernel
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -289,6 +284,8 @@ namespace Kernel
|
|||
const auto& input = entry.get<Report>();
|
||||
if (input.type != Report::Type::Input)
|
||||
continue;
|
||||
if (report_id.value_or(input.report_id) != input.report_id)
|
||||
continue;
|
||||
|
||||
ASSERT(input.report_size <= 32);
|
||||
|
||||
|
@ -326,7 +323,9 @@ namespace Kernel
|
|||
|
||||
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)
|
||||
{
|
||||
|
@ -345,21 +344,32 @@ namespace Kernel
|
|||
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();
|
||||
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();
|
||||
}
|
||||
|
||||
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;
|
||||
GlobalState global_state;
|
||||
|
||||
LocalState local_state;
|
||||
|
||||
BAN::Optional<Collection> result;
|
||||
BAN::Vector<Collection> result_stack;
|
||||
BAN::Vector<Collection> collection_stack;
|
||||
|
||||
bool one_has_report_id = false;
|
||||
bool all_has_report_id = true;
|
||||
|
||||
const auto extract_report_item =
|
||||
[&](bool as_unsigned) -> int64_t
|
||||
{
|
||||
|
@ -411,6 +421,11 @@ namespace Kernel
|
|||
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_maximum = get_correct_sign(
|
||||
global_state.logical_minimum.value(),
|
||||
|
@ -436,6 +451,7 @@ namespace Kernel
|
|||
item.usage_minimum = local_state.usage_minimum.value();
|
||||
item.usage_maximum = local_state.usage_maximum.value();
|
||||
item.type = type;
|
||||
item.report_id = global_state.report_id.value_or(0);
|
||||
item.report_count = global_state.report_count.value();
|
||||
item.report_size = global_state.report_size.value();
|
||||
item.logical_minimum = logical_minimum;
|
||||
|
@ -454,6 +470,7 @@ namespace Kernel
|
|||
item.usage_minimum = 0;
|
||||
item.usage_maximum = 0;
|
||||
item.type = type;
|
||||
item.report_id = global_state.report_id.value_or(0);
|
||||
item.report_count = global_state.report_count.value();
|
||||
item.report_size = global_state.report_size.value();
|
||||
item.logical_minimum = 0;
|
||||
|
@ -466,9 +483,10 @@ namespace Kernel
|
|||
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;
|
||||
item.usage_page = (usage >> 16) ? (usage >> 16) : global_state.usage_page.value();
|
||||
|
@ -476,7 +494,8 @@ namespace Kernel
|
|||
item.usage_minimum = 0;
|
||||
item.usage_maximum = 0;
|
||||
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.logical_minimum = logical_minimum;
|
||||
item.logical_maximum = logical_maximum;
|
||||
|
@ -554,12 +573,7 @@ namespace Kernel
|
|||
}
|
||||
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());
|
||||
TRY(result_stack.push_back(BAN::move(collection_stack.back())));
|
||||
collection_stack.pop_back();
|
||||
}
|
||||
else
|
||||
|
@ -605,8 +619,16 @@ namespace Kernel
|
|||
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);
|
||||
{
|
||||
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
|
||||
global_state.report_count = extract_report_item(true);
|
||||
break;
|
||||
|
@ -663,23 +685,38 @@ namespace Kernel
|
|||
report_data = report_data.slice(1 + item_size);
|
||||
}
|
||||
|
||||
if (!result.has_value())
|
||||
if (result_stack.empty())
|
||||
{
|
||||
dwarnln("No collection defined in report descriptor");
|
||||
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)
|
||||
{
|
||||
for (size_t i = 0; i < indent; i++)
|
||||
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 = "";
|
||||
switch (report.type)
|
||||
|
@ -691,6 +728,12 @@ namespace Kernel
|
|||
print_indent(indent);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
BAN::Formatter::println(Debug::putchar, "collection {}", collection.type);
|
||||
|
@ -732,9 +775,9 @@ namespace Kernel
|
|||
for (const auto& entry : collection.entries)
|
||||
{
|
||||
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>())
|
||||
dump_hid_report(entry.get<Report>(), indent + 4);
|
||||
dump_hid_report(entry.get<Report>(), indent + 4, use_report_id);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -155,10 +155,10 @@ namespace Kernel
|
|||
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[0xE0] = keycode_normal(4, 0);
|
||||
s_scancode_to_keycode[0xE3] = keycode_normal(4, 1);
|
||||
s_scancode_to_keycode[0xE2] = keycode_normal(4, 2);
|
||||
s_scancode_to_keycode[0x2C] = keycode_normal(4, 3);
|
||||
s_scancode_to_keycode[0xE6] = keycode_normal(4, 5);
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
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()
|
||||
{
|
||||
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 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)
|
||||
switch (m_speed_class)
|
||||
{
|
||||
case USB::SpeedClass::LowSpeed:
|
||||
case USB::SpeedClass::FullSpeed:
|
||||
|
@ -97,7 +110,7 @@ namespace Kernel
|
|||
}
|
||||
|
||||
// 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());
|
||||
|
||||
return {};
|
||||
|
@ -155,6 +168,39 @@ namespace Kernel
|
|||
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)
|
||||
{
|
||||
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(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);
|
||||
endpoint_context.endpoint_type = XHCI::EndpointType::InterruptIn;
|
||||
endpoint_context.max_packet_size = endpoint.max_packet_size;
|
||||
|
@ -202,9 +251,10 @@ namespace Kernel
|
|||
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;
|
||||
endpoint_context.average_trb_length = max_esit_payload;
|
||||
endpoint_context.interval = interval;
|
||||
}
|
||||
|
||||
XHCI::TRB configure_endpoint { .configure_endpoint_command = {} };
|
||||
|
|
|
@ -205,9 +205,8 @@ static void init2(void*)
|
|||
// Initialize empty keymap
|
||||
MUST(LibInput::KeyboardLayout::initialize());
|
||||
|
||||
// FIXME: implement device hot plugging, so multiple devices is possible
|
||||
//if (auto res = PS2Controller::initialize(); res.is_error())
|
||||
// dprintln("{}", res.error());
|
||||
if (auto res = PS2Controller::initialize(); res.is_error())
|
||||
dprintln("{}", res.error());
|
||||
|
||||
MUST(NetworkManager::initialize());
|
||||
|
||||
|
@ -216,9 +215,6 @@ static void init2(void*)
|
|||
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");
|
||||
|
||||
|
|
|
@ -31,6 +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 \
|
||||
-device qemu-xhci -device usb-kbd -device usb-mouse \
|
||||
$DISK_ARGS \
|
||||
$@ \
|
||||
|
|
|
@ -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/keyboard0", O_RDONLY);
|
||||
int keyboard_fd = open("/dev/keyboard", O_RDONLY);
|
||||
if (keyboard_fd == -1)
|
||||
perror("open");
|
||||
|
||||
int mouse_fd = open("/dev/mouse0", O_RDONLY);
|
||||
int mouse_fd = open("/dev/mouse", O_RDONLY);
|
||||
if (mouse_fd == -1)
|
||||
perror("open");
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ void cleanup()
|
|||
int main(int argc, char** argv)
|
||||
{
|
||||
const char* fb_path = "/dev/fb0";
|
||||
const char* mouse_path = "/dev/mouse0";
|
||||
const char* mouse_path = "/dev/mouse";
|
||||
|
||||
if (argc == 1)
|
||||
;
|
||||
|
|
Loading…
Reference in New Issue