Compare commits

...

2 Commits

Author SHA1 Message Date
Bananymous 088f77a226 Kernel: Add super basic support for USB keyboard LEDs
This is very hacky but it seems to mostly work. Also for some reason
this fixed my Razer Mamba mouse????
2025-02-11 02:18:50 +02:00
Bananymous 4dd6c85df2 Kernel: Fix USB keyboard Scroll lock
I was using 8 bit modifier and ScrollLock bit does not fit this. Also I
was not generating ScrollLock keypresses
2025-02-11 02:16:38 +02:00
4 changed files with 116 additions and 10 deletions

View File

@ -78,6 +78,9 @@ namespace Kernel
void handle_stall(uint8_t endpoint_id) override; void handle_stall(uint8_t endpoint_id) override;
void handle_input_data(size_t byte_count, uint8_t endpoint_id) override; void handle_input_data(size_t byte_count, uint8_t endpoint_id) override;
USBDevice& device() { return m_device; }
const USBDevice::InterfaceDescriptor& interface() const { return m_interface; }
private: private:
USBHIDDriver(USBDevice&, const USBDevice::InterfaceDescriptor&); USBHIDDriver(USBDevice&, const USBDevice::InterfaceDescriptor&);
~USBHIDDriver(); ~USBHIDDriver();

View File

@ -20,18 +20,24 @@ namespace Kernel
void update() override; void update() override;
private: private:
USBKeyboard() USBKeyboard(USBHIDDriver& driver, BAN::Vector<USBHID::Report>&& outputs);
: USBHIDDevice(InputDevice::Type::Keyboard)
{}
~USBKeyboard() = default; ~USBKeyboard() = default;
void set_leds(uint16_t mask);
void set_leds(uint8_t report_id, uint16_t mask);
private: private:
USBHIDDriver& m_driver;
SpinLock m_keyboard_lock; SpinLock m_keyboard_lock;
InterruptState m_lock_state; InterruptState m_lock_state;
BAN::Array<bool, 0x100> m_keyboard_state { false }; BAN::Array<bool, 0x100> m_keyboard_state { false };
BAN::Array<bool, 0x100> m_keyboard_state_temp { false }; BAN::Array<bool, 0x100> m_keyboard_state_temp { false };
uint8_t m_toggle_mask { 0 }; uint16_t m_toggle_mask { 0 };
uint16_t m_led_mask { 0 };
BAN::Vector<USBHID::Report> m_outputs;
BAN::Optional<uint8_t> m_repeat_scancode; BAN::Optional<uint8_t> m_repeat_scancode;
uint8_t m_repeat_modifier { 0 }; uint8_t m_repeat_modifier { 0 };

View File

