feat: better rtc framework which aims to remove single rtc restrictions.
[lunaix-os.git] / lunaix-os / kernel / device / input.c
1 #include <lunaix/clock.h>
2 #include <lunaix/input.h>
3 #include <lunaix/mm/page.h>
4 #include <lunaix/mm/valloc.h>
5 #include <lunaix/spike.h>
6 #include <lunaix/status.h>
7
8 #include <klibc/string.h>
9
10 static DEFINE_LLIST(listener_chain);
11
12 static struct device* input_devcat = NULL;
13
14 void
15 input_init()
16 {
17     input_devcat = device_addcat(NULL, "input");
18
19     int i;
20     ptr_t input_dev_init;
21     ldga_foreach(inputdev, ptr_t, i, input_dev_init)
22     {
23         ((void (*)())input_dev_init)();
24     }
25 }
26
27 void
28 input_fire_event(struct input_device* idev, struct input_evt_pkt* pkt)
29 {
30     pkt->timestamp = clock_systime();
31     idev->current_pkt = *pkt;
32
33     struct input_evt_chain *pos, *n;
34     llist_for_each(pos, n, &listener_chain, chain)
35     {
36         if (pos->evt_cb(idev) == INPUT_EVT_CATCH) {
37             break;
38         }
39     }
40
41     // wake up all pending readers
42     pwake_all(&idev->readers);
43 }
44
45 void
46 input_add_listener(input_evt_cb listener)
47 {
48     assert(listener);
49
50     struct input_evt_chain* chain = vzalloc(sizeof(*chain));
51     llist_append(&listener_chain, &chain->chain);
52
53     chain->evt_cb = listener;
54 }
55
56 int
57 __input_dev_read(struct device* dev, void* buf, size_t offset, size_t len)
58 {
59     struct input_device* idev = dev->underlay;
60
61     if (len < sizeof(struct input_evt_pkt)) {
62         return ERANGE;
63     }
64
65     // wait for new event
66     pwait(&idev->readers);
67
68     memcpy(buf, &idev->current_pkt, sizeof(struct input_evt_pkt));
69
70     return sizeof(struct input_evt_pkt);
71 }
72
73 int
74 __input_dev_read_pg(struct device* dev, void* buf, size_t offset)
75 {
76     return __input_dev_read(dev, buf, offset, PG_SIZE);
77 }
78
79 struct input_device*
80 input_add_device(char* name_fmt, ...)
81 {
82     assert(input_devcat);
83
84     struct input_device* idev = vzalloc(sizeof(*idev));
85     waitq_init(&idev->readers);
86
87     va_list args;
88     va_start(args, name_fmt);
89
90     struct device* dev =
91       device_add(input_devcat, idev, name_fmt, DEV_IFSEQ, args);
92
93     idev->dev_if = dev;
94     dev->ops.read = __input_dev_read;
95     dev->ops.read_page = __input_dev_read_pg;
96
97     va_end(args);
98
99     return idev;
100 }