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/Device.cpp
|
||||
kernel/USB/HID/HIDDriver.cpp
|
||||
kernel/USB/HID/Joystick.cpp
|
||||
kernel/USB/HID/Keyboard.cpp
|
||||
kernel/USB/HID/Mouse.cpp
|
||||
kernel/USB/Hub/HubDriver.cpp
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ namespace Kernel
|
|||
Debug,
|
||||
Keyboard,
|
||||
Mouse,
|
||||
Joystick,
|
||||
SCSI,
|
||||
NVMeController,
|
||||
NVMeNamespace,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ namespace Kernel
|
|||
{
|
||||
Mouse,
|
||||
Keyboard,
|
||||
Joystick,
|
||||
};
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ namespace Kernel
|
|||
{}
|
||||
virtual ~USBHIDDevice() = default;
|
||||
|
||||
virtual BAN::ErrorOr<void> initialize() { return {}; }
|
||||
|
||||
virtual void start_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/Lock/SpinLockAsMutex.h>
|
||||
|
||||
#include <LibInput/Joystick.h>
|
||||
#include <LibInput/KeyEvent.h>
|
||||
#include <LibInput/MouseEvent.h>
|
||||
|
||||
|
|
@ -18,6 +19,8 @@ namespace Kernel
|
|||
static BAN::Vector<BAN::WeakPtr<InputDevice>> s_mice;
|
||||
static BAN::RefPtr<MouseDevice> s_mouse_device;
|
||||
|
||||
static BAN::Vector<BAN::WeakPtr<InputDevice>> s_joysticks;
|
||||
|
||||
static const char* get_name_format(InputDevice::Type type)
|
||||
{
|
||||
switch (type)
|
||||
|
|
@ -26,6 +29,8 @@ namespace Kernel
|
|||
return "keyboard{}";
|
||||
case InputDevice::Type::Mouse:
|
||||
return "mouse{}";
|
||||
case InputDevice::Type::Joystick:
|
||||
return "joystick{}";
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
|
@ -44,6 +49,11 @@ namespace Kernel
|
|||
if (!s_mice[i].valid())
|
||||
return makedev(DeviceNumber::Mouse, i + 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();
|
||||
}
|
||||
|
|
@ -56,6 +66,8 @@ namespace Kernel
|
|||
return sizeof(LibInput::RawKeyEvent);
|
||||
case InputDevice::Type::Mouse:
|
||||
return sizeof(LibInput::MouseEvent);
|
||||
case InputDevice::Type::Joystick:
|
||||
return sizeof(LibInput::JoystickEvent);
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
|
@ -69,18 +81,23 @@ namespace Kernel
|
|||
{
|
||||
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))
|
||||
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());
|
||||
case 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());
|
||||
break;
|
||||
case 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());
|
||||
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/USB/HID/HIDDriver.h>
|
||||
#include <kernel/USB/HID/Joystick.h>
|
||||
#include <kernel/USB/HID/Keyboard.h>
|
||||
#include <kernel/USB/HID/Mouse.h>
|
||||
|
||||
|
|
@ -208,6 +209,10 @@ namespace Kernel
|
|||
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());
|
||||
|
||||
return {};
|
||||
|
|
@ -256,6 +261,10 @@ namespace Kernel
|
|||
report.device = TRY(BAN::RefPtr<USBMouse>::create());
|
||||
dprintln("Initialized an USB Mouse");
|
||||
break;
|
||||
case 0x04:
|
||||
report.device = TRY(BAN::RefPtr<USBJoystick>::create(*this));
|
||||
dprintln("Initialized an USB Joystick");
|
||||
break;
|
||||
case 0x06:
|
||||
report.device = TRY(BAN::RefPtr<USBKeyboard>::create(*this, BAN::move(outputs)));
|
||||
dprintln("Initialized an USB Keyboard");
|
||||
|
|
@ -376,13 +385,13 @@ namespace Kernel
|
|||
continue;
|
||||
}
|
||||
|
||||
const uint32_t usage_base = input.usage_id ? input.usage_id : input.usage_minimum;
|
||||
|
||||
const bool relative = !!(input.flags & 0x04);
|
||||
const bool variable = !!(input.flags & 0x02);
|
||||
|
||||
const auto usage = input.usage_id ? input.usage_id : (input.usage_minimum + (variable ? i : logical));
|
||||
|
||||
if (!variable)
|
||||
device_input.device->handle_array(input.usage_page, usage_base + logical);
|
||||
device_input.device->handle_array(input.usage_page, usage);
|
||||
else
|
||||
{
|
||||
const int64_t physical =
|
||||
|
|
@ -392,9 +401,9 @@ namespace Kernel
|
|||
input.physical_minimum;
|
||||
|
||||
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
|
||||
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;
|
||||
|
|
@ -595,15 +604,16 @@ namespace Kernel
|
|||
break;
|
||||
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);
|
||||
}
|
||||
|
||||
uint16_t usage_page = 0;
|
||||
if (global_state.usage_page.has_value())
|
||||
usage_page = global_state.usage_page.value();
|
||||
if (local_state.usage_stack.front() >> 16)
|
||||
if (!local_state.usage_stack.empty() && local_state.usage_stack.front() >> 16)
|
||||
usage_page = local_state.usage_stack.front() >> 16;
|
||||
if (usage_page == 0)
|
||||
{
|
||||
|
|
@ -612,8 +622,11 @@ namespace Kernel
|
|||
}
|
||||
|
||||
TRY(collection_stack.emplace_back());
|
||||
collection_stack.back().type = report_data[1];
|
||||
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;
|
||||
}
|
||||
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