@ -213,18 +213,18 @@ namespace Kernel
return {}; return {};
} }
static BAN::ErrorOr<void> gather_collection_inputs(const USBHID::Collection& collection, BAN::Vector<USBHID::Report>& output) static BAN::ErrorOr<void> gather_collection_reports(const USBHID::Collection& collection, BAN::Vector<USBHID::Report>& output, USBHID::Report::Type type)
{ {
for (const auto& entry : collection.entries) for (const auto& entry : collection.entries)
{ {
if (entry.has<USBHID::Collection>()) if (entry.has<USBHID::Collection>())
{ {
TRY(gather_collection_inputs(entry.get<USBHID::Collection>(), output)); TRY(gather_collection_reports(entry.get<USBHID::Collection>(), output, type));
continue; continue;
} }
const auto& report = entry.get<USBHID::Report>(); const auto& report = entry.get<USBHID::Report>();
if (report.type != USBHID::Report::Type::Input) if (report.type != type)
continue; continue;
TRY(output.push_back(report)); TRY(output.push_back(report));
@ -243,7 +243,10 @@ namespace Kernel
const auto& collection = collection_list[i]; const auto& collection = collection_list[i];
USBHIDDriver::DeviceReport report; USBHIDDriver::DeviceReport report;
TRY(gather_collection_inputs(collection, report.inputs)); TRY(gather_collection_reports(collection, report.inputs, USBHID::Report::Type::Input));
BAN::Vector<USBHID::Report> outputs;
TRY(gather_collection_reports(collection, outputs, USBHID::Report::Type::Output));
if (collection.usage_page == 0x01) if (collection.usage_page == 0x01)
{ {
@ -254,7 +257,7 @@ namespace Kernel
dprintln("Initialized an USB Mouse"); dprintln("Initialized an USB Mouse");
break; break;
case 0x06: case 0x06:
report.device = TRY(BAN::RefPtr<USBKeyboard>::create()); report.device = TRY(BAN::RefPtr<USBKeyboard>::create(*this, BAN::move(outputs)));
dprintln("Initialized an USB Keyboard"); dprintln("Initialized an USB Keyboard");
break; break;
default: default:

View File

@ -14,6 +14,14 @@ namespace Kernel
static void initialize_scancode_to_keycode(); static void initialize_scancode_to_keycode();
static constexpr bool is_repeatable_scancode(uint8_t scancode); static constexpr bool is_repeatable_scancode(uint8_t scancode);
USBKeyboard::USBKeyboard(USBHIDDriver& driver, BAN::Vector<USBHID::Report>&& outputs)
: USBHIDDevice(InputDevice::Type::Keyboard)
, m_driver(driver)
, m_outputs(BAN::move(outputs))
{
set_leds(0);
}
void USBKeyboard::start_report() void USBKeyboard::start_report()
{ {
m_lock_state = m_keyboard_lock.lock(); m_lock_state = m_keyboard_lock.lock();
@ -31,7 +39,7 @@ namespace Kernel
// FIXME: RawKeyEvent probably should only contain keycode. // FIXME: RawKeyEvent probably should only contain keycode.
// Modifier should be determined when converting to KeyEvent. // Modifier should be determined when converting to KeyEvent.
uint8_t modifier = 0; uint16_t modifier = 0;
#define READ_MODIFIER(scancode, key_modifier) \ #define READ_MODIFIER(scancode, key_modifier) \
if (m_keyboard_state_temp[scancode]) \ if (m_keyboard_state_temp[scancode]) \
@ -126,6 +134,12 @@ namespace Kernel
{ {
using KeyModifier = LibInput::KeyEvent::Modifier; using KeyModifier = LibInput::KeyEvent::Modifier;
const auto toggle_mask = ({ SpinLockGuard _(m_keyboard_lock); m_toggle_mask; });
if (m_led_mask != toggle_mask)
set_leds(toggle_mask);
m_led_mask = toggle_mask;
SpinLockGuard _(m_keyboard_lock); SpinLockGuard _(m_keyboard_lock);
if (!m_repeat_scancode.has_value() || SystemTimer::get().ms_since_boot() < m_next_repeat_event_ms) if (!m_repeat_scancode.has_value() || SystemTimer::get().ms_since_boot() < m_next_repeat_event_ms)
@ -143,6 +157,85 @@ namespace Kernel
m_next_repeat_event_ms += s_repeat_interval_ms; m_next_repeat_event_ms += s_repeat_interval_ms;
} }
void USBKeyboard::set_leds(uint16_t mask)
{
uint8_t report_ids_done[0x100 / 8] {};
for (const auto& report : m_outputs)
{
if (report.usage_page != 0x08)
continue;
const auto byte = report.report_id / 8;
const auto bit = report.report_id % 8;
if (report_ids_done[byte] & (1u << bit))
continue;
set_leds(report.report_id, mask);
report_ids_done[byte] |= (1u << bit);
}
}
void USBKeyboard::set_leds(uint8_t report_id, uint16_t mask)
{
using KeyModifier = LibInput::KeyEvent::Modifier;
size_t report_bits = 0;
for (const auto& report : m_outputs)
{
if (report.report_id != report_id)
continue;
report_bits += report.report_size * report.report_count;
}
const size_t report_bytes = (report_bits + 7) / 8;
uint8_t* data = static_cast<uint8_t*>(kmalloc(report_bytes));
if (data == nullptr)
return;
memset(data, 0, report_bytes);
size_t bit_offset = 0;
for (const auto& report : m_outputs)
{
if (report.report_id != report_id)
continue;
for (size_t i = 0; report.report_size == 1 && i < report.report_count; i++, bit_offset++)
{
const size_t usage = (report.usage_id ? report.usage_id : report.usage_minimum) + bit_offset;
switch (usage)
{
case 0x01:
if (mask & KeyModifier::NumLock)
data[bit_offset / 8] |= 1u << (bit_offset % 8);
break;
case 0x02:
if (mask & KeyModifier::CapsLock)
data[bit_offset / 8] |= 1u << (bit_offset % 8);
break;
case 0x03:
if (mask & KeyModifier::ScrollLock)
data[bit_offset / 8] |= 1u << (bit_offset % 8);
break;
}
}
bit_offset += report.report_size * report.report_count;
}
USBDeviceRequest request;
request.bmRequestType = USB::RequestType::HostToDevice | USB::RequestType::Class | USB::RequestType::Interface;
request.bRequest = 0x09;
request.wValue = 0x0200 | report_id;
request.wIndex = m_driver.interface().descriptor.bInterfaceNumber;
request.wLength = report_bytes;
if (auto ret = m_driver.device().send_request(request, kmalloc_paddr_of(reinterpret_cast<vaddr_t>(data)).value()); ret.is_error())
dprintln_if(DEBUG_USB_KEYBOARD, "Failed to update LEDs: {}", ret.error());
kfree(data);
}
void initialize_scancode_to_keycode() void initialize_scancode_to_keycode()
{ {
using LibInput::keycode_function; using LibInput::keycode_function;
@ -238,6 +331,7 @@ namespace Kernel
s_scancode_to_keycode[0x4D] = keycode_function(17); s_scancode_to_keycode[0x4D] = keycode_function(17);
s_scancode_to_keycode[0x4B] = keycode_function(18); s_scancode_to_keycode[0x4B] = keycode_function(18);
s_scancode_to_keycode[0x4E] = keycode_function(19); s_scancode_to_keycode[0x4E] = keycode_function(19);
s_scancode_to_keycode[0x47] = keycode_function(20);
s_scancode_to_keycode[0x53] = keycode_numpad(0, 0); s_scancode_to_keycode[0x53] = keycode_numpad(0, 0);
s_scancode_to_keycode[0x54] = keycode_numpad(0, 1); s_scancode_to_keycode[0x54] = keycode_numpad(0, 1);