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;
266 bool registered =
false;
270 if (m_LifetimePins) {
273 retire = !m_LifetimePins;
275 registered = m_Registered;
276 m_Registered =
false;
289 if (notification.meta) {
290 reinterpret_cast<InputFile*
>(notification.meta)->handleInput(notification);
297 if (m_Buffer.
tryWrite(
reinterpret_cast<const uint8_t*
>(©),
sizeof(copy))) {
303 DeviceType type,
bool endpoint)
304 :
File(name, 0, 0, 0, inode, filesystem, 0, parent),
306 m_Endpoint(endpoint),
309 ByteSet(m_KeyState, 0,
sizeof(m_KeyState));
310 ByteSet(m_ButtonState, 0,
sizeof(m_ButtonState));
313EvdevFile::~EvdevFile() {
314 bool registered =
false;
317 registered = m_Registered;
318 m_Registered =
false;
325bool EvdevFile::initialise() {
333 const InputManager::CallbackType filter =
334 m_Type ==
Keyboard ? InputManager::RawKey
335 : (m_Type == Pointer ? InputManager::Mouse : InputManager::AbsoluteMouse);
348 auto* endpoint =
new EvdevFile(
getName(), 0, getFilesystem(), getParent(), m_Type,
true);
349 if (!endpoint || !endpoint->initialise()) {
358 SYSCALL_ERROR(InvalidArgument);
362 return m_Buffer.
read(
reinterpret_cast<uint8_t*
>(buffer), size, bCanBlock);
366 SYSCALL_ERROR(PermissionDenied);
374 return m_Buffer.
canRead(timeout == 1) ? 1 : 0;
384 if (!isEvdevIoctl(command)) {
387 const uint8_t number = ioctlNumber(command);
388 if ((number == 0x40 || number == 0x41) && m_Type == AbsolutePointer) {
391 return number == 0x01 || number == 0x02 || number == 0x03 || number == 0x06 || number == 0x07 ||
392 number == 0x08 || number == 0x09 || (number >= 0x18 && number <= 0x1b) ||
393 (number >= 0x20 && number <= 0x3f) || number == 0x90;
397 const uint8_t number = ioctlNumber(command);
398 const size_t capacity = ioctlSize(command);
399 auto copyOut = [buffer](
const void* value,
size_t size) {
401 SYSCALL_ERROR(BadAddress);
406 if (number == 0x01) {
407 return copyOut(&LinuxEvdevVersion,
sizeof(LinuxEvdevVersion)) ? 0 : -1;
409 if (number == 0x02) {
410 const LinuxInputId id = {LinuxBusVirtual, 0x1,
static_cast<uint16_t
>(m_Type + 1), 1};
411 return copyOut(&
id,
sizeof(
id)) ? 0 : -1;
413 if (number == 0x03) {
414 if (ioctlDirection(command) & 2) {
415 const int repeat[2] = {250, 33};
416 return copyOut(repeat,
sizeof(repeat)) ? 0 : -1;
420 if (number == 0x06 || number == 0x07 || number == 0x08) {
423 ? (m_Type ==
Keyboard ?
"Pedigree keyboard"
424 : (m_Type == Pointer ?
"Pedigree pointer" :
"Pedigree tablet"))
425 : (number == 0x07 ?
"pedigree/input0" :
"");
426 const size_t available = StringLength(value) + 1;
427 const size_t copied = min(capacity, available);
428 if (!copyOut(value, copied)) {
431 return static_cast<int>(copied);
433 if (number == 0x90) {
436 if (number == 0x40 || number == 0x41) {
438 SYSCALL_ERROR(InvalidArgument);
444 info.value = number == 0x40 ? m_AbsoluteX : m_AbsoluteY;
446 info.maximum = 0x7fff;
447 return copyOut(&info,
sizeof(info)) ? 0 : -1;
450 uint8_t result[96] = {};
451 if (number == 0x09) {
453 }
else if (number == 0x18) {
456 MemoryCopy(result, m_KeyState,
sizeof(m_KeyState));
459 for (
size_t i = 0; i < 5; ++i) {
460 if (m_ButtonState[i]) {
461 setBit(result,
sizeof(result), linuxButtonCode(i));
465 }
else if (number >= 0x20 && number <= 0x3f) {
466 const uint8_t eventType = number - 0x20;
467 if (eventType == 0) {
468 setBit(result,
sizeof(result), LinuxEvSyn);
469 setBit(result,
sizeof(result), LinuxEvKey);
470 if (m_Type == Pointer) {
471 setBit(result,
sizeof(result), LinuxEvRelative);
472 }
else if (m_Type == AbsolutePointer) {
473 setBit(result,
sizeof(result), LinuxEvAbsolute);
474 setBit(result,
sizeof(result), LinuxEvRelative);
476 }
else if (eventType == LinuxEvKey) {
479 const uint16_t key = linuxKeyCode(
usage);
481 setBit(result,
sizeof(result), key);
485 for (
size_t i = 0; i < 5; ++i) {
486 setBit(result,
sizeof(result), linuxButtonCode(i));
489 }
else if (eventType == LinuxEvRelative && m_Type !=
Keyboard) {
490 if (m_Type == Pointer) {
491 setBit(result,
sizeof(result), LinuxRelX);
492 setBit(result,
sizeof(result), LinuxRelY);
494 setBit(result,
sizeof(result), LinuxRelWheel);
495 }
else if (eventType == LinuxEvAbsolute && m_Type == AbsolutePointer) {
496 setBit(result,
sizeof(result), LinuxAbsX);
497 setBit(result,
sizeof(result), LinuxAbsY);
501 const size_t copied = min(capacity,
sizeof(result));
502 if (!copyOut(result, copied)) {
505 return static_cast<int>(copied);
523 bool registered =
false;
527 if (m_LifetimePins) {
530 retire = !m_LifetimePins;
532 registered = m_Registered;
533 m_Registered =
false;
545 if (notification.meta) {
546 reinterpret_cast<EvdevFile*
>(notification.meta)->handleInput(notification);
551 if (m_Buffer.
tryWrite(
reinterpret_cast<const uint8_t*
>(events),
560 const Time::Timestamp now = Time::getTimeNanoseconds();
561 auto append = [&](uint16_t type, uint16_t code, int32_t value) {
563 event.seconds = now / Time::Multiplier::Second;
564 event.microseconds = (now % Time::Multiplier::Second) / Time::Multiplier::Microsecond;
570 if (m_Type ==
Keyboard && notification.type == InputManager::RawKey) {
571 const uint16_t key = linuxKeyCode(notification.data.rawkey.
scancode);
575 const bool pressed = !notification.data.rawkey.
keyUp;
579 setBit(m_KeyState,
sizeof(m_KeyState), key);
581 m_KeyState[key / 8] &=
static_cast<uint8_t
>(~(1U << (key % 8)));
584 append(LinuxEvKey, key, pressed ? 1 : 0);
585 }
else if (m_Type == Pointer && notification.type == InputManager::Mouse) {
586 if (notification.data.pointy.relx) {
587 append(LinuxEvRelative, LinuxRelX, notification.data.pointy.relx);
589 if (notification.data.pointy.rely) {
590 append(LinuxEvRelative, LinuxRelY, -notification.data.pointy.rely);
592 if (notification.data.pointy.relz) {
593 append(LinuxEvRelative, LinuxRelWheel, notification.data.pointy.relz);
597 for (
size_t i = 0; i < 5; ++i) {
598 const bool pressed = notification.data.pointy.buttons[i];
599 if (pressed != m_ButtonState[i]) {
600 m_ButtonState[i] = pressed;
601 append(LinuxEvKey, linuxButtonCode(i), pressed ? 1 : 0);
605 }
else if (m_Type == AbsolutePointer && notification.type == InputManager::AbsoluteMouse) {
608 if (!m_HaveAbsolute || notification.data.absolute.x != m_AbsoluteX) {
609 m_AbsoluteX = notification.data.absolute.x;
610 append(LinuxEvAbsolute, LinuxAbsX, m_AbsoluteX);
612 if (!m_HaveAbsolute || notification.data.absolute.y != m_AbsoluteY) {
613 m_AbsoluteY = notification.data.absolute.y;
614 append(LinuxEvAbsolute, LinuxAbsY, m_AbsoluteY);
616 m_HaveAbsolute =
true;
617 for (
size_t i = 0; i < 5; ++i) {
618 const bool pressed = notification.data.absolute.buttons[i];
619 if (pressed != m_ButtonState[i]) {
620 m_ButtonState[i] = pressed;
621 append(LinuxEvKey, linuxButtonCode(i), pressed ? 1 : 0);
625 if (notification.data.absolute.wheel) {
626 append(LinuxEvRelative, LinuxRelWheel, notification.data.absolute.wheel);
uint64_t readableGeneration() const
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
ReadinessGenerations readinessGenerations() 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)