21#include "modules/subsys/posix/InputFile.h"
22#include "pedigree/kernel/LockGuard.h"
23#include "pedigree/kernel/syscallError.h"
24#include "pedigree/kernel/time/Time.h"
26#include "modules/subsys/posix/PosixSubsystem.h"
29constexpr InputManager::CallbackType InputStreamFilter =
30 InputManager::Mouse | InputManager::AbsoluteMouse | InputManager::RawKey |
InputManager::Key;
31constexpr size_t InputBufferRecords = 128;
33constexpr size_t LinuxInputBufferRecords = 256;
34constexpr uint16_t LinuxBusVirtual = 0x06;
35constexpr int LinuxEvdevVersion = 0x010001;
37size_t ioctlSize(
size_t command) {
38 return (command >> 16) & 0x3fff;
41uint8_t ioctlNumber(
size_t command) {
42 return command & 0xff;
45uint8_t ioctlDirection(
size_t command) {
49bool isEvdevIoctl(
size_t command) {
50 return ((command >> 8) & 0xff) ==
'E';
53void setBit(uint8_t* bitmap,
size_t bytes,
size_t bit) {
54 if (bit / 8 < bytes) {
55 bitmap[bit / 8] |=
static_cast<uint8_t
>(1U << (bit % 8));
59uint16_t linuxKeyCode(uint8_t
usage) {
60 static constexpr uint16_t letters[] = {
61 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 50,
62 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,
65 return letters[
usage - 4];
167uint16_t linuxButtonCode(
size_t button) {
168 static constexpr uint16_t buttons[] = {
169 LinuxBtnLeft, LinuxBtnMiddle, LinuxBtnRight, LinuxBtnSide, LinuxBtnExtra,
171 return button <
sizeof(buttons) /
sizeof(buttons[0]) ? buttons[button] : 0;
175InputFile::InputFile(
String name,
size_t inode,
Filesystem* filesystem,
File* parent,
bool endpoint)
176 :
File(name, 0, 0, 0, inode, filesystem, 0, parent),
177 m_Endpoint(endpoint),
179 m_Buffer(InputBufferRecords * sizeof(
InputManager::InputNotification)) {}
181InputFile::~InputFile() {
182 bool registered =
false;
185 registered = m_Registered;
186 m_Registered =
false;
194bool InputFile::initialise() {
219 auto* endpoint =
new InputFile(
getName(), 0, getFilesystem(), getParent(),
true);
220 if (!endpoint || !endpoint->initialise()) {
229 return m_Buffer.
read(
reinterpret_cast<uint8_t*
>(buffer), size, bCanBlock);
241 return m_Buffer.
canRead(timeout == 1) ? 1 : 0;
260 bool registered =
false;
264 if (m_LifetimePins) {
267 retire = !m_LifetimePins;
269 registered = m_Registered;
270 m_Registered =
false;
283 if (notification.meta) {
284 reinterpret_cast<InputFile*
>(notification.meta)->handleInput(notification);
291 if (m_Buffer.
tryWrite(
reinterpret_cast<const uint8_t*
>(©),
sizeof(copy))) {
297 DeviceType type,
bool endpoint)
298 :
File(name, 0, 0, 0, inode, filesystem, 0, parent),
300 m_Endpoint(endpoint),
303 ByteSet(m_KeyState, 0,
sizeof(m_KeyState));
304 ByteSet(m_ButtonState, 0,
sizeof(m_ButtonState));
307EvdevFile::~EvdevFile() {
308 bool registered =
false;
311 registered = m_Registered;
312 m_Registered =
false;
319bool EvdevFile::initialise() {
327 const InputManager::CallbackType filter =
328 m_Type ==
Keyboard ? InputManager::RawKey
329 : (m_Type == Pointer ? InputManager::Mouse : InputManager::AbsoluteMouse);
342 auto* endpoint =
new EvdevFile(
getName(), 0, getFilesystem(), getParent(), m_Type,
true);
343 if (!endpoint || !endpoint->initialise()) {
352 SYSCALL_ERROR(InvalidArgument);
356 return m_Buffer.
read(
reinterpret_cast<uint8_t*
>(buffer), size, bCanBlock);
360 SYSCALL_ERROR(PermissionDenied);
368 return m_Buffer.
canRead(timeout == 1) ? 1 : 0;
372 if (!isEvdevIoctl(command)) {
375 const uint8_t number = ioctlNumber(command);
376 if ((number == 0x40 || number == 0x41) && m_Type == AbsolutePointer) {
379 return number == 0x01 || number == 0x02 || number == 0x03 || number == 0x06 || number == 0x07 ||
380 number == 0x08 || number == 0x09 || (number >= 0x18 && number <= 0x1b) ||
381 (number >= 0x20 && number <= 0x3f) || number == 0x90;
385 const uint8_t number = ioctlNumber(command);
386 const size_t capacity = ioctlSize(command);
387 auto copyOut = [buffer](
const void* value,
size_t size) {
389 SYSCALL_ERROR(BadAddress);
394 if (number == 0x01) {
395 return copyOut(&LinuxEvdevVersion,
sizeof(LinuxEvdevVersion)) ? 0 : -1;
397 if (number == 0x02) {
398 const LinuxInputId id = {LinuxBusVirtual, 0x1,
static_cast<uint16_t
>(m_Type + 1), 1};
399 return copyOut(&
id,
sizeof(
id)) ? 0 : -1;
401 if (number == 0x03) {
402 if (ioctlDirection(command) & 2) {
403 const int repeat[2] = {250, 33};
404 return copyOut(repeat,
sizeof(repeat)) ? 0 : -1;
408 if (number == 0x06 || number == 0x07 || number == 0x08) {
411 ? (m_Type ==
Keyboard ?
"Pedigree keyboard"
412 : (m_Type == Pointer ?
"Pedigree pointer" :
"Pedigree tablet"))
413 : (number == 0x07 ?
"pedigree/input0" :
"");
414 const size_t available = StringLength(value) + 1;
415 const size_t copied = min(capacity, available);
416 if (!copyOut(value, copied)) {
419 return static_cast<int>(copied);
421 if (number == 0x90) {
424 if (number == 0x40 || number == 0x41) {
426 SYSCALL_ERROR(InvalidArgument);
432 info.value = number == 0x40 ? m_AbsoluteX : m_AbsoluteY;
434 info.maximum = 0x7fff;
435 return copyOut(&info,
sizeof(info)) ? 0 : -1;
438 uint8_t result[96] = {};
439 if (number == 0x09) {
441 }
else if (number == 0x18) {
444 MemoryCopy(result, m_KeyState,
sizeof(m_KeyState));
447 for (
size_t i = 0; i < 5; ++i) {
448 if (m_ButtonState[i]) {
449 setBit(result,
sizeof(result), linuxButtonCode(i));
453 }
else if (number >= 0x20 && number <= 0x3f) {
454 const uint8_t eventType = number - 0x20;
455 if (eventType == 0) {
456 setBit(result,
sizeof(result), LinuxEvSyn);
457 setBit(result,
sizeof(result), LinuxEvKey);
458 if (m_Type == Pointer) {
459 setBit(result,
sizeof(result), LinuxEvRelative);
460 }
else if (m_Type == AbsolutePointer) {
461 setBit(result,
sizeof(result), LinuxEvAbsolute);
462 setBit(result,
sizeof(result), LinuxEvRelative);
464 }
else if (eventType == LinuxEvKey) {
467 const uint16_t key = linuxKeyCode(
usage);
469 setBit(result,
sizeof(result), key);
473 for (
size_t i = 0; i < 5; ++i) {
474 setBit(result,
sizeof(result), linuxButtonCode(i));
477 }
else if (eventType == LinuxEvRelative && m_Type !=
Keyboard) {
478 if (m_Type == Pointer) {
479 setBit(result,
sizeof(result), LinuxRelX);
480 setBit(result,
sizeof(result), LinuxRelY);
482 setBit(result,
sizeof(result), LinuxRelWheel);
483 }
else if (eventType == LinuxEvAbsolute && m_Type == AbsolutePointer) {
484 setBit(result,
sizeof(result), LinuxAbsX);
485 setBit(result,
sizeof(result), LinuxAbsY);
489 const size_t copied = min(capacity,
sizeof(result));
490 if (!copyOut(result, copied)) {
493 return static_cast<int>(copied);
511 bool registered =
false;
515 if (m_LifetimePins) {
518 retire = !m_LifetimePins;
520 registered = m_Registered;
521 m_Registered =
false;
533 if (notification.meta) {
534 reinterpret_cast<EvdevFile*
>(notification.meta)->handleInput(notification);
539 if (m_Buffer.
tryWrite(
reinterpret_cast<const uint8_t*
>(events),
548 const Time::Timestamp now = Time::getTimeNanoseconds();
549 auto append = [&](uint16_t type, uint16_t code, int32_t value) {
551 event.seconds = now / Time::Multiplier::Second;
552 event.microseconds = (now % Time::Multiplier::Second) / Time::Multiplier::Microsecond;
558 if (m_Type ==
Keyboard && notification.type == InputManager::RawKey) {
559 const uint16_t key = linuxKeyCode(notification.data.rawkey.
scancode);
563 const bool pressed = !notification.data.rawkey.
keyUp;
567 setBit(m_KeyState,
sizeof(m_KeyState), key);
569 m_KeyState[key / 8] &=
static_cast<uint8_t
>(~(1U << (key % 8)));
572 append(LinuxEvKey, key, pressed ? 1 : 0);
573 }
else if (m_Type == Pointer && notification.type == InputManager::Mouse) {
574 if (notification.data.pointy.relx) {
575 append(LinuxEvRelative, LinuxRelX, notification.data.pointy.relx);
577 if (notification.data.pointy.rely) {
578 append(LinuxEvRelative, LinuxRelY, -notification.data.pointy.rely);
580 if (notification.data.pointy.relz) {
581 append(LinuxEvRelative, LinuxRelWheel, notification.data.pointy.relz);
585 for (
size_t i = 0; i < 5; ++i) {
586 const bool pressed = notification.data.pointy.buttons[i];
587 if (pressed != m_ButtonState[i]) {
588 m_ButtonState[i] = pressed;
589 append(LinuxEvKey, linuxButtonCode(i), pressed ? 1 : 0);
593 }
else if (m_Type == AbsolutePointer && notification.type == InputManager::AbsoluteMouse) {
596 if (!m_HaveAbsolute || notification.data.absolute.x != m_AbsoluteX) {
597 m_AbsoluteX = notification.data.absolute.x;
598 append(LinuxEvAbsolute, LinuxAbsX, m_AbsoluteX);
600 if (!m_HaveAbsolute || notification.data.absolute.y != m_AbsoluteY) {
601 m_AbsoluteY = notification.data.absolute.y;
602 append(LinuxEvAbsolute, LinuxAbsY, m_AbsoluteY);
604 m_HaveAbsolute =
true;
605 for (
size_t i = 0; i < 5; ++i) {
606 const bool pressed = notification.data.absolute.buttons[i];
607 if (pressed != m_ButtonState[i]) {
608 m_ButtonState[i] = pressed;
609 append(LinuxEvKey, linuxButtonCode(i), pressed ? 1 : 0);
613 if (notification.data.absolute.wheel) {
614 append(LinuxEvRelative, LinuxRelWheel, notification.data.absolute.wheel);
bool tryWrite(const T *buffer, size_t count)
size_t read(T *buffer, size_t count, bool block=true)
int command(size_t command, void *buffer) override
uint64_t readBytewise(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true) override
bool supports(size_t command) const override
uint64_t writeBytewise(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true) override
int select(bool bWriting=false, int timeout=0) override
bool retainVfsReference() override
void releaseVfsReference() override
virtual bool retainVfsReference()
uint64_t append(uint64_t size, uintptr_t buffer, uint64_t &location, bool bCanBlock=true)
virtual void releaseVfsReference()
void setGidOnly(size_t gid)
void setPermissionsOnly(uint32_t perms)
void setUidOnly(size_t uid)
static bool copyToUser(void *destination, const void *source, size_t count, size_t elementSize=1)