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