PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
mouse.c
Go to the documentation of this file.
2#include <kernel/fs/devfs.h>
3#include <kernel/fs/file.h>
4#include <kernel/fs/vfs.h>
5#include <kernel/log/log.h>
8#include <kernel/sync/lock.h>
9
10#include <errno.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <sys/math.h>
14
15static dentry_t* dir = NULL;
16
17static atomic_uint64_t newId = ATOMIC_VAR_INIT(0);
18
19static size_t mouse_name_read(file_t* file, void* buffer, size_t count, size_t* offset)
20{
21 mouse_t* mouse = file->vnode->data;
22 assert(mouse != NULL);
23
24 size_t length = strlen(mouse->name);
25 return BUFFER_READ(buffer, count, offset, mouse->name, length);
26}
27
30};
31
33{
34 mouse_t* mouse = file->vnode->data;
35 assert(mouse != NULL);
36
37 mouse_client_t* client = calloc(1, sizeof(mouse_client_t));
38 if (client == NULL)
39 {
40 errno = ENOMEM;
41 return ERR;
42 }
43 list_entry_init(&client->entry);
44 fifo_init(&client->fifo, client->buffer, sizeof(client->buffer));
45
46 lock_acquire(&mouse->lock);
47 list_push_back(&mouse->clients, &client->entry);
48 lock_release(&mouse->lock);
49
50 file->data = client;
51 return 0;
52}
53
54static void mouse_events_close(file_t* file)
55{
56 mouse_t* mouse = file->vnode->data;
57 assert(mouse != NULL);
58
59 mouse_client_t* client = file->data;
60 if (client == NULL)
61 {
62 return;
63 }
64
65 lock_acquire(&mouse->lock);
66 list_remove(&client->entry);
67 lock_release(&mouse->lock);
68
69 free(client);
70}
71
72static size_t mouse_events_read(file_t* file, void* buffer, size_t count, size_t* offset)
73{
75
76 if (count == 0)
77 {
78 return 0;
79 }
80
81 mouse_t* mouse = file->vnode->data;
82 assert(mouse != NULL);
83 mouse_client_t* client = file->data;
84 assert(client != NULL);
85
86 LOCK_SCOPE(&mouse->lock);
87
88 if (fifo_bytes_readable(&client->fifo) == 0)
89 {
90 if (file->mode & MODE_NONBLOCK)
91 {
92 errno = EAGAIN;
93 return ERR;
94 }
95
96 if (WAIT_BLOCK_LOCK(&mouse->waitQueue, &mouse->lock, fifo_bytes_readable(&client->fifo) != 0) == ERR)
97 {
98 return ERR;
99 }
100 }
101
102 return fifo_read(&client->fifo, buffer, count);
103}
104
106{
107 mouse_t* mouse = file->vnode->data;
108 assert(mouse != NULL);
109 mouse_client_t* client = file->data;
110 assert(client != NULL);
111
112 LOCK_SCOPE(&mouse->lock);
113
114 if (fifo_bytes_readable(&client->fifo) != 0)
115 {
116 *revents |= POLLIN;
117 }
118 return &mouse->waitQueue;
119}
120
123 .close = mouse_events_close,
124 .read = mouse_events_read,
125 .poll = mouse_events_poll,
126};
127
128static void mouse_dir_cleanup(vnode_t* vnode)
129{
130 mouse_t* mouse = vnode->data;
131 if (mouse == NULL)
132 {
133 return;
134 }
135
136 wait_queue_deinit(&mouse->waitQueue);
137 free(mouse);
138}
139
143
144mouse_t* mouse_new(const char* name)
145{
146 if (name == NULL)
147 {
148 errno = EINVAL;
149 return NULL;
150 }
151
152 if (dir == NULL)
153 {
154 dir = devfs_dir_new(NULL, "mouse", NULL, NULL);
155 if (dir == NULL)
156 {
157 return NULL;
158 }
159 }
160
161 mouse_t* mouse = malloc(sizeof(mouse_t));
162 if (mouse == NULL)
163 {
164 errno = ENOMEM;
165 return NULL;
166 }
167 strncpy(mouse->name, name, sizeof(mouse->name));
168 mouse->name[sizeof(mouse->name) - 1] = '\0';
169 wait_queue_init(&mouse->waitQueue);
170 list_init(&mouse->clients);
171 lock_init(&mouse->lock);
172 mouse->dir = NULL;
173 list_init(&mouse->files);
174
175 char id[MAX_NAME];
176 if (snprintf(id, MAX_NAME, "%llu", atomic_fetch_add(&newId, 1)) < 0)
177 {
178 wait_queue_deinit(&mouse->waitQueue);
179 free(mouse->name);
180 free(mouse);
181 return NULL;
182 }
183
184 mouse->dir = devfs_dir_new(dir, id, &dirVnodeOps, mouse);
185 if (mouse->dir == NULL)
186 {
187 wait_queue_deinit(&mouse->waitQueue);
188 free(mouse);
189 return NULL;
190 }
191
193 {
194 .name = "name",
195 .fileOps = &nameOps,
196 .data = mouse,
197 },
198 {
199 .name = "events",
200 .fileOps = &eventsOps,
201 .data = mouse,
202 },
203 {
204 .name = NULL,
205 },
206 };
207
208 if (devfs_files_new(&mouse->files, mouse->dir, files) == ERR)
209 {
210 wait_queue_deinit(&mouse->waitQueue);
211 UNREF(mouse->dir);
212 free(mouse);
213 return NULL;
214 }
215
216 return mouse;
217}
218
220{
221 if (mouse == NULL)
222 {
223 return;
224 }
225
226 UNREF(mouse->dir);
227 devfs_files_free(&mouse->files);
228}
229
230static void mouse_broadcast(mouse_t* mouse, const char* string, size_t length)
231{
232 LOCK_SCOPE(&mouse->lock);
233
234 mouse_client_t* client;
235 LIST_FOR_EACH(client, &mouse->clients, entry)
236 {
237 if (fifo_bytes_writeable(&client->fifo) >= length)
238 {
239 fifo_write(&client->fifo, string, length);
240 }
241 }
242
243 wait_unblock(&mouse->waitQueue, WAIT_ALL, EOK);
244}
245
247{
248 if (mouse == NULL)
249 {
250 return;
251 }
252
253 char event[MAX_NAME];
254 int length = snprintf(event, sizeof(event), "%u_", button);
255 if (length < 0)
256 {
257 LOG_ERR("failed to format mouse press event\n");
258 return;
259 }
260
261 mouse_broadcast(mouse, event, (size_t)length);
262}
263
265{
266 if (mouse == NULL)
267 {
268 return;
269 }
270
271 char event[MAX_NAME];
272 int length = snprintf(event, sizeof(event), "%u^", button);
273 if (length < 0)
274 {
275 LOG_ERR("failed to format mouse release event\n");
276 return;
277 }
278
279 mouse_broadcast(mouse, event, (size_t)length);
280}
281
283{
284 if (mouse == NULL)
285 {
286 return;
287 }
288
289 char event[MAX_NAME];
290 int length = snprintf(event, sizeof(event), "%lldx", delta);
291 if (length < 0)
292 {
293 LOG_ERR("failed to format mouse move X event\n");
294 return;
295 }
296
297 mouse_broadcast(mouse, event, (size_t)length);
298}
299
301{
302 if (mouse == NULL)
303 {
304 return;
305 }
306
307 char event[MAX_NAME];
308 int length = snprintf(event, sizeof(event), "%lldy", delta);
309 if (length < 0)
310 {
311 LOG_ERR("failed to format mouse move Y event\n");
312 return;
313 }
314
315 mouse_broadcast(mouse, event, (size_t)length);
316}
317
319{
320 if (mouse == NULL)
321 {
322 return;
323 }
324
325 char event[MAX_NAME];
326 int length = snprintf(event, sizeof(event), "%lldz", delta);
327 if (length < 0)
328 {
329 LOG_ERR("failed to format mouse scroll event\n");
330 return;
331 }
332
333 mouse_broadcast(mouse, event, (size_t)length);
334}
#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 mouse
Definition dwm.c:24
mouse_t * mouse_new(const char *name)
Allocate and initialize a mouse structure.
Definition mouse.c:144
void mouse_free(mouse_t *mouse)
Free and deinitialize a mouse structure.
Definition mouse.c:219
void mouse_press(mouse_t *mouse, uint32_t button)
Push a mouse button press event to the mouse event queue.
Definition mouse.c:246
void mouse_release(mouse_t *mouse, uint32_t button)
Push a mouse button release event to the mouse event queue.
Definition mouse.c:264
void mouse_scroll(mouse_t *mouse, int64_t delta)
Push a mouse scroll event to the mouse event queue.
Definition mouse.c:318
void mouse_move_x(mouse_t *mouse, int64_t delta)
Push a mouse movement in the X direction to the mouse event queue.
Definition mouse.c:282
void mouse_move_y(mouse_t *mouse, int64_t delta)
Push a mouse movement in the Y direction to the mouse event queue.
Definition mouse.c:300
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 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
#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 uint64_t offset
Definition screen.c:19
static list_t files
Definition file.c:9
static dentry_t * dir
Definition mouse.c:15
static atomic_uint64_t newId
Definition mouse.c:17
static size_t mouse_name_read(file_t *file, void *buffer, size_t count, size_t *offset)
Definition mouse.c:19
static void mouse_dir_cleanup(vnode_t *vnode)
Definition mouse.c:128
static uint64_t mouse_events_open(file_t *file)
Definition mouse.c:32
static void mouse_events_close(file_t *file)
Definition mouse.c:54
static file_ops_t nameOps
Definition mouse.c:28
static wait_queue_t * mouse_events_poll(file_t *file, poll_events_t *revents)
Definition mouse.c:105
static file_ops_t eventsOps
Definition mouse.c:121
static size_t mouse_events_read(file_t *file, void *buffer, size_t count, size_t *offset)
Definition mouse.c:72
static void mouse_broadcast(mouse_t *mouse, const char *string, size_t length)
Definition mouse.c:230
static vnode_ops_t dirVnodeOps
Definition mouse.c:140
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
__UINT32_TYPE__ uint32_t
Definition stdint.h:15
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__INT64_TYPE__ int64_t
Definition stdint.h:16
_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 mouse.h:60
fifo_t fifo
Definition mouse.h:62
uint8_t buffer[MOUSE_CLIENT_BUFFER_SIZE]
Definition mouse.h:63
list_entry_t entry
Definition mouse.h:61
Mouse structure.
Definition mouse.h:71
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