PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
kbd.c
Go to the documentation of this file.
2
3#include <kernel/fs/devfs.h>
4#include <kernel/fs/file.h>
5#include <kernel/fs/path.h>
6#include <kernel/fs/vfs.h>
7#include <kernel/log/log.h>
10#include <kernel/sched/wait.h>
11#include <kernel/sync/lock.h>
12
13#include <errno.h>
14#include <kernel/utils/fifo.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <sys/fs.h>
18#include <sys/math.h>
19#include <sys/proc.h>
20
21static dentry_t* dir = NULL;
22
23static atomic_uint64_t newId = ATOMIC_VAR_INIT(0);
24
25static size_t kbd_name_read(file_t* file, void* buffer, size_t count, size_t* offset)
26{
27 kbd_t* kbd = file->vnode->data;
28 assert(kbd != NULL);
29
30 size_t length = strlen(kbd->name);
31 return BUFFER_READ(buffer, count, offset, kbd->name, length);
32}
33
36};
37
39{
40 kbd_t* kbd = file->vnode->data;
41 assert(kbd != NULL);
42
43 kbd_client_t* client = calloc(1, sizeof(kbd_client_t));
44 if (client == NULL)
45 {
46 errno = ENOMEM;
47 return ERR;
48 }
49 list_entry_init(&client->entry);
50 fifo_init(&client->fifo, client->buffer, sizeof(client->buffer));
51
52 lock_acquire(&kbd->lock);
53 list_push_back(&kbd->clients, &client->entry);
54 lock_release(&kbd->lock);
55
56 file->data = client;
57 return 0;
58}
59
60static void kbd_events_close(file_t* file)
61{
62 kbd_t* kbd = file->vnode->data;
63 assert(kbd != NULL);
64
65 kbd_client_t* client = file->data;
66 if (client == NULL)
67 {
68 return;
69 }
70
71 lock_acquire(&kbd->lock);
72 list_remove(&client->entry);
73 lock_release(&kbd->lock);
74
75 free(client);
76}
77
78static size_t kbd_events_read(file_t* file, void* buffer, size_t count, size_t* offset)
79{
81
82 if (count == 0)
83 {
84 return 0;
85 }
86
87 kbd_t* kbd = file->vnode->data;
88 assert(kbd != NULL);
89 kbd_client_t* client = file->data;
90 assert(client != NULL);
91
92 LOCK_SCOPE(&kbd->lock);
93
94 if (fifo_bytes_readable(&client->fifo) == 0)
95 {
96 if (file->mode & MODE_NONBLOCK)
97 {
98 errno = EAGAIN;
99 return ERR;
100 }
101
102 if (WAIT_BLOCK_LOCK(&kbd->waitQueue, &kbd->lock, fifo_bytes_readable(&client->fifo) != 0) == ERR)
103 {
104 return ERR;
105 }
106 }
107
108 return fifo_read(&client->fifo, buffer, count);
109}
110
112{
113 kbd_t* kbd = file->vnode->data;
114 assert(kbd != NULL);
115 kbd_client_t* client = file->data;
116 assert(client != NULL);
117
118 LOCK_SCOPE(&kbd->lock);
119
120 if (fifo_bytes_readable(&client->fifo) != 0)
121 {
122 *revents |= POLLIN;
123 }
124 return &kbd->waitQueue;
125}
126
129 .close = kbd_events_close,
130 .read = kbd_events_read,
131 .poll = kbd_events_poll,
132};
133
134static void kbd_dir_cleanup(vnode_t* vnode)
135{
136 kbd_t* kbd = vnode->data;
137 if (kbd == NULL)
138 {
139 return;
140 }
141
142 wait_queue_deinit(&kbd->waitQueue);
143 free(kbd);
144}
145
149
150kbd_t* kbd_new(const char* name)
151{
152 if (name == NULL)
153 {
154 errno = EINVAL;
155 return NULL;
156 }
157
158 if (dir == NULL)
159 {
160 dir = devfs_dir_new(NULL, "kbd", NULL, NULL);
161 if (dir == NULL)
162 {
163 return NULL;
164 }
165 }
166
167 kbd_t* kbd = malloc(sizeof(kbd_t));
168 if (kbd == NULL)
169 {
170 errno = ENOMEM;
171 return NULL;
172 }
173 strncpy(kbd->name, name, sizeof(kbd->name));
174 kbd->name[sizeof(kbd->name) - 1] = '\0';
175 wait_queue_init(&kbd->waitQueue);
176 list_init(&kbd->clients);
177 lock_init(&kbd->lock);
178 kbd->dir = NULL;
179 list_init(&kbd->files);
180
181 char id[MAX_NAME];
182 if (snprintf(id, MAX_NAME, "%llu", atomic_fetch_add(&newId, 1)) < 0)
183 {
184 wait_queue_deinit(&kbd->waitQueue);
185 free(kbd);
186 errno = EIO;
187 return NULL;
188 }
189
190 kbd->dir = devfs_dir_new(dir, id, &dirVnodeOps, kbd);
191 if (kbd->dir == NULL)
192 {
193 wait_queue_deinit(&kbd->waitQueue);
194 free(kbd);
195 return NULL;
196 }
197
199 {
200 .name = "name",
201 .fileOps = &nameOps,
202 .data = kbd,
203 },
204 {
205 .name = "events",
206 .fileOps = &eventsOps,
207 .data = kbd,
208 },
209 {
210 .name = NULL,
211 },
212 };
213
214 if (devfs_files_new(&kbd->files, kbd->dir, files) == ERR)
215 {
216 wait_queue_deinit(&kbd->waitQueue);
217 UNREF(kbd->dir);
218 free(kbd);
219 return NULL;
220 }
221
222 return kbd;
223}
224
226{
227 if (kbd == NULL)
228 {
229 return;
230 }
231
232 UNREF(kbd->dir);
233 devfs_files_free(&kbd->files);
234}
235
236static void kbd_broadcast(kbd_t* kbd, const char* string, size_t length)
237{
238 LOCK_SCOPE(&kbd->lock);
239
240 kbd_client_t* client;
241 LIST_FOR_EACH(client, &kbd->clients, entry)
242 {
243 if (fifo_bytes_writeable(&client->fifo) >= length)
244 {
245 fifo_write(&client->fifo, string, length);
246 }
247 }
248
249 wait_unblock(&kbd->waitQueue, WAIT_ALL, EOK);
250}
251
253{
254 if (kbd == NULL)
255 {
256 return;
257 }
258
259 char event[MAX_NAME];
260 int length = snprintf(event, sizeof(event), "%u_", code);
261 if (length < 0)
262 {
263 LOG_ERR("failed to format keyboard press event\n");
264 return;
265 }
266
267 kbd_broadcast(kbd, event, (size_t)length);
268}
269
271{
272 if (kbd == NULL)
273 {
274 return;
275 }
276
277 char event[MAX_NAME];
278 int length = snprintf(event, sizeof(event), "%u^", code);
279 if (length < 0)
280 {
281 LOG_ERR("failed to format keyboard release event\n");
282 return;
283 }
284
285 kbd_broadcast(kbd, event, (size_t)length);
286}
#define MAX_NAME
Maximum length of names.
Definition MAX_NAME.h:11
#define assert(expression)
Definition assert.h:29
EFI_PHYSICAL_ADDRESS buffer
Definition main.c:237
static fd_t kbd
Definition dwm.c:23
void kbd_release(kbd_t *kbd, keycode_t code)
Push a keyboard release event to the keyboard event queue.
Definition kbd.c:270
void kbd_press(kbd_t *kbd, keycode_t code)
Push a keyboard press event to the keyboard event queue.
Definition kbd.c:252
void kbd_free(kbd_t *kbd)
Frees a keyboard.
Definition kbd.c:225
kbd_t * kbd_new(const char *name)
Allocate and initialize a new keyboard.
Definition kbd.c:150
uint64_t devfs_files_new(list_t *out, dentry_t *parent, const devfs_file_desc_t *descs)
Create multiple files in a devfs directory.
Definition devfs.c:195
void devfs_files_free(list_t *files)
Free all files in a list created by devfs_files_new().
Definition devfs.c:250
dentry_t * devfs_dir_new(dentry_t *parent, const char *name, const vnode_ops_t *vnodeOps, void *data)
Create a new directory inside a mounted devfs instance.
Definition devfs.c:82
@ MODE_NONBLOCK
Definition path.h:84
#define LOG_ERR(format,...)
Definition log.h:93
uint64_t wait_unblock(wait_queue_t *queue, uint64_t amount, errno_t err)
Unblock threads waiting on a wait queue.
Definition wait.c:307
void wait_queue_deinit(wait_queue_t *queue)
Deinitialize wait queue.
Definition wait.c:57
#define WAIT_ALL
Used to indicate that the wait should unblock all waiting threads.
Definition wait.h:43
void wait_queue_init(wait_queue_t *queue)
Initialize wait queue.
Definition wait.c:51
#define WAIT_BLOCK_LOCK(queue, lock, condition)
Blocks until the condition is true, condition will be tested on every wakeup. Will release the lock b...
Definition wait.h:109
static void lock_init(lock_t *lock)
Initializes a lock.
Definition lock.h:79
#define LOCK_SCOPE(lock)
Acquires a lock for the reminder of the current scope.
Definition lock.h:58
static void lock_release(lock_t *lock)
Releases a lock.
Definition lock.h:175
static void lock_acquire(lock_t *lock)
Acquires a lock, blocking until it is available.
Definition lock.h:96
static size_t fifo_read(fifo_t *fifo, void *buffer, size_t count)
Read data from a fifo buffer at a specific offset.
Definition fifo.h:113
static size_t fifo_bytes_writeable(const fifo_t *fifo)
Return the number of bytes available for writing in a fifo buffer.
Definition fifo.h:95
static void fifo_init(fifo_t *fifo, uint8_t *buffer, size_t size)
Initialize a fifo buffer.
Definition fifo.h:54
static size_t fifo_write(fifo_t *fifo, const void *buffer, size_t count)
Write data to the fifo buffer.
Definition fifo.h:155
static size_t fifo_bytes_readable(const fifo_t *fifo)
Return the number of bytes available for reading in a fifo buffer.
Definition fifo.h:79
#define UNREF(ptr)
Decrement reference count.
Definition ref.h:109
#define BUFFER_READ(buffer, count, offset, src, size)
Helper macros for implementing file operations dealing with simple buffers.
Definition vfs.h:209
#define EINVAL
Invalid argument.
Definition errno.h:142
#define ENOMEM
Out of memory.
Definition errno.h:92
#define EIO
I/O error.
Definition errno.h:57
#define errno
Error number variable.
Definition errno.h:27
#define EOK
No error.
Definition errno.h:32
#define EAGAIN
Try again.
Definition errno.h:87
#define UNUSED(x)
Mark a variable as unused.
Definition defs.h:96
poll_events_t
Poll events type.
Definition fs.h:286
@ POLLIN
File descriptor is ready to read.
Definition fs.h:288
keycode_t
Keyboard keycode type.
Definition kbd.h:29
#define LIST_FOR_EACH(elem, list, member)
Iterates over a list.
Definition list.h:58
static void list_remove(list_entry_t *entry)
Removes a list entry from its current list.
Definition list.h:290
static void list_push_back(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:322
static void list_entry_init(list_entry_t *entry)
Initializes a list entry.
Definition list.h:173
static void list_init(list_t *list)
Initializes a list.
Definition list.h:185
#define NULL
Pointer error value.
Definition NULL.h:25
#define ERR
Integer error value.
Definition ERR.h:17
static dentry_t * dir
Definition kbd.c:21
static atomic_uint64_t newId
Definition kbd.c:23
static size_t kbd_events_read(file_t *file, void *buffer, size_t count, size_t *offset)
Definition kbd.c:78
static size_t kbd_name_read(file_t *file, void *buffer, size_t count, size_t *offset)
Definition kbd.c:25
static void kbd_events_close(file_t *file)
Definition kbd.c:60
static void kbd_dir_cleanup(vnode_t *vnode)
Definition kbd.c:134
static wait_queue_t * kbd_events_poll(file_t *file, poll_events_t *revents)
Definition kbd.c:111
static file_ops_t nameOps
Definition kbd.c:34
static file_ops_t eventsOps
Definition kbd.c:127
static vnode_ops_t dirVnodeOps
Definition kbd.c:146
static uint64_t kbd_events_open(file_t *file)
Definition kbd.c:38
static void kbd_broadcast(kbd_t *kbd, const char *string, size_t length)
Definition kbd.c:236
static uint64_t offset
Definition screen.c:19
static list_t files
Definition file.c:9
static atomic_long count
Definition main.c:11
#define ATOMIC_VAR_INIT(value)
Definition stdatomic.h:74
#define atomic_fetch_add(object, operand)
Definition stdatomic.h:283
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
_PUBLIC int snprintf(char *_RESTRICT s, size_t n, const char *_RESTRICT format,...)
Definition snprintf.c:3
_PUBLIC void * calloc(size_t nmemb, size_t size)
Definition calloc.c:6
_PUBLIC void * malloc(size_t size)
Definition malloc.c:5
_PUBLIC void free(void *ptr)
Definition free.c:11
_PUBLIC char * strncpy(char *_RESTRICT s1, const char *_RESTRICT s2, size_t n)
Definition strncpy.c:3
_PUBLIC size_t strlen(const char *s)
Definition strlen.c:3
Directory entry structure.
Definition dentry.h:155
Descriptor for batch file creation.
Definition devfs.h:73
File operations structure.
Definition file.h:54
size_t(* read)(file_t *file, void *buffer, size_t count, size_t *offset)
Definition file.h:58
uint64_t(* open)(file_t *file)
Definition file.h:55
File structure.
Definition file.h:39
void * data
Definition file.h:46
mode_t mode
Definition file.h:42
vnode_t * vnode
Definition file.h:43
Keyboard event client structure.
Definition kbd.h:57
list_entry_t entry
Definition kbd.h:58
fifo_t fifo
Definition kbd.h:59
uint8_t buffer[KBD_CLIENT_BUFFER_SIZE]
Definition kbd.h:60
Keyboard structure.
Definition kbd.h:68
vnode operations structure.
Definition vnode.h:69
void(* cleanup)(vnode_t *vnode)
Cleanup function called when the vnode is being freed.
Definition vnode.h:138
vnode structure.
Definition vnode.h:48
void * data
Filesystem defined data.
Definition vnode.h:52
The primitive that threads block on.
Definition wait.h:185