mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 12:48:22 +00:00
input: add new evdev subsystem
Co-authored-by: Matheus <matheusuky@gmail.com>
This commit is contained in:
@@ -2,9 +2,11 @@
|
||||
#define _CONSOLE_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <kernel/input.h>
|
||||
|
||||
void console_init();
|
||||
void console_putc(char c);
|
||||
size_t console_write(char *str, size_t size);
|
||||
void console_process_events(input_event_t *events, int count);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#define DEV_MAJOR_PTY 12
|
||||
#define DEV_MAJOR_ACPI 13
|
||||
#define DEV_MAJOR_PROF 14
|
||||
#define DEV_MAJOR_INPUT 15
|
||||
|
||||
typedef struct {
|
||||
int (*open)(int minor, vnode_t **vnode, int flags);
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
#ifndef _INPUT_H
|
||||
#define _INPUT_H
|
||||
|
||||
#include <kernel/poll.h>
|
||||
#include <kernel/timekeeper.h>
|
||||
#include <kernel/vfs.h>
|
||||
#include <bitmap.h>
|
||||
#include <list.h>
|
||||
#include <ringbuffer.h>
|
||||
#include <semaphore.h>
|
||||
#include <spinlock.h>
|
||||
|
||||
typedef struct {
|
||||
timeval_t time;
|
||||
uint16_t type;
|
||||
uint16_t code;
|
||||
int32_t value;
|
||||
} input_event_t;
|
||||
|
||||
typedef struct {
|
||||
int32_t value;
|
||||
int32_t min;
|
||||
int32_t max;
|
||||
int32_t fuzz;
|
||||
int32_t flat;
|
||||
int32_t res;
|
||||
} input_absinfo_t;
|
||||
|
||||
#define INPUT_DEVICE_BUS_PCI 0x1
|
||||
#define INPUT_DEVICE_BUS_USB 0x3
|
||||
#define INPUT_DEVICE_BUS_VIRTUAL 0x6
|
||||
#define INPUT_DEVICE_BUS_I8042 0x11
|
||||
|
||||
#define INPUT_PROP_POINTER 0x0
|
||||
#define INPUT_PROP_DIRECT 0x1
|
||||
#define INPUT_PROP_MAX 0x1f
|
||||
#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1)
|
||||
|
||||
#define INPUT_EV_SYN 0x0
|
||||
#define INPUT_EV_KEY 0x1
|
||||
#define INPUT_EV_REL 0x2
|
||||
#define INPUT_EV_ABS 0x3
|
||||
#define INPUT_EV_MSC 0x4
|
||||
#define INPUT_EV_MAX 0x1f
|
||||
#define INPUT_EV_CNT (INPUT_EV_MAX + 1)
|
||||
|
||||
#define INPUT_SYN_REPORT 0x0
|
||||
#define INPUT_SYN_DROPPED 0x3
|
||||
#define INPUT_SYN_MAX 0xf
|
||||
#define INPUT_SYN_CNT (INPUT_SYN_MAX + 1)
|
||||
|
||||
#define INPUT_KEY_RESERVED 0x0
|
||||
#define INPUT_KEY_ESC 0x1
|
||||
#define INPUT_KEY_1 0x2
|
||||
#define INPUT_KEY_2 0x3
|
||||
#define INPUT_KEY_3 0x4
|
||||
#define INPUT_KEY_4 0x5
|
||||
#define INPUT_KEY_5 0x6
|
||||
#define INPUT_KEY_6 0x7
|
||||
#define INPUT_KEY_7 0x8
|
||||
#define INPUT_KEY_8 0x9
|
||||
#define INPUT_KEY_9 0xa
|
||||
#define INPUT_KEY_0 0xb
|
||||
#define INPUT_KEY_MINUS 0xc
|
||||
#define INPUT_KEY_EQUAL 0xd
|
||||
#define INPUT_KEY_BACKSPACE 0xe
|
||||
#define INPUT_KEY_TAB 0xf
|
||||
#define INPUT_KEY_Q 0x10
|
||||
#define INPUT_KEY_W 0x11
|
||||
#define INPUT_KEY_E 0x12
|
||||
#define INPUT_KEY_R 0x13
|
||||
#define INPUT_KEY_T 0x14
|
||||
#define INPUT_KEY_Y 0x15
|
||||
#define INPUT_KEY_U 0x16
|
||||
#define INPUT_KEY_I 0x17
|
||||
#define INPUT_KEY_O 0x18
|
||||
#define INPUT_KEY_P 0x19
|
||||
#define INPUT_KEY_LEFTBRACE 0x1a
|
||||
#define INPUT_KEY_RIGHTBRACE 0x1b
|
||||
#define INPUT_KEY_ENTER 0x1c
|
||||
#define INPUT_KEY_LEFTCTRL 0x1d
|
||||
#define INPUT_KEY_A 0x1e
|
||||
#define INPUT_KEY_S 0x1f
|
||||
#define INPUT_KEY_D 0x20
|
||||
#define INPUT_KEY_F 0x21
|
||||
#define INPUT_KEY_G 0x22
|
||||
#define INPUT_KEY_H 0x23
|
||||
#define INPUT_KEY_J 0x24
|
||||
#define INPUT_KEY_K 0x25
|
||||
#define INPUT_KEY_L 0x26
|
||||
#define INPUT_KEY_SEMICOLON 0x27
|
||||
#define INPUT_KEY_APOSTROPHE 0x28
|
||||
#define INPUT_KEY_GRAVE 0x29
|
||||
#define INPUT_KEY_LEFTSHIFT 0x2a
|
||||
#define INPUT_KEY_BACKSLASH 0x2b
|
||||
#define INPUT_KEY_Z 0x2c
|
||||
#define INPUT_KEY_X 0x2d
|
||||
#define INPUT_KEY_C 0x2e
|
||||
#define INPUT_KEY_V 0x2f
|
||||
#define INPUT_KEY_B 0x30
|
||||
#define INPUT_KEY_N 0x31
|
||||
#define INPUT_KEY_M 0x32
|
||||
#define INPUT_KEY_COMMA 0x33
|
||||
#define INPUT_KEY_DOT 0x34
|
||||
#define INPUT_KEY_SLASH 0x35
|
||||
#define INPUT_KEY_RIGHTSHIFT 0x36
|
||||
#define INPUT_KEY_KPASTERISK 0x37
|
||||
#define INPUT_KEY_LEFTALT 0x38
|
||||
#define INPUT_KEY_SPACE 0x39
|
||||
#define INPUT_KEY_CAPSLOCK 0x3a
|
||||
#define INPUT_KEY_F1 0x3b
|
||||
#define INPUT_KEY_F2 0x3c
|
||||
#define INPUT_KEY_F3 0x3d
|
||||
#define INPUT_KEY_F4 0x3e
|
||||
#define INPUT_KEY_F5 0x3f
|
||||
#define INPUT_KEY_F6 0x40
|
||||
#define INPUT_KEY_F7 0x41
|
||||
#define INPUT_KEY_F8 0x42
|
||||
#define INPUT_KEY_F9 0x43
|
||||
#define INPUT_KEY_F10 0x44
|
||||
#define INPUT_KEY_NUMLOCK 0x45
|
||||
#define INPUT_KEY_SCROLLLOCK 0x46
|
||||
#define INPUT_KEY_KP7 0x47
|
||||
#define INPUT_KEY_KP8 0x48
|
||||
#define INPUT_KEY_KP9 0x49
|
||||
#define INPUT_KEY_KPMINUS 0x4a
|
||||
#define INPUT_KEY_KP4 0x4b
|
||||
#define INPUT_KEY_KP5 0x4c
|
||||
#define INPUT_KEY_KP6 0x4d
|
||||
#define INPUT_KEY_KPPLUS 0x4e
|
||||
#define INPUT_KEY_KP1 0x4f
|
||||
#define INPUT_KEY_KP2 0x50
|
||||
#define INPUT_KEY_KP3 0x51
|
||||
#define INPUT_KEY_KP0 0x52
|
||||
#define INPUT_KEY_KPDOT 0x53
|
||||
#define INPUT_KEY_F11 0x57
|
||||
#define INPUT_KEY_F12 0x58
|
||||
#define INPUT_KEY_KPENTER 0x60
|
||||
#define INPUT_KEY_RIGHTCTRL 0x61
|
||||
#define INPUT_KEY_KPSLASH 0x62
|
||||
#define INPUT_KEY_RIGHTALT 0x64
|
||||
#define INPUT_KEY_HOME 0x66
|
||||
#define INPUT_KEY_UP 0x67
|
||||
#define INPUT_KEY_PAGEUP 0x68
|
||||
#define INPUT_KEY_LEFT 0x69
|
||||
#define INPUT_KEY_RIGHT 0x6a
|
||||
#define INPUT_KEY_END 0x6b
|
||||
#define INPUT_KEY_DOWN 0x6c
|
||||
#define INPUT_KEY_PAGEDOWN 0x6d
|
||||
#define INPUT_KEY_INSERT 0x6e
|
||||
#define INPUT_KEY_DELETE 0x6f
|
||||
#define INPUT_KEY_LEFTMETA 0x7d
|
||||
#define INPUT_KEY_RIGHTMETA 0x7e
|
||||
#define INPUT_KEY_F13 0xb7
|
||||
#define INPUT_KEY_F14 0xb8
|
||||
#define INPUT_KEY_F15 0xb9
|
||||
#define INPUT_KEY_F16 0xba
|
||||
#define INPUT_KEY_F17 0xbb
|
||||
#define INPUT_KEY_F18 0xbc
|
||||
#define INPUT_KEY_F19 0xbd
|
||||
#define INPUT_KEY_F20 0xbe
|
||||
#define INPUT_KEY_F21 0xbf
|
||||
#define INPUT_KEY_F22 0xc0
|
||||
#define INPUT_KEY_F23 0xc1
|
||||
#define INPUT_KEY_F24 0xc2
|
||||
#define INPUT_KEY_BTN_LEFT 0x110
|
||||
#define INPUT_KEY_BTN_RIGHT 0x111
|
||||
#define INPUT_KEY_BTN_MIDDLE 0x112
|
||||
#define INPUT_KEY_BTN_SIDE 0x113
|
||||
#define INPUT_KEY_BTN_EXTRA 0x114
|
||||
#define INPUT_KEY_MAX 0x2ff
|
||||
#define INPUT_KEY_CNT (INPUT_KEY_MAX + 1)
|
||||
|
||||
#define INPUT_REL_X 0x0
|
||||
#define INPUT_REL_Y 0x1
|
||||
#define INPUT_REL_WHEEL 0x8
|
||||
#define INPUT_REL_MAX 0xf
|
||||
#define INPUT_REL_CNT (INPUT_REL_MAX + 1)
|
||||
|
||||
#define INPUT_ABS_X 0x0
|
||||
#define INPUT_ABS_Y 0x1
|
||||
#define INPUT_ABS_MAX 0x3f
|
||||
#define INPUT_ABS_CNT (INPUT_ABS_MAX + 1)
|
||||
|
||||
typedef struct input_device input_device_t;
|
||||
|
||||
typedef struct {
|
||||
list_node_t node;
|
||||
|
||||
spinlock_t lock;
|
||||
pollheader_t poll_header;
|
||||
mutex_t mutex; // for userspace to not race
|
||||
ringbuffer_t buffer;
|
||||
|
||||
input_device_t *device;
|
||||
vnode_t *vnode;
|
||||
} input_listener_t;
|
||||
|
||||
struct input_device {
|
||||
spinlock_t lock;
|
||||
list_t listeners;
|
||||
|
||||
int clock_id;
|
||||
|
||||
char name[128];
|
||||
char phys[64];
|
||||
char uniq[64];
|
||||
|
||||
bitmap_t prop_bits;
|
||||
bitmap_t ev_bits;
|
||||
bitmap_t syn_bits;
|
||||
bitmap_t key_bits;
|
||||
bitmap_t rel_bits;
|
||||
bitmap_t abs_bits;
|
||||
|
||||
uint16_t id_bus;
|
||||
uint16_t id_vendor;
|
||||
uint16_t id_product;
|
||||
uint16_t id_version;
|
||||
|
||||
uint16_t ver_major;
|
||||
uint8_t ver_minor;
|
||||
uint8_t ver_patch;
|
||||
};
|
||||
|
||||
input_device_t *input_new();
|
||||
|
||||
// Posts the given input events to the device's event queue followed by a SYN_REPORT event.
|
||||
void input_queue_packet(input_device_t *dev, input_event_t *events, int count);
|
||||
|
||||
#endif
|
||||
@@ -18,6 +18,7 @@
|
||||
#define IPL_NET 400
|
||||
#define IPL_DISK 500
|
||||
#define IPL_SERIAL 550
|
||||
#define IPL_INPUT 600
|
||||
#define IPL_KEYBOARD 600
|
||||
#define IPL_MOUSE 650
|
||||
#define IPL_ACPI 700
|
||||
|
||||
+162
-32
@@ -5,16 +5,31 @@
|
||||
#include <kernel/term.h>
|
||||
#include <kernel/devfs.h>
|
||||
#include <errno.h>
|
||||
#include <kernel/keyboard.h>
|
||||
#include <termios.h>
|
||||
#include <kernel/poll.h>
|
||||
#include <kernel/tty.h>
|
||||
#include <kernel/init.h>
|
||||
|
||||
static spinlock_t input_buffer_lock = SPINLOCK_INIT_VALUE;
|
||||
static ringbuffer_t input_buffer;
|
||||
static semaphore_t input_sem;
|
||||
|
||||
static mutex_t writemutex;
|
||||
static thread_t *thread;
|
||||
static tty_t *tty;
|
||||
|
||||
static size_t console_ttywrite(void *internal, char *str, size_t count) {
|
||||
return console_write(str, count);
|
||||
}
|
||||
|
||||
void console_putc(char c) {
|
||||
if (c == '\n') {
|
||||
console_write("\r\n", 2);
|
||||
} else {
|
||||
console_write(&c, 1);
|
||||
}
|
||||
}
|
||||
|
||||
size_t console_write(char *str, size_t count) {
|
||||
MUTEX_ACQUIRE(&writemutex);
|
||||
|
||||
@@ -24,15 +39,17 @@ size_t console_write(char *str, size_t count) {
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t console_ttywrite(void *internal, char *str, size_t count) {
|
||||
return console_write(str, count);
|
||||
}
|
||||
void console_process_events(input_event_t *events, int count) {
|
||||
long ipl = spinlock_acquire_raise_ipl(&input_buffer_lock, IPL_INPUT);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (events[i].type != INPUT_EV_KEY || events[i].code >= INPUT_KEY_BTN_LEFT)
|
||||
continue;
|
||||
|
||||
void console_putc(char c) {
|
||||
if (c == '\n')
|
||||
console_write("\n\r", 2);
|
||||
else
|
||||
console_write(&c, 1);
|
||||
size_t written = ringbuffer_write(&input_buffer, &events[i], sizeof(input_event_t));
|
||||
if (written == sizeof(input_event_t))
|
||||
semaphore_signal(&input_sem);
|
||||
}
|
||||
spinlock_release_lower_ipl(&input_buffer_lock, ipl);
|
||||
}
|
||||
|
||||
// taken from https://en.wikipedia.org/wiki/ANSI_escape_code#Terminal_input_sequences
|
||||
@@ -49,55 +66,165 @@ void console_putc(char c) {
|
||||
#define RIGHT_STR "\e[C"
|
||||
#define LEFT_STR "\e[D"
|
||||
|
||||
static const char key_to_ascii_normal[] = {
|
||||
[INPUT_KEY_ESC] = '\e', [INPUT_KEY_1] = '1',
|
||||
[INPUT_KEY_2] = '2', [INPUT_KEY_3] = '3',
|
||||
[INPUT_KEY_4] = '4', [INPUT_KEY_5] = '5',
|
||||
[INPUT_KEY_6] = '6', [INPUT_KEY_7] = '7',
|
||||
[INPUT_KEY_8] = '8', [INPUT_KEY_9] = '9',
|
||||
[INPUT_KEY_0] = '0', [INPUT_KEY_MINUS] = '-',
|
||||
[INPUT_KEY_EQUAL] = '=', [INPUT_KEY_BACKSPACE] = '\b',
|
||||
[INPUT_KEY_TAB] = '\t', [INPUT_KEY_Q] = 'q',
|
||||
[INPUT_KEY_W] = 'w', [INPUT_KEY_E] = 'e',
|
||||
[INPUT_KEY_R] = 'r', [INPUT_KEY_T] = 't',
|
||||
[INPUT_KEY_Y] = 'y', [INPUT_KEY_U] = 'u',
|
||||
[INPUT_KEY_I] = 'i', [INPUT_KEY_O] = 'o',
|
||||
[INPUT_KEY_P] = 'p', [INPUT_KEY_LEFTBRACE] = '[',
|
||||
[INPUT_KEY_RIGHTBRACE] = ']', [INPUT_KEY_ENTER] = '\r',
|
||||
[INPUT_KEY_A] = 'a', [INPUT_KEY_S] = 's',
|
||||
[INPUT_KEY_D] = 'd', [INPUT_KEY_F] = 'f',
|
||||
[INPUT_KEY_G] = 'g', [INPUT_KEY_H] = 'h',
|
||||
[INPUT_KEY_J] = 'j', [INPUT_KEY_K] = 'k',
|
||||
[INPUT_KEY_L] = 'l', [INPUT_KEY_SEMICOLON] = ';',
|
||||
[INPUT_KEY_APOSTROPHE] = '\'', [INPUT_KEY_GRAVE] = '`',
|
||||
[INPUT_KEY_BACKSLASH] = '\\', [INPUT_KEY_Z] = 'z',
|
||||
[INPUT_KEY_X] = 'x', [INPUT_KEY_C] = 'c',
|
||||
[INPUT_KEY_V] = 'v', [INPUT_KEY_B] = 'b',
|
||||
[INPUT_KEY_N] = 'n', [INPUT_KEY_M] = 'm',
|
||||
[INPUT_KEY_COMMA] = ',', [INPUT_KEY_DOT] = '.',
|
||||
[INPUT_KEY_SLASH] = '/', [INPUT_KEY_KPASTERISK] = '*',
|
||||
[INPUT_KEY_SPACE] = ' ', [INPUT_KEY_KP7] = '7',
|
||||
[INPUT_KEY_KP8] = '8', [INPUT_KEY_KP9] = '9',
|
||||
[INPUT_KEY_KPMINUS] = '-', [INPUT_KEY_KP4] = '4',
|
||||
[INPUT_KEY_KP5] = '5', [INPUT_KEY_KP6] = '6',
|
||||
[INPUT_KEY_KPPLUS] = '+', [INPUT_KEY_KP1] = '1',
|
||||
[INPUT_KEY_KP2] = '2', [INPUT_KEY_KP3] = '3',
|
||||
[INPUT_KEY_KP0] = '0', [INPUT_KEY_KPDOT] = '.',
|
||||
[INPUT_KEY_KPENTER] = '\r', [INPUT_KEY_KPSLASH] = '/',
|
||||
};
|
||||
|
||||
static const char key_to_ascii_shift[] = {
|
||||
[INPUT_KEY_ESC] = '\e', [INPUT_KEY_1] = '!',
|
||||
[INPUT_KEY_2] = '@', [INPUT_KEY_3] = '#',
|
||||
[INPUT_KEY_4] = '$', [INPUT_KEY_5] = '%',
|
||||
[INPUT_KEY_6] = '^', [INPUT_KEY_7] = '&',
|
||||
[INPUT_KEY_8] = '*', [INPUT_KEY_9] = '(',
|
||||
[INPUT_KEY_0] = ')', [INPUT_KEY_MINUS] = '_',
|
||||
[INPUT_KEY_EQUAL] = '+', [INPUT_KEY_BACKSPACE] = '\b',
|
||||
[INPUT_KEY_TAB] = '\t', [INPUT_KEY_Q] = 'Q',
|
||||
[INPUT_KEY_W] = 'W', [INPUT_KEY_E] = 'E',
|
||||
[INPUT_KEY_R] = 'R', [INPUT_KEY_T] = 'T',
|
||||
[INPUT_KEY_Y] = 'Y', [INPUT_KEY_U] = 'U',
|
||||
[INPUT_KEY_I] = 'I', [INPUT_KEY_O] = 'O',
|
||||
[INPUT_KEY_P] = 'P', [INPUT_KEY_LEFTBRACE] = '{',
|
||||
[INPUT_KEY_RIGHTBRACE] = '}', [INPUT_KEY_ENTER] = '\r',
|
||||
[INPUT_KEY_A] = 'A', [INPUT_KEY_S] = 'S',
|
||||
[INPUT_KEY_D] = 'D', [INPUT_KEY_F] = 'F',
|
||||
[INPUT_KEY_G] = 'G', [INPUT_KEY_H] = 'H',
|
||||
[INPUT_KEY_J] = 'J', [INPUT_KEY_K] = 'K',
|
||||
[INPUT_KEY_L] = 'L', [INPUT_KEY_SEMICOLON] = ':',
|
||||
[INPUT_KEY_APOSTROPHE] = '"', [INPUT_KEY_GRAVE] = '~',
|
||||
[INPUT_KEY_BACKSLASH] = '|', [INPUT_KEY_Z] = 'Z',
|
||||
[INPUT_KEY_X] = 'X', [INPUT_KEY_C] = 'C',
|
||||
[INPUT_KEY_V] = 'V', [INPUT_KEY_B] = 'B',
|
||||
[INPUT_KEY_N] = 'N', [INPUT_KEY_M] = 'M',
|
||||
[INPUT_KEY_COMMA] = '<', [INPUT_KEY_DOT] = '>',
|
||||
[INPUT_KEY_SLASH] = '?', [INPUT_KEY_KPASTERISK] = '*',
|
||||
[INPUT_KEY_SPACE] = ' ', [INPUT_KEY_KP7] = '7',
|
||||
[INPUT_KEY_KP8] = '8', [INPUT_KEY_KP9] = '9',
|
||||
[INPUT_KEY_KPMINUS] = '-', [INPUT_KEY_KP4] = '4',
|
||||
[INPUT_KEY_KP5] = '5', [INPUT_KEY_KP6] = '6',
|
||||
[INPUT_KEY_KPPLUS] = '+', [INPUT_KEY_KP1] = '1',
|
||||
[INPUT_KEY_KP2] = '2', [INPUT_KEY_KP3] = '3',
|
||||
[INPUT_KEY_KP0] = '0', [INPUT_KEY_KPDOT] = '.',
|
||||
[INPUT_KEY_KPENTER] = '\r', [INPUT_KEY_KPSLASH] = '/',
|
||||
};
|
||||
|
||||
static void consolethread() {
|
||||
bool left_ctrl = false;
|
||||
bool right_ctrl = false;
|
||||
bool left_shift = false;
|
||||
bool right_shift = false;
|
||||
|
||||
for (;;) {
|
||||
kbpacket_t packet;
|
||||
keyboard_wait(keyboard_console, &packet);
|
||||
if (packet.flags & KBPACKET_FLAGS_RELEASED)
|
||||
continue;
|
||||
semaphore_wait(&input_sem, false);
|
||||
__assert(RINGBUFFER_DATACOUNT(&input_buffer) >= sizeof(input_event_t));
|
||||
|
||||
if (packet.ascii) {
|
||||
// control characters
|
||||
if (packet.flags & (KBPACKET_FLAGS_LEFTCTRL | KBPACKET_FLAGS_RIGHTCTRL)) {
|
||||
if (!((packet.ascii >= 'a' && packet.ascii <= 'z') || (packet.ascii >= 'A' && packet.ascii <= '\\')))
|
||||
continue;
|
||||
input_event_t ev;
|
||||
__assert(ringbuffer_read(&input_buffer, &ev, sizeof(input_event_t)) == sizeof(input_event_t));
|
||||
|
||||
packet.ascii = packet.ascii >= 'a' ? packet.ascii - 0x60 : packet.ascii - 0x40;
|
||||
if (ev.code == INPUT_KEY_LEFTCTRL) {
|
||||
left_ctrl = ev.value != 0;
|
||||
continue;
|
||||
} else if (ev.code == INPUT_KEY_RIGHTCTRL) {
|
||||
right_ctrl = ev.value != 0;
|
||||
continue;
|
||||
} else if (ev.code == INPUT_KEY_LEFTSHIFT) {
|
||||
left_shift = ev.value != 0;
|
||||
continue;
|
||||
} else if (ev.code == INPUT_KEY_RIGHTSHIFT) {
|
||||
right_shift = ev.value != 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
tty_process(tty, packet.ascii);
|
||||
bool ctrl = left_ctrl || right_ctrl;
|
||||
bool shift = left_shift || right_shift;
|
||||
|
||||
// we only care about key presses, not releases
|
||||
if (ev.value == 0)
|
||||
continue;
|
||||
|
||||
char ascii = 0;
|
||||
if (shift) {
|
||||
if (ev.code < sizeof(key_to_ascii_shift))
|
||||
ascii = key_to_ascii_shift[ev.code];
|
||||
} else {
|
||||
if (ev.code < sizeof(key_to_ascii_normal))
|
||||
ascii = key_to_ascii_normal[ev.code];
|
||||
}
|
||||
|
||||
if (ascii != 0) {
|
||||
if (ctrl) {
|
||||
// control characters
|
||||
if (!((ascii >= 'a' && ascii <= 'z') || (ascii >= 'A' && ascii <= '\\')))
|
||||
continue;
|
||||
|
||||
ascii = ascii >= 'a' ? ascii - 0x60 : ascii - 0x40;
|
||||
}
|
||||
|
||||
tty_process(tty, ascii);
|
||||
} else {
|
||||
// no ascii for key but we can send in a escape sequence for it
|
||||
char *target = NULL;
|
||||
switch (packet.keycode) {
|
||||
case KEYCODE_HOME:
|
||||
switch (ev.code) {
|
||||
case INPUT_KEY_HOME:
|
||||
target = HOME_STR;
|
||||
break;
|
||||
case KEYCODE_INSERT:
|
||||
case INPUT_KEY_INSERT:
|
||||
target = INSERT_STR;
|
||||
break;
|
||||
case KEYCODE_DELETE:
|
||||
case INPUT_KEY_DELETE:
|
||||
target = DELETE_STR;
|
||||
break;
|
||||
case KEYCODE_END:
|
||||
case INPUT_KEY_END:
|
||||
target = END_STR;
|
||||
break;
|
||||
case KEYCODE_PAGEUP:
|
||||
case INPUT_KEY_PAGEUP:
|
||||
target = PGUP_STR;
|
||||
break;
|
||||
case KEYCODE_PAGEDOWN:
|
||||
case INPUT_KEY_PAGEDOWN:
|
||||
target = PGDN_STR;
|
||||
break;
|
||||
case KEYCODE_UP:
|
||||
case INPUT_KEY_UP:
|
||||
target = UP_STR;
|
||||
break;
|
||||
case KEYCODE_DOWN:
|
||||
case INPUT_KEY_DOWN:
|
||||
target = DOWN_STR;
|
||||
break;
|
||||
case KEYCODE_RIGHT:
|
||||
case INPUT_KEY_RIGHT:
|
||||
target = RIGHT_STR;
|
||||
break;
|
||||
case KEYCODE_LEFT:
|
||||
case INPUT_KEY_LEFT:
|
||||
target = LEFT_STR;
|
||||
break;
|
||||
default:
|
||||
@@ -112,6 +239,9 @@ static void consolethread() {
|
||||
}
|
||||
|
||||
void console_init() {
|
||||
SEMAPHORE_INIT(&input_sem, 0);
|
||||
ringbuffer_init(&input_buffer, 128 * sizeof(input_event_t));
|
||||
|
||||
MUTEX_INIT(&writemutex);
|
||||
|
||||
thread = sched_newthread(consolethread, PAGE_SIZE * 16, 0, NULL, NULL);
|
||||
@@ -131,4 +261,4 @@ void console_init() {
|
||||
logging_sethook(console_putc);
|
||||
}
|
||||
|
||||
INIT_ROUTINE_DEFINE(console, INIT_ROUTINE_FLAGS_NONE, console_init, scheduler, keyboard);
|
||||
INIT_ROUTINE_DEFINE(console, INIT_ROUTINE_FLAGS_NONE, console_init, scheduler);
|
||||
|
||||
@@ -0,0 +1,498 @@
|
||||
#include <kernel/alloc.h>
|
||||
#include <kernel/console.h>
|
||||
#include <kernel/devfs.h>
|
||||
#include <kernel/init.h>
|
||||
#include <kernel/input.h>
|
||||
#include <kernel/usercopy.h>
|
||||
#include <logging.h>
|
||||
|
||||
#define MAX_DEVICES 256
|
||||
|
||||
#define INPUT_DEV_BUFFER_SIZE (128 * sizeof(input_event_t))
|
||||
|
||||
static int input_dev_count = 0;
|
||||
|
||||
BITMAP_DEFINE_STATIC(listener_minor_bitmap, MAX_DEVICES);
|
||||
static MUTEX_DEFINE(minor_bitmap_mutex);
|
||||
static MUTEX_DEFINE(input_dev_table_lock);
|
||||
static hashtable_t input_dev_table;
|
||||
static hashtable_t input_listener_table;
|
||||
|
||||
static devops_t input_dev_ops;
|
||||
static devops_t input_listener_ops;
|
||||
|
||||
static void *get(int minor) {
|
||||
hashtable_t *table;
|
||||
if (minor >= MAX_DEVICES) {
|
||||
table = &input_listener_table;
|
||||
minor -= MAX_DEVICES;
|
||||
} else {
|
||||
if (minor >= input_dev_count)
|
||||
return NULL;
|
||||
table = &input_dev_table;
|
||||
}
|
||||
|
||||
void *result;
|
||||
|
||||
MUTEX_ACQUIRE(&input_dev_table_lock);
|
||||
int err = hashtable_get(table, &result, &minor, sizeof(minor));
|
||||
MUTEX_RELEASE(&input_dev_table_lock);
|
||||
|
||||
return err ? NULL : result;
|
||||
}
|
||||
|
||||
static int listener_minor_allocate(void) {
|
||||
MUTEX_ACQUIRE(&minor_bitmap_mutex);
|
||||
|
||||
int output = bitmap_find_first_set(&listener_minor_bitmap);
|
||||
if (output >= 0)
|
||||
bitmap_set(&listener_minor_bitmap, output, 0);
|
||||
|
||||
MUTEX_RELEASE(&minor_bitmap_mutex);
|
||||
return output;
|
||||
}
|
||||
|
||||
static void listener_minor_free(int minor) {
|
||||
MUTEX_ACQUIRE(&minor_bitmap_mutex);
|
||||
bitmap_set(&listener_minor_bitmap, minor, 1);
|
||||
MUTEX_RELEASE(&minor_bitmap_mutex);
|
||||
}
|
||||
|
||||
static int input_dev_open(int minor, vnode_t **vnode, int flags) {
|
||||
input_device_t *dev = get(minor);
|
||||
if (dev == NULL)
|
||||
return ENODEV;
|
||||
|
||||
int res;
|
||||
int listener_minor = listener_minor_allocate();
|
||||
if (listener_minor == -1)
|
||||
return ENOSPC;
|
||||
|
||||
char tmp_name[20];
|
||||
snprintf(tmp_name, 20, "input/.listener%d", listener_minor);
|
||||
|
||||
// TODO implement a way to atomically do this
|
||||
res = devfs_register(&input_listener_ops, tmp_name, V_TYPE_CHDEV, DEV_MAJOR_INPUT, listener_minor + MAX_DEVICES, 0, NULL);
|
||||
if (res != 0) {
|
||||
listener_minor_free(listener_minor);
|
||||
return res;
|
||||
}
|
||||
|
||||
vnode_t *listener_vnode;
|
||||
__assert(devfs_getbyname(tmp_name, &listener_vnode) == 0);
|
||||
devfs_remove(tmp_name, DEV_MAJOR_INPUT, listener_minor + MAX_DEVICES);
|
||||
|
||||
input_listener_t *listener = alloc(sizeof(input_listener_t));
|
||||
if (listener == NULL) {
|
||||
VOP_RELEASE(listener_vnode);
|
||||
listener_minor_free(listener_minor);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
res = ringbuffer_init(&listener->buffer, INPUT_DEV_BUFFER_SIZE);
|
||||
if (res != 0) {
|
||||
VOP_RELEASE(listener_vnode);
|
||||
free(listener);
|
||||
listener_minor_free(listener_minor);
|
||||
return res;
|
||||
}
|
||||
|
||||
MUTEX_ACQUIRE(&input_dev_table_lock);
|
||||
res = hashtable_set(&input_listener_table, listener, &listener_minor, sizeof(listener_minor), true);
|
||||
MUTEX_RELEASE(&input_dev_table_lock);
|
||||
|
||||
if (res != 0) {
|
||||
ringbuffer_destroy(&listener->buffer);
|
||||
VOP_RELEASE(listener_vnode);
|
||||
free(listener);
|
||||
listener_minor_free(listener_minor);
|
||||
return res;
|
||||
}
|
||||
|
||||
listener->device = dev;
|
||||
listener->vnode = listener_vnode;
|
||||
|
||||
SPINLOCK_INIT(listener->lock);
|
||||
MUTEX_INIT(&listener->mutex);
|
||||
POLL_INITHEADER(&listener->poll_header);
|
||||
|
||||
long ipl = spinlock_acquire_raise_ipl(&dev->lock, IPL_INPUT);
|
||||
list_push_back(&dev->listeners, &listener->node);
|
||||
spinlock_release_lower_ipl(&dev->lock, ipl);
|
||||
|
||||
VOP_RELEASE(*vnode);
|
||||
*vnode = listener_vnode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static devops_t input_dev_ops = {
|
||||
.open = input_dev_open
|
||||
};
|
||||
|
||||
static int input_listener_close(int minor, int flags) {
|
||||
input_listener_t *lis = get(minor);
|
||||
if (lis == NULL)
|
||||
return ENODEV;
|
||||
|
||||
int listener_minor = minor - MAX_DEVICES;
|
||||
|
||||
MUTEX_ACQUIRE(&input_dev_table_lock);
|
||||
hashtable_remove(&input_listener_table, &listener_minor, sizeof(listener_minor));
|
||||
MUTEX_RELEASE(&input_dev_table_lock);
|
||||
|
||||
long ipl = spinlock_acquire_raise_ipl(&lis->device->lock, IPL_INPUT);
|
||||
list_remove(&lis->device->listeners, &lis->node);
|
||||
spinlock_release_lower_ipl(&lis->device->lock, ipl);
|
||||
|
||||
ringbuffer_destroy(&lis->buffer);
|
||||
free(lis);
|
||||
|
||||
listener_minor_free(listener_minor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int input_listener_internal_poll(input_listener_t *lis, polldata_t *data, int events) {
|
||||
int revents = 0;
|
||||
|
||||
if ((events & POLLIN) && RINGBUFFER_DATACOUNT(&lis->buffer) > 0)
|
||||
revents |= POLLIN;
|
||||
|
||||
if (revents == 0 && data)
|
||||
poll_add(&lis->poll_header, data, events);
|
||||
|
||||
return revents;
|
||||
}
|
||||
|
||||
static int input_listener_read(int minor, iovec_iterator_t *iovec_iterator, size_t size, uintmax_t offset, int flags, size_t *readc) {
|
||||
input_listener_t *lis = get(minor);
|
||||
if (lis == NULL)
|
||||
return ENODEV;
|
||||
|
||||
if (size % sizeof(input_event_t) != 0)
|
||||
return EINVAL;
|
||||
|
||||
int err = 0;
|
||||
for (;;) {
|
||||
polldesc_t desc = {0};
|
||||
err = poll_initdesc(&desc, 1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
MUTEX_ACQUIRE(&lis->mutex);
|
||||
long ipl = spinlock_acquire_raise_ipl(&lis->lock, IPL_INPUT);
|
||||
int revents = input_listener_internal_poll(lis, &desc.data[0], POLLIN);
|
||||
spinlock_release_lower_ipl(&lis->lock, ipl);
|
||||
|
||||
if (revents != 0) {
|
||||
*readc = iovec_iterator_read_from_ringbuffer(iovec_iterator, &lis->buffer, size);
|
||||
if (*readc == RINGBUFFER_USER_COPY_FAILED)
|
||||
err = EFAULT;
|
||||
|
||||
MUTEX_RELEASE(&lis->mutex);
|
||||
|
||||
poll_leave(&desc);
|
||||
poll_destroydesc(&desc);
|
||||
break;
|
||||
}
|
||||
|
||||
MUTEX_RELEASE(&lis->mutex);
|
||||
|
||||
if (flags & V_FFLAGS_NONBLOCKING) {
|
||||
poll_leave(&desc);
|
||||
poll_destroydesc(&desc);
|
||||
return EAGAIN;
|
||||
}
|
||||
|
||||
err = poll_dowait(&desc, 0);
|
||||
|
||||
poll_leave(&desc);
|
||||
poll_destroydesc(&desc);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int input_listener_poll(int minor, polldata_t *data, int events) {
|
||||
input_listener_t *lis = get(minor);
|
||||
if (lis == NULL)
|
||||
return POLLERR;
|
||||
|
||||
long ipl = spinlock_acquire_raise_ipl(&lis->lock, IPL_INPUT);
|
||||
|
||||
int revents = input_listener_internal_poll(lis, data, events);
|
||||
|
||||
spinlock_release_lower_ipl(&lis->lock, ipl);
|
||||
|
||||
return revents;
|
||||
}
|
||||
|
||||
static int copy_bitmap_to_user(bitmap_t *bitmap, void *arg, size_t size) {
|
||||
int err = 0;
|
||||
|
||||
long nlong = 0;
|
||||
if (bitmap != NULL) {
|
||||
nlong = ROUND_UP(bitmap->size, sizeof(long) * 8) / (sizeof(long) * 8);
|
||||
err = USERCOPY_POSSIBLY_TO_USER(arg, bitmap->data, min(size, nlong * sizeof(long)));
|
||||
if (err != 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (nlong * sizeof(long) < size)
|
||||
err = USERCOPY_POSSIBLY_MEMSET_TO_USER((void *)arg + nlong * sizeof(long), 0, size - nlong * sizeof(long));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#define EVIOCGVERSION 0x1
|
||||
#define EVIOCGID 0x2
|
||||
#define EVIOCGNAME 0x6
|
||||
#define EVIOCGPHYS 0x7
|
||||
#define EVIOCGUNIQ 0x8
|
||||
#define EVIOCGPROP 0x9
|
||||
#define EVIOCGKEY 0x18
|
||||
#define EVIOCGLED 0x19
|
||||
#define EVIOCGSND 0x1a
|
||||
#define EVIOCGSW 0x1b
|
||||
#define EVIOCGBIT 0x20
|
||||
#define EVIOCGABS 0x40
|
||||
#define EVIOVSABS 0xc0
|
||||
|
||||
#define ID_BUS 0
|
||||
#define ID_VENDOR 1
|
||||
#define ID_PRODUCT 2
|
||||
#define ID_VERSION 3
|
||||
|
||||
|
||||
static int input_listener_ioctl(int minor, unsigned long request, void *arg, int *result, cred_t *cred) {
|
||||
input_listener_t *lis = get(minor);
|
||||
if (lis == NULL)
|
||||
return ENODEV;
|
||||
|
||||
int number = request & 0xff;
|
||||
int type = (request >> 8) & 0xff;
|
||||
int size = (request >> 16) & 0x3fff;
|
||||
|
||||
if (type != 'E')
|
||||
return ENOTTY;
|
||||
|
||||
if (number == EVIOCGVERSION) {
|
||||
uint32_t version = 0;
|
||||
version |= lis->device->ver_major << 16;
|
||||
version |= lis->device->ver_minor << 8;
|
||||
version |= lis->device->ver_patch << 0;
|
||||
|
||||
return USERCOPY_POSSIBLY_TO_USER(arg, &version, sizeof(version));
|
||||
} else if (number == EVIOCGID) {
|
||||
uint16_t id[4];
|
||||
id[ID_BUS] = lis->device->id_bus;
|
||||
id[ID_VENDOR] = lis->device->id_vendor;
|
||||
id[ID_PRODUCT] = lis->device->id_product;
|
||||
id[ID_VERSION] = lis->device->id_version;
|
||||
|
||||
return USERCOPY_POSSIBLY_TO_USER(arg, &id, sizeof(id));
|
||||
} else if (number == EVIOCGNAME) {
|
||||
return USERCOPY_POSSIBLY_TO_USER(arg, &lis->device->name, min(size, sizeof(lis->device->name)));
|
||||
} else if (number == EVIOCGPHYS) {
|
||||
return USERCOPY_POSSIBLY_TO_USER(arg, &lis->device->phys, min(size, sizeof(lis->device->phys)));
|
||||
} else if (number == EVIOCGUNIQ) {
|
||||
return USERCOPY_POSSIBLY_TO_USER(arg, &lis->device->uniq, min(size, sizeof(lis->device->uniq)));
|
||||
} else if (number == EVIOCGPROP) {
|
||||
return copy_bitmap_to_user(&lis->device->prop_bits, arg, size);
|
||||
} else if (number == EVIOCGKEY || number == EVIOCGLED || number == EVIOCGSND || number == EVIOCGSW) {
|
||||
// TODO: maintain current device state so SYN_DROPPED recovery can
|
||||
// report pressed keys/buttons and active LEDs/sounds/switches.
|
||||
return copy_bitmap_to_user(NULL, arg, size);
|
||||
} else if (number == EVIOCGBIT) {
|
||||
return copy_bitmap_to_user(&lis->device->ev_bits, arg, size);
|
||||
} else if (number > EVIOCGBIT && number < EVIOCGBIT + INPUT_EV_CNT) {
|
||||
bitmap_t *bitmap = NULL;
|
||||
if (bitmap_get(&lis->device->ev_bits, number - EVIOCGBIT)) {
|
||||
switch (number - EVIOCGBIT) {
|
||||
case INPUT_EV_KEY:
|
||||
bitmap = &lis->device->key_bits;
|
||||
break;
|
||||
case INPUT_EV_REL:
|
||||
bitmap = &lis->device->rel_bits;
|
||||
break;
|
||||
case INPUT_EV_ABS:
|
||||
bitmap = &lis->device->abs_bits;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return copy_bitmap_to_user(bitmap, arg, size);
|
||||
} else if (number >= EVIOCGABS && number < EVIOCGABS + INPUT_ABS_CNT) {
|
||||
if (!bitmap_get(&lis->device->ev_bits, INPUT_EV_ABS))
|
||||
return EINVAL;
|
||||
|
||||
int abs_code = number - EVIOCGABS;
|
||||
if (!bitmap_get(&lis->device->abs_bits, abs_code))
|
||||
return EINVAL;
|
||||
|
||||
input_absinfo_t absinfo;
|
||||
absinfo.value = -1;
|
||||
absinfo.min = -1;
|
||||
absinfo.max = -1;
|
||||
absinfo.fuzz = 0;
|
||||
absinfo.flat = 0;
|
||||
absinfo.res = 0;
|
||||
return USERCOPY_POSSIBLY_TO_USER(arg, &absinfo, sizeof(input_absinfo_t));
|
||||
} else {
|
||||
printf("input_ioctl: unhandled ioctl %lu (%u, %u, %u)\n", request, number, type, size);
|
||||
return ENOTTY;
|
||||
}
|
||||
}
|
||||
|
||||
static devops_t input_listener_ops = {
|
||||
.close = input_listener_close,
|
||||
.read = input_listener_read,
|
||||
.poll = input_listener_poll,
|
||||
.ioctl = input_listener_ioctl,
|
||||
};
|
||||
|
||||
input_device_t *input_new() {
|
||||
// TODO proper allocator for hotplug support
|
||||
int minor = __atomic_fetch_add(&input_dev_count, 1, __ATOMIC_RELAXED);
|
||||
if (minor >= MAX_DEVICES)
|
||||
return NULL;
|
||||
|
||||
char name_buffer[32];
|
||||
snprintf(name_buffer, sizeof(name_buffer), "input/event%d", minor);
|
||||
|
||||
input_device_t *dev = alloc(sizeof(input_device_t));
|
||||
if (dev == NULL)
|
||||
return NULL;
|
||||
|
||||
list_init(&dev->listeners);
|
||||
|
||||
int res;
|
||||
res = bitmap_init(&dev->prop_bits, INPUT_PROP_CNT);
|
||||
if (res != 0)
|
||||
goto cleanup;
|
||||
|
||||
res = bitmap_init(&dev->ev_bits, INPUT_EV_CNT);
|
||||
if (res != 0)
|
||||
goto cleanup;
|
||||
|
||||
res = bitmap_init(&dev->syn_bits, INPUT_SYN_CNT);
|
||||
if (res != 0)
|
||||
goto cleanup;
|
||||
|
||||
res = bitmap_init(&dev->key_bits, INPUT_KEY_CNT);
|
||||
if (res != 0)
|
||||
goto cleanup;
|
||||
|
||||
res = bitmap_init(&dev->rel_bits, INPUT_REL_CNT);
|
||||
if (res != 0)
|
||||
goto cleanup;
|
||||
|
||||
res = bitmap_init(&dev->abs_bits, INPUT_ABS_CNT);
|
||||
if (res != 0)
|
||||
goto cleanup;
|
||||
|
||||
MUTEX_ACQUIRE(&input_dev_table_lock);
|
||||
res = hashtable_set(&input_dev_table, dev, &minor, sizeof(minor), true);
|
||||
MUTEX_RELEASE(&input_dev_table_lock);
|
||||
if (res != 0)
|
||||
goto cleanup;
|
||||
|
||||
// TODO proper handling here for hotplug support
|
||||
res = devfs_register(&input_dev_ops, name_buffer, V_TYPE_CHDEV, DEV_MAJOR_INPUT, minor, 0666, NULL);
|
||||
__assert(res == 0);
|
||||
|
||||
bitmap_set(&dev->ev_bits, INPUT_EV_SYN, 1);
|
||||
bitmap_set(&dev->syn_bits, INPUT_SYN_REPORT, 1);
|
||||
bitmap_set(&dev->syn_bits, INPUT_SYN_DROPPED, 1);
|
||||
|
||||
return dev;
|
||||
|
||||
cleanup:
|
||||
if (dev->ev_bits.data != NULL)
|
||||
bitmap_destroy(&dev->ev_bits);
|
||||
if (dev->syn_bits.data != NULL)
|
||||
bitmap_destroy(&dev->syn_bits);
|
||||
if (dev->key_bits.data != NULL)
|
||||
bitmap_destroy(&dev->key_bits);
|
||||
if (dev->rel_bits.data != NULL)
|
||||
bitmap_destroy(&dev->rel_bits);
|
||||
if (dev->abs_bits.data != NULL)
|
||||
bitmap_destroy(&dev->abs_bits);
|
||||
|
||||
free(dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void input_queue_internal(input_listener_t *lis, input_event_t *event, bool signal) {
|
||||
timespec_t ts;
|
||||
if (lis->device->clock_id == CLOCK_REALTIME || lis->device->clock_id == CLOCK_MONOTONIC) {
|
||||
ts = timekeeper_time();
|
||||
} else if (lis->device->clock_id == CLOCK_BOOTTIME) {
|
||||
ts = timekeeper_timefromboot();
|
||||
} else {
|
||||
ts.s = 0;
|
||||
ts.ns = 0;
|
||||
}
|
||||
|
||||
event->time = timespec_to_timeval(ts);
|
||||
|
||||
size_t written = ringbuffer_write(&lis->buffer, event, sizeof(input_event_t));
|
||||
if (written == sizeof(input_event_t) && signal)
|
||||
poll_event(&lis->poll_header, POLLIN);
|
||||
}
|
||||
|
||||
static void input_queue_packet_internal(input_listener_t *lis, input_event_t *events, int count) {
|
||||
size_t needed_space = (count + 1) * sizeof(input_event_t);
|
||||
spinlock_acquire(&lis->lock);
|
||||
if (RINGBUFFER_FREESPACE(&lis->buffer) < needed_space) {
|
||||
// Not enough space, write a SYN_DROPPED event.
|
||||
input_event_t event;
|
||||
event.type = INPUT_EV_SYN;
|
||||
event.code = INPUT_SYN_DROPPED;
|
||||
event.value = 0;
|
||||
input_queue_internal(lis, &event, true);
|
||||
} else {
|
||||
// Queue all the events.
|
||||
for (int i = 0; i < count; ++i) {
|
||||
input_queue_internal(lis, &events[i], false);
|
||||
}
|
||||
|
||||
input_event_t event;
|
||||
event.type = INPUT_EV_SYN;
|
||||
event.code = INPUT_SYN_REPORT;
|
||||
event.value = 0;
|
||||
input_queue_internal(lis, &event, true);
|
||||
}
|
||||
spinlock_release(&lis->lock);
|
||||
}
|
||||
|
||||
void input_queue_packet(input_device_t *dev, input_event_t *events, int count) {
|
||||
if (count < 1)
|
||||
return;
|
||||
|
||||
console_process_events(events, count);
|
||||
|
||||
long ipl = spinlock_acquire_raise_ipl(&dev->lock, IPL_INPUT);
|
||||
|
||||
list_for_each(&dev->listeners, node) {
|
||||
input_listener_t *lis = container_of(node, input_listener_t, node);
|
||||
input_queue_packet_internal(lis, events, count);
|
||||
}
|
||||
|
||||
spinlock_release_lower_ipl(&dev->lock, ipl);
|
||||
}
|
||||
|
||||
static void input_init(void) {
|
||||
bitmap_set_range(&listener_minor_bitmap, 0, MAX_DEVICES, 1);
|
||||
__assert(devfs_createdir("input") == 0);
|
||||
|
||||
// TODO define this statically
|
||||
__assert(hashtable_init(&input_dev_table, 32) == 0);
|
||||
__assert(hashtable_init(&input_listener_table, 128) == 0);
|
||||
}
|
||||
|
||||
INIT_ROUTINE_DEFINE(input, INIT_ROUTINE_FLAGS_NONE, input_init, devfs, console);
|
||||
Reference in New Issue
Block a user