Kernel: Add support for DualShock 3 controllers
This driver accepts any HID joystick devices but button and axis mappings will only work on a PS3 controller
This commit is contained in:
parent
08bfa0971e
commit
65664b0d65
|
|
@ -108,6 +108,7 @@ set(KERNEL_SOURCES
|
||||||
kernel/USB/Controller.cpp
|
kernel/USB/Controller.cpp
|
||||||
kernel/USB/Device.cpp
|
kernel/USB/Device.cpp
|
||||||
kernel/USB/HID/HIDDriver.cpp
|
kernel/USB/HID/HIDDriver.cpp
|
||||||
|
kernel/USB/HID/Joystick.cpp
|
||||||
kernel/USB/HID/Keyboard.cpp
|
kernel/USB/HID/Keyboard.cpp
|
||||||
kernel/USB/HID/Mouse.cpp
|
kernel/USB/HID/Mouse.cpp
|
||||||
kernel/USB/Hub/HubDriver.cpp
|
kernel/USB/Hub/HubDriver.cpp
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ namespace Kernel
|
||||||
Debug,
|
Debug,
|
||||||
Keyboard,
|
Keyboard,
|
||||||
Mouse,
|
Mouse,
|
||||||
|
Joystick,
|
||||||
SCSI,
|
SCSI,
|
||||||
NVMeController,
|
NVMeController,
|
||||||
NVMeNamespace,
|
NVMeNamespace,
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
Mouse,
|
Mouse,
|
||||||
Keyboard,
|
Keyboard,
|
||||||
|
Joystick,
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,8 @@ namespace Kernel
|
||||||
{}
|
{}
|
||||||
virtual ~USBHIDDevice() = default;
|
virtual ~USBHIDDevice() = default;
|
||||||
|
|
||||||
|
virtual BAN::ErrorOr<void> initialize() { return {}; }
|
||||||
|
|
||||||
virtual void start_report() = 0;
|
virtual void start_report() = 0;
|
||||||
virtual void stop_report() = 0;
|
virtual void stop_report() = 0;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/USB/HID/HIDDriver.h>
|
||||||
|
|
||||||
|
#include <LibInput/Joystick.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
class USBJoystick final : public USBHIDDevice
|
||||||
|
{
|
||||||
|
BAN_NON_COPYABLE(USBJoystick);
|
||||||
|
BAN_NON_MOVABLE(USBJoystick);
|
||||||
|
|
||||||
|
public:
|
||||||
|
BAN::ErrorOr<void> initialize() override;
|
||||||
|
|
||||||
|
void start_report() override;
|
||||||
|
void stop_report() override;
|
||||||
|
|
||||||
|
void handle_array(uint16_t usage_page, uint16_t usage) override;
|
||||||
|
void handle_variable(uint16_t usage_page, uint16_t usage, int64_t state) override;
|
||||||
|
void handle_variable_absolute(uint16_t usage_page, uint16_t usage, int64_t state, int64_t min, int64_t max) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
|
||||||
|
bool can_read_impl() const override { return true; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
USBJoystick(USBHIDDriver&);
|
||||||
|
~USBJoystick() = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
USBHIDDriver& m_driver;
|
||||||
|
|
||||||
|
SpinLock m_state_lock;
|
||||||
|
InterruptState m_interrupt_state;
|
||||||
|
LibInput::JoystickState m_state {};
|
||||||
|
|
||||||
|
friend class BAN::RefPtr<USBJoystick>;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include <kernel/Input/InputDevice.h>
|
#include <kernel/Input/InputDevice.h>
|
||||||
#include <kernel/Lock/SpinLockAsMutex.h>
|
#include <kernel/Lock/SpinLockAsMutex.h>
|
||||||
|
|
||||||
|
#include <LibInput/Joystick.h>
|
||||||
#include <LibInput/KeyEvent.h>
|
#include <LibInput/KeyEvent.h>
|
||||||
#include <LibInput/MouseEvent.h>
|
#include <LibInput/MouseEvent.h>
|
||||||
|
|
||||||
|
|
@ -18,6 +19,8 @@ namespace Kernel
|
||||||
static BAN::Vector<BAN::WeakPtr<InputDevice>> s_mice;
|
static BAN::Vector<BAN::WeakPtr<InputDevice>> s_mice;
|
||||||
static BAN::RefPtr<MouseDevice> s_mouse_device;
|
static BAN::RefPtr<MouseDevice> s_mouse_device;
|
||||||
|
|
||||||
|
static BAN::Vector<BAN::WeakPtr<InputDevice>> s_joysticks;
|
||||||
|
|
||||||
static const char* get_name_format(InputDevice::Type type)
|
static const char* get_name_format(InputDevice::Type type)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
|
|
@ -26,6 +29,8 @@ namespace Kernel
|
||||||
return "keyboard{}";
|
return "keyboard{}";
|
||||||
case InputDevice::Type::Mouse:
|
case InputDevice::Type::Mouse:
|
||||||
return "mouse{}";
|
return "mouse{}";
|
||||||
|
case InputDevice::Type::Joystick:
|
||||||
|
return "joystick{}";
|
||||||
}
|
}
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
@ -44,6 +49,11 @@ namespace Kernel
|
||||||
if (!s_mice[i].valid())
|
if (!s_mice[i].valid())
|
||||||
return makedev(DeviceNumber::Mouse, i + 1);
|
return makedev(DeviceNumber::Mouse, i + 1);
|
||||||
return makedev(DeviceNumber::Mouse, s_mice.size() + 1);
|
return makedev(DeviceNumber::Mouse, s_mice.size() + 1);
|
||||||
|
case InputDevice::Type::Joystick:
|
||||||
|
for (size_t i = 0; i < s_joysticks.size(); i++)
|
||||||
|
if (!s_joysticks[i].valid())
|
||||||
|
return makedev(DeviceNumber::Joystick, i + 1);
|
||||||
|
return makedev(DeviceNumber::Joystick, s_joysticks.size() + 1);
|
||||||
}
|
}
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
@ -56,6 +66,8 @@ namespace Kernel
|
||||||
return sizeof(LibInput::RawKeyEvent);
|
return sizeof(LibInput::RawKeyEvent);
|
||||||
case InputDevice::Type::Mouse:
|
case InputDevice::Type::Mouse:
|
||||||
return sizeof(LibInput::MouseEvent);
|
return sizeof(LibInput::MouseEvent);
|
||||||
|
case InputDevice::Type::Joystick:
|
||||||
|
return sizeof(LibInput::JoystickEvent);
|
||||||
}
|
}
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
@ -69,18 +81,23 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
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)
|
switch (m_type)
|
||||||
{
|
{
|
||||||
if (s_keyboards.size() < minor(m_rdev))
|
case Type::Keyboard:
|
||||||
MUST(s_keyboards.resize(minor(m_rdev)));
|
if (s_keyboards.size() < minor(m_rdev))
|
||||||
s_keyboards[minor(m_rdev) - 1] = MUST(get_weak_ptr());
|
MUST(s_keyboards.resize(minor(m_rdev)));
|
||||||
}
|
s_keyboards[minor(m_rdev) - 1] = MUST(get_weak_ptr());
|
||||||
|
break;
|
||||||
if (m_type == Type::Mouse)
|
case Type::Mouse:
|
||||||
{
|
if (s_mice.size() < minor(m_rdev))
|
||||||
if (s_mice.size() < minor(m_rdev))
|
MUST(s_mice.resize(minor(m_rdev)));
|
||||||
MUST(s_mice.resize(minor(m_rdev)));
|
s_mice[minor(m_rdev) - 1] = MUST(get_weak_ptr());
|
||||||
s_mice[minor(m_rdev) - 1] = MUST(get_weak_ptr());
|
break;
|
||||||
|
case Type::Joystick:
|
||||||
|
if (s_joysticks.size() < minor(m_rdev))
|
||||||
|
MUST(s_joysticks.resize(minor(m_rdev)));
|
||||||
|
s_joysticks[minor(m_rdev) - 1] = MUST(get_weak_ptr());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <kernel/FS/DevFS/FileSystem.h>
|
#include <kernel/FS/DevFS/FileSystem.h>
|
||||||
#include <kernel/USB/HID/HIDDriver.h>
|
#include <kernel/USB/HID/HIDDriver.h>
|
||||||
|
#include <kernel/USB/HID/Joystick.h>
|
||||||
#include <kernel/USB/HID/Keyboard.h>
|
#include <kernel/USB/HID/Keyboard.h>
|
||||||
#include <kernel/USB/HID/Mouse.h>
|
#include <kernel/USB/HID/Mouse.h>
|
||||||
|
|
||||||
|
|
@ -208,6 +209,10 @@ namespace Kernel
|
||||||
return BAN::Error::from_errno(EINVAL);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto& report : m_device_inputs)
|
||||||
|
if (report.device && report.device->initialize().is_error())
|
||||||
|
report.device.clear();
|
||||||
|
|
||||||
m_device.send_data_buffer(m_data_endpoint_id, m_data_buffer->paddr(), m_data_buffer->size());
|
m_device.send_data_buffer(m_data_endpoint_id, m_data_buffer->paddr(), m_data_buffer->size());
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
|
@ -256,6 +261,10 @@ namespace Kernel
|
||||||
report.device = TRY(BAN::RefPtr<USBMouse>::create());
|
report.device = TRY(BAN::RefPtr<USBMouse>::create());
|
||||||
dprintln("Initialized an USB Mouse");
|
dprintln("Initialized an USB Mouse");
|
||||||
break;
|
break;
|
||||||
|
case 0x04:
|
||||||
|
report.device = TRY(BAN::RefPtr<USBJoystick>::create(*this));
|
||||||
|
dprintln("Initialized an USB Joystick");
|
||||||
|
break;
|
||||||
case 0x06:
|
case 0x06:
|
||||||
report.device = TRY(BAN::RefPtr<USBKeyboard>::create(*this, BAN::move(outputs)));
|
report.device = TRY(BAN::RefPtr<USBKeyboard>::create(*this, BAN::move(outputs)));
|
||||||
dprintln("Initialized an USB Keyboard");
|
dprintln("Initialized an USB Keyboard");
|
||||||
|
|
@ -376,13 +385,13 @@ namespace Kernel
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint32_t usage_base = input.usage_id ? input.usage_id : input.usage_minimum;
|
|
||||||
|
|
||||||
const bool relative = !!(input.flags & 0x04);
|
const bool relative = !!(input.flags & 0x04);
|
||||||
const bool variable = !!(input.flags & 0x02);
|
const bool variable = !!(input.flags & 0x02);
|
||||||
|
|
||||||
|
const auto usage = input.usage_id ? input.usage_id : (input.usage_minimum + (variable ? i : logical));
|
||||||
|
|
||||||
if (!variable)
|
if (!variable)
|
||||||
device_input.device->handle_array(input.usage_page, usage_base + logical);
|
device_input.device->handle_array(input.usage_page, usage);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const int64_t physical =
|
const int64_t physical =
|
||||||
|
|
@ -392,9 +401,9 @@ namespace Kernel
|
||||||
input.physical_minimum;
|
input.physical_minimum;
|
||||||
|
|
||||||
if (relative)
|
if (relative)
|
||||||
device_input.device->handle_variable(input.usage_page, usage_base + i, physical);
|
device_input.device->handle_variable(input.usage_page, usage, physical);
|
||||||
else
|
else
|
||||||
device_input.device->handle_variable_absolute(input.usage_page, usage_base + i, physical, input.physical_minimum, input.physical_maximum);
|
device_input.device->handle_variable_absolute(input.usage_page, usage, physical, input.physical_minimum, input.physical_maximum);
|
||||||
}
|
}
|
||||||
|
|
||||||
bit_offset += input.report_size;
|
bit_offset += input.report_size;
|
||||||
|
|
@ -595,15 +604,16 @@ namespace Kernel
|
||||||
break;
|
break;
|
||||||
case 0b1010: // collection
|
case 0b1010: // collection
|
||||||
{
|
{
|
||||||
if (local_state.usage_stack.size() != 1)
|
if (local_state.usage_stack.size() > 1)
|
||||||
{
|
{
|
||||||
dwarnln("{} usages specified for collection", local_state.usage_stack.empty() ? "No" : "Multiple");
|
dwarnln("Multiple usages specified for a collection");
|
||||||
return BAN::Error::from_errno(EFAULT);
|
return BAN::Error::from_errno(EFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t usage_page = 0;
|
uint16_t usage_page = 0;
|
||||||
if (global_state.usage_page.has_value())
|
if (global_state.usage_page.has_value())
|
||||||
usage_page = global_state.usage_page.value();
|
usage_page = global_state.usage_page.value();
|
||||||
if (local_state.usage_stack.front() >> 16)
|
if (!local_state.usage_stack.empty() && local_state.usage_stack.front() >> 16)
|
||||||
usage_page = local_state.usage_stack.front() >> 16;
|
usage_page = local_state.usage_stack.front() >> 16;
|
||||||
if (usage_page == 0)
|
if (usage_page == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -612,8 +622,11 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
|
|
||||||
TRY(collection_stack.emplace_back());
|
TRY(collection_stack.emplace_back());
|
||||||
|
collection_stack.back().type = report_data[1];
|
||||||
collection_stack.back().usage_page = usage_page;
|
collection_stack.back().usage_page = usage_page;
|
||||||
collection_stack.back().usage_id = local_state.usage_stack.front();
|
if (!local_state.usage_stack.empty())
|
||||||
|
collection_stack.back().usage_id = local_state.usage_stack.front();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0b1100: // end collection
|
case 0b1100: // end collection
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,114 @@
|
||||||
|
#include <kernel/Input/InputDevice.h>
|
||||||
|
#include <kernel/USB/HID/Joystick.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
USBJoystick::USBJoystick(USBHIDDriver& driver)
|
||||||
|
: USBHIDDevice(InputDevice::Type::Joystick)
|
||||||
|
, m_driver(driver)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> USBJoystick::initialize()
|
||||||
|
{
|
||||||
|
// TODO: this is not a generic USB HID joystick driver but one for PS3 controller.
|
||||||
|
// this may still work with other HID joysticks so i won't limit this only
|
||||||
|
// based on the device.
|
||||||
|
|
||||||
|
// linux hid-sony.c
|
||||||
|
|
||||||
|
auto temp_region = TRY(DMARegion::create(17));
|
||||||
|
|
||||||
|
USBDeviceRequest request;
|
||||||
|
|
||||||
|
// move ps3 controller to "operational" state
|
||||||
|
request.bmRequestType = USB::RequestType::DeviceToHost | USB::RequestType::Class | USB::RequestType::Interface;
|
||||||
|
request.bRequest = 0x01;
|
||||||
|
request.wValue = 0x03F2;
|
||||||
|
request.wIndex = m_driver.interface().descriptor.bInterfaceNumber;
|
||||||
|
request.wLength = 17;
|
||||||
|
TRY(m_driver.device().send_request(request, temp_region->paddr()));
|
||||||
|
|
||||||
|
// some compatible controllers need this too
|
||||||
|
request.bmRequestType = USB::RequestType::DeviceToHost | USB::RequestType::Class | USB::RequestType::Interface;
|
||||||
|
request.bRequest = 0x01;
|
||||||
|
request.wValue = 0x03F5;
|
||||||
|
request.wIndex = m_driver.interface().descriptor.bInterfaceNumber;
|
||||||
|
request.wLength = 8;
|
||||||
|
TRY(m_driver.device().send_request(request, temp_region->paddr()));
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void USBJoystick::start_report()
|
||||||
|
{
|
||||||
|
m_interrupt_state = m_state_lock.lock();
|
||||||
|
|
||||||
|
for (auto& axis : m_state.axis)
|
||||||
|
axis = {};
|
||||||
|
for (auto& button : m_state.buttons)
|
||||||
|
button = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void USBJoystick::stop_report()
|
||||||
|
{
|
||||||
|
m_state_lock.unlock(m_interrupt_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void USBJoystick::handle_array(uint16_t usage_page, uint16_t usage)
|
||||||
|
{
|
||||||
|
(void)usage;
|
||||||
|
dprintln("Unsupported array {2H}", usage_page);
|
||||||
|
}
|
||||||
|
|
||||||
|
void USBJoystick::handle_variable(uint16_t usage_page, uint16_t usage, int64_t state)
|
||||||
|
{
|
||||||
|
(void)usage;
|
||||||
|
(void)state;
|
||||||
|
dprintln("Unsupported relative usage page {2H}", usage_page);
|
||||||
|
}
|
||||||
|
|
||||||
|
void USBJoystick::handle_variable_absolute(uint16_t usage_page, uint16_t usage, int64_t state, int64_t min, int64_t max)
|
||||||
|
{
|
||||||
|
switch (usage_page)
|
||||||
|
{
|
||||||
|
case 0x01:
|
||||||
|
switch (usage)
|
||||||
|
{
|
||||||
|
case 0x01:
|
||||||
|
// TODO: PS3 controller sends some extra data with this usage
|
||||||
|
break;
|
||||||
|
case 0x30:
|
||||||
|
m_state.axis[0] = { state, min, max };
|
||||||
|
break;
|
||||||
|
case 0x31:
|
||||||
|
m_state.axis[1] = { state, min, max };
|
||||||
|
break;
|
||||||
|
case 0x32:
|
||||||
|
m_state.axis[2] = { state, min, max };
|
||||||
|
break;
|
||||||
|
case 0x35:
|
||||||
|
m_state.axis[3] = { state, min, max };
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x09:
|
||||||
|
if (usage > 0 && usage <= sizeof(m_state.buttons))
|
||||||
|
m_state.buttons[usage - 1] = state;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dprintln("Unsupported absolute usage page {2H}", usage_page);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<size_t> USBJoystick::read_impl(off_t, BAN::ByteSpan buffer)
|
||||||
|
{
|
||||||
|
SpinLockGuard _(m_state_lock);
|
||||||
|
const size_t to_copy = BAN::Math::min(buffer.size(), sizeof(m_state));
|
||||||
|
memcpy(buffer.data(), &m_state, to_copy);
|
||||||
|
return to_copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace LibInput
|
||||||
|
{
|
||||||
|
|
||||||
|
// TODO: not used but here if we ever make controller
|
||||||
|
// support generating events instead of being polled
|
||||||
|
struct JoystickEvent
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct JoystickState
|
||||||
|
{
|
||||||
|
struct Axis
|
||||||
|
{
|
||||||
|
int64_t value;
|
||||||
|
int64_t min;
|
||||||
|
int64_t max;
|
||||||
|
};
|
||||||
|
|
||||||
|
Axis axis[4];
|
||||||
|
bool buttons[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue