tools/llvm: Do not build with symbols
[minix3.git] / minix / servers / input / input.c
blob089e779b959fce9e681b0294d350b9106f0f49a5
1 /* Keyboard/mouse input server. */
2 #include <minix/drivers.h>
3 #include <minix/chardriver.h>
4 #include <minix/ds.h>
5 #include <sys/ioctl.h>
6 #include <sys/kbdio.h>
8 #include "input.h"
10 #define INPUT_DEBUG 0
12 static int input_open(devminor_t, int, endpoint_t);
13 static int input_close(devminor_t);
14 static ssize_t input_read(devminor_t, u64_t, endpoint_t, cp_grant_id_t, size_t,
15 int, cdev_id_t);
16 static int input_ioctl(devminor_t, unsigned long, endpoint_t, cp_grant_id_t,
17 int, endpoint_t, cdev_id_t);
18 static int input_cancel(devminor_t, endpoint_t, cdev_id_t);
19 static int input_select(devminor_t, unsigned int, endpoint_t);
20 static void input_other(message *, int);
22 static struct input_dev devs[INPUT_DEV_MAX];
24 #define input_dev_active(dev) ((dev)->owner != NONE || \
25 (dev)->minor == KBDMUX_MINOR || \
26 (dev)->minor == MOUSEMUX_MINOR)
27 #define input_dev_buf_empty(dev) ((dev)->count == 0)
28 #define input_dev_buf_full(dev) ((dev)->count == EVENTBUF_SIZE)
30 /* Entry points to the input driver. */
31 static struct chardriver input_tab = {
32 .cdr_open = input_open,
33 .cdr_close = input_close,
34 .cdr_read = input_read,
35 .cdr_ioctl = input_ioctl,
36 .cdr_cancel = input_cancel,
37 .cdr_select = input_select,
38 .cdr_other = input_other
42 * Map a minor number to an input device structure.
44 static struct input_dev *
45 input_map(devminor_t minor)
48 * The minor device numbers were chosen not to be equal to the array
49 * slots, so that more keyboards can be added without breaking backward
50 * compatibility later.
52 if (minor == KBDMUX_MINOR)
53 return &devs[KBDMUX_DEV];
54 else if (minor >= KBD0_MINOR && minor < KBD0_MINOR + KBD_MINORS)
55 return &devs[FIRST_KBD_DEV + (minor - KBD0_MINOR)];
56 else if (minor == MOUSEMUX_MINOR)
57 return &devs[MOUSEMUX_DEV];
58 else if (minor >= MOUSE0_MINOR && minor < MOUSE0_MINOR + MOUSE_MINORS)
59 return &devs[FIRST_MOUSE_DEV + (minor - MOUSE0_MINOR)];
60 else
61 return NULL;
65 * Map an input device structure index to a minor number.
67 static devminor_t
68 input_revmap(int id)
70 if (id == KBDMUX_DEV)
71 return KBDMUX_MINOR;
72 else if (id >= FIRST_KBD_DEV && id <= LAST_KBD_DEV)
73 return KBD0_MINOR + (id - FIRST_KBD_DEV);
74 else if (id == MOUSEMUX_DEV)
75 return MOUSEMUX_MINOR;
76 else if (id >= FIRST_MOUSE_DEV && id <= LAST_MOUSE_DEV)
77 return MOUSE0_MINOR + (id - FIRST_MOUSE_DEV);
78 else
79 panic("reverse-mapping invalid ID %d", id);
83 * Open an input device.
85 static int
86 input_open(devminor_t minor, int UNUSED(access), endpoint_t UNUSED(user_endpt))
88 struct input_dev *input_dev;
90 if ((input_dev = input_map(minor)) == NULL)
91 return ENXIO;
93 if (!input_dev_active(input_dev))
94 return ENXIO;
96 if (input_dev->opened)
97 return EBUSY;
99 input_dev->opened = TRUE;
101 return OK;
105 * Close an input device.
107 static int
108 input_close(devminor_t minor)
110 struct input_dev *input_dev;
112 if ((input_dev = input_map(minor)) == NULL)
113 return ENXIO;
115 if (!input_dev->opened) {
116 printf("INPUT: closing already-closed device %d\n", minor);
117 return EINVAL;
120 input_dev->opened = FALSE;
121 input_dev->tail = 0;
122 input_dev->count = 0;
124 return OK;
128 * Copy input events to a reader.
130 static ssize_t
131 input_copy_events(endpoint_t endpt, cp_grant_id_t grant,
132 unsigned int event_count, struct input_dev *input_dev)
134 int r, nbytes, wrap_left;
135 size_t event_size = sizeof(*input_dev->eventbuf);
137 if (input_dev->count < event_count)
138 panic("input_copy_events: not enough input is ready");
140 wrap_left = input_dev->tail + event_count - EVENTBUF_SIZE;
141 nbytes = (wrap_left <= 0 ? event_count :
142 EVENTBUF_SIZE - input_dev->tail) * event_size;
144 if ((r = sys_safecopyto(endpt, grant, 0,
145 (vir_bytes)(input_dev->eventbuf + input_dev->tail), nbytes)) != OK)
146 return r;
148 /* Copy possible remaining part if we wrap over. */
149 if (wrap_left > 0 && (r = sys_safecopyto(endpt, grant, nbytes,
150 (vir_bytes) input_dev->eventbuf, wrap_left * event_size)) != OK)
151 return r;
153 input_dev->tail = (input_dev->tail + event_count) % EVENTBUF_SIZE;
154 input_dev->count -= event_count;
156 return event_size * event_count; /* bytes copied */
160 * Read from an input device.
162 static ssize_t
163 input_read(devminor_t minor, u64_t UNUSED(position), endpoint_t endpt,
164 cp_grant_id_t grant, size_t size, int flags, cdev_id_t id)
166 unsigned int event_count;
167 struct input_dev *input_dev;
169 if ((input_dev = input_map(minor)) == NULL)
170 return ENXIO;
172 /* We cannot accept more than one pending read request at once. */
173 if (!input_dev_active(input_dev) || input_dev->suspended)
174 return EIO;
176 /* The caller's buffer must have room for at least one whole event. */
177 event_count = size / sizeof(*input_dev->eventbuf);
178 if (event_count == 0)
179 return EIO;
181 /* No data available? Suspend the caller, unless we shouldn't block. */
182 if (input_dev_buf_empty(input_dev)) {
183 if (flags & CDEV_NONBLOCK)
184 return EAGAIN;
186 input_dev->suspended = TRUE;
187 input_dev->caller = endpt;
188 input_dev->grant = grant;
189 input_dev->req_id = id;
191 /* We should now wake up any selector, but that's lame.. */
192 return EDONTREPLY;
195 if (event_count > input_dev->count)
196 event_count = input_dev->count;
198 return input_copy_events(endpt, grant, event_count, input_dev);
202 * Set keyboard LEDs on one or all keyboards.
204 static void
205 input_set_leds(devminor_t minor, unsigned int mask)
207 struct input_dev *dev;
208 message m;
209 int i, r;
211 /* Prepare the request message */
212 memset(&m, 0, sizeof(m));
214 m.m_type = INPUT_SETLEDS;
215 m.m_input_linputdriver_setleds.led_mask = mask;
218 * Send the request to all matching keyboard devices. As side effect,
219 * this approach discards the request on mouse devices.
221 for (i = FIRST_KBD_DEV; i <= LAST_KBD_DEV; i++) {
222 dev = &devs[i];
224 if (minor != KBDMUX_MINOR && minor != dev->minor)
225 continue;
227 /* Save the new state; the driver might (re)start later. */
228 dev->leds = mask;
230 if (dev->owner != NONE) {
231 if ((r = asynsend3(dev->owner, &m, AMF_NOREPLY)) != OK)
232 printf("INPUT: asynsend to %u failed (%d)\n",
233 dev->owner, r);
239 * Process an IOCTL request.
241 static int
242 input_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt,
243 cp_grant_id_t grant, int flags, endpoint_t user_endpt, cdev_id_t id)
245 struct input_dev *input_dev;
246 kio_leds_t leds;
247 unsigned int mask;
248 int r;
250 if ((input_dev = input_map(minor)) == NULL)
251 return ENXIO;
253 if (!input_dev_active(input_dev))
254 return EIO;
256 switch (request) {
257 case KIOCSLEDS:
258 if ((r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &leds,
259 sizeof(leds))) != OK)
260 return r;
262 mask = 0;
263 if (leds.kl_bits & KBD_LEDS_NUM)
264 mask |= (1 << INPUT_LED_NUMLOCK);
265 if (leds.kl_bits & KBD_LEDS_CAPS)
266 mask |= (1 << INPUT_LED_CAPSLOCK);
267 if (leds.kl_bits & KBD_LEDS_SCROLL)
268 mask |= (1 << INPUT_LED_SCROLLLOCK);
270 input_set_leds(minor, mask);
272 return OK;
274 default:
275 return ENOTTY;
280 * Cancel a suspended read request.
282 static int
283 input_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id)
285 struct input_dev *input_dev;
287 if ((input_dev = input_map(minor)) == NULL)
288 return ENXIO;
290 if (input_dev->suspended && input_dev->caller == endpt &&
291 input_dev->req_id == id) {
292 input_dev->suspended = FALSE;
294 return EINTR;
297 return EDONTREPLY;
301 * Perform a select call on an input device.
303 static int
304 input_select(devminor_t minor, unsigned int ops, endpoint_t endpt)
306 struct input_dev *input_dev;
307 int ready_ops;
309 if ((input_dev = input_map(minor)) == NULL)
310 return ENXIO;
312 ready_ops = 0;
314 if (ops & CDEV_OP_RD) {
315 if (!input_dev_active(input_dev) || input_dev->suspended)
316 ready_ops |= CDEV_OP_RD; /* immediate error */
317 else if (!input_dev_buf_empty(input_dev))
318 ready_ops |= CDEV_OP_RD; /* data available */
319 else if (ops & CDEV_NOTIFY)
320 input_dev->selector = endpt; /* report later */
323 if (ops & CDEV_OP_WR) ready_ops |= CDEV_OP_WR; /* immediate error */
325 return ready_ops;
329 * An input device receives an input event. Enqueue it, and possibly unsuspend
330 * a read request or wake up a selector.
332 static void
333 input_process(struct input_dev *input_dev, const message *m)
335 unsigned int next;
336 int r;
338 if (input_dev_buf_full(input_dev)) {
339 /* Overflow. Overwrite the oldest event. */
340 input_dev->tail = (input_dev->tail + 1) % EVENTBUF_SIZE;
341 input_dev->count--;
343 #if INPUT_DEBUG
344 printf("INPUT: overflow on device %u\n", input_dev - devs);
345 #endif
347 next = (input_dev->tail + input_dev->count) % EVENTBUF_SIZE;
348 input_dev->eventbuf[next].page = m->m_linputdriver_input_event.page;
349 input_dev->eventbuf[next].code = m->m_linputdriver_input_event.code;
350 input_dev->eventbuf[next].value = m->m_linputdriver_input_event.value;
351 input_dev->eventbuf[next].flags = m->m_linputdriver_input_event.flags;
352 input_dev->eventbuf[next].devid = m->m_linputdriver_input_event.id;
353 input_dev->eventbuf[next].rsvd[0] = 0;
354 input_dev->eventbuf[next].rsvd[1] = 0;
355 input_dev->count++;
358 * There is new input. Revive a suspended reader if there was one.
359 * Otherwise see if we should reply to a select query.
361 if (input_dev->suspended) {
362 r = input_copy_events(input_dev->caller, input_dev->grant, 1,
363 input_dev);
364 chardriver_reply_task(input_dev->caller, input_dev->req_id, r);
365 input_dev->suspended = FALSE;
366 } else if (input_dev->selector != NONE) {
367 chardriver_reply_select(input_dev->selector, input_dev->minor,
368 CDEV_OP_RD);
369 input_dev->selector = NONE;
374 * An input event has arrived from a driver.
376 static void
377 input_event(message *m)
379 struct input_dev *input_dev, *mux_dev;
380 int r, id;
382 /* Unlike minor numbers, device IDs are in fact array indices. */
383 id = m->m_linputdriver_input_event.id;
384 if (id < 0 || id >= INPUT_DEV_MAX)
385 return;
387 /* The sender must owner the device. */
388 input_dev = &devs[id];
389 if (input_dev->owner != m->m_source)
390 return;
392 /* Input events are also delivered to the respective multiplexer. */
393 if (input_dev->minor >= KBD0_MINOR &&
394 input_dev->minor < KBD0_MINOR + KBD_MINORS)
395 mux_dev = &devs[KBDMUX_DEV];
396 else
397 mux_dev = &devs[MOUSEMUX_DEV];
400 * Try to deliver the event to the input device or otherwise the
401 * corresponding multiplexer. If neither are opened, forward the event
402 * to TTY.
404 if (input_dev->opened)
405 input_process(input_dev, m);
406 else if (mux_dev->opened)
407 input_process(mux_dev, m);
408 else {
409 message fwd;
410 mess_input_tty_event *tty_event = &(fwd.m_input_tty_event);
412 fwd.m_type = TTY_INPUT_EVENT;
413 tty_event->id = m->m_linputdriver_input_event.id;
414 tty_event->page = m->m_linputdriver_input_event.page;
415 tty_event->code = m->m_linputdriver_input_event.code;
416 tty_event->value = m->m_linputdriver_input_event.value;
417 tty_event->flags = m->m_linputdriver_input_event.flags;
419 if ((r = ipc_send(TTY_PROC_NR, &fwd)) != OK)
420 printf("INPUT: send to TTY failed (%d)\n", r);
425 * Allocate a device structure for an input driver of the given type, and
426 * return its ID. If the given label already owns a device ID of the right
427 * type, update that entry instead. If no device ID could be allocated, return
428 * INVALID_INPUT_ID.
430 static int
431 input_alloc_id(int mouse, endpoint_t owner, const char *label)
433 int n, id, start, end;
435 if (!mouse) {
436 start = FIRST_KBD_DEV;
437 end = LAST_KBD_DEV;
438 } else {
439 start = FIRST_MOUSE_DEV;
440 end = LAST_MOUSE_DEV;
443 id = INVALID_INPUT_ID;
444 for (n = start; n <= end; n++) {
445 if (devs[n].owner != NONE) {
446 if (!strcmp(devs[n].label, label)) {
447 devs[n].owner = owner;
448 return n;
450 /* Do not allocate the ID of a disconnected but open device. */
451 } else if (!devs[n].opened && id == INVALID_INPUT_ID) {
452 id = n;
456 if (id != INVALID_INPUT_ID) {
457 devs[id].owner = owner;
458 strlcpy(devs[id].label, label, sizeof(devs[id].label));
460 #if INPUT_DEBUG
461 printf("INPUT: connected device %u to %u (%s)\n", id,
462 owner, label);
463 #endif
464 } else {
465 printf("INPUT: out of %s slots for new driver %d\n",
466 mouse ? "mouse" : "keyboard", owner);
469 return id;
473 * Register keyboard and/or a mouse devices for a driver.
475 static void
476 input_connect(endpoint_t owner, char *labelp, int typemask)
478 message m;
479 char label[DS_MAX_KEYLEN];
480 int r, kbd_id, mouse_id;
482 #if INPUT_DEBUG
483 printf("INPUT: connect request from %u (%s) for mask %x\n", owner,
484 labelp, typemask);
485 #endif
487 /* Check the driver's label. */
488 if ((r = ds_retrieve_label_name(label, owner)) != OK) {
489 printf("INPUT: unable to get label for %u: %d\n", owner, r);
490 return;
492 if (strcmp(label, labelp)) {
493 printf("INPUT: ignoring driver %s label %s\n", label, labelp);
494 return;
497 kbd_id = INVALID_INPUT_ID;
498 mouse_id = INVALID_INPUT_ID;
501 * We ignore allocation failures here, thus possibly sending invalid
502 * IDs to the driver even for either or both the devices types it
503 * requested. As a result, the driver will not send us input for these
504 * device types, possibly effectively disabling the driver altogether.
505 * Theoretically we could still admit events to the multiplexers for
506 * such drivers, but that would lead to unexpected behavior with
507 * respect to keyboard LEDs, for example.
509 if (typemask & INPUT_DEV_KBD)
510 kbd_id = input_alloc_id(FALSE /*mouse*/, owner, label);
511 if (typemask & INPUT_DEV_MOUSE)
512 mouse_id = input_alloc_id(TRUE /*mouse*/, owner, label);
514 memset(&m, 0, sizeof(m));
516 m.m_type = INPUT_CONF;
517 m.m_input_linputdriver_input_conf.kbd_id = kbd_id;
518 m.m_input_linputdriver_input_conf.mouse_id = mouse_id;
519 m.m_input_linputdriver_input_conf.rsvd1_id = INVALID_INPUT_ID; /* reserved (joystick?) */
520 m.m_input_linputdriver_input_conf.rsvd2_id = INVALID_INPUT_ID; /* reserved for future use */
522 if ((r = asynsend3(owner, &m, AMF_NOREPLY)) != OK)
523 printf("INPUT: asynsend to %u failed (%d)\n", owner, r);
525 /* If a keyboard was registered, also set its initial LED state. */
526 if (kbd_id != INVALID_INPUT_ID)
527 input_set_leds(devs[kbd_id].minor, devs[kbd_id].leds);
531 * Disconnect a device.
533 static void
534 input_disconnect(struct input_dev *input_dev)
536 #if INPUT_DEBUG
537 printf("INPUT: disconnected device %u\n", input_dev - devs);
538 #endif
540 if (input_dev->suspended) {
541 chardriver_reply_task(input_dev->caller, input_dev->req_id,
542 EIO);
543 input_dev->suspended = FALSE;
546 if (input_dev->selector != NONE) {
547 chardriver_reply_select(input_dev->selector, input_dev->minor,
548 CDEV_OP_RD);
549 input_dev->selector = NONE;
552 input_dev->owner = NONE;
556 * Check for driver status changes in the data store.
558 static void
559 input_check(void)
561 char key[DS_MAX_KEYLEN], *label;
562 const char *driver_prefix = "drv.inp.";
563 u32_t value;
564 size_t len;
565 int i, r, type;
566 endpoint_t owner;
568 len = strlen(driver_prefix);
570 /* Check for new (input driver) entries. */
571 while (ds_check(key, &type, &owner) == OK) {
572 if ((r = ds_retrieve_u32(key, &value)) != OK) {
573 printf("INPUT: ds_retrieve_u32 failed (%d)\n", r);
574 continue;
577 /* Only check for input driver registration events. */
578 if (strncmp(key, driver_prefix, len))
579 continue;
581 /* The prefix is followed by the driver's own label. */
582 label = &key[len];
584 input_connect(owner, label, value);
587 /* Check for removed (label) entries. */
588 for (i = 0; i < INPUT_DEV_MAX; i++) {
589 /* This also skips the multiplexers. */
590 if (devs[i].owner == NONE)
591 continue;
593 r = ds_retrieve_label_endpt(devs[i].label, &owner);
595 if (r == OK)
596 devs[i].owner = owner; /* not really necessary */
597 else if (r == ESRCH)
598 input_disconnect(&devs[i]);
599 else
600 printf("INPUT: ds_retrieve_label_endpt failed (%d)\n",
606 * Process messages not part of the character driver protocol.
608 static void
609 input_other(message *m, int ipc_status)
611 if (is_ipc_notify(ipc_status)) {
612 switch (m->m_source) {
613 case DS_PROC_NR:
614 input_check();
615 break;
616 default:
617 printf("INPUT: unexpected notify from %d\n",
618 m->m_source);
620 return;
623 /* An input event from a registered driver. */
624 switch (m->m_type) {
625 case INPUT_EVENT:
626 input_event(m);
628 break;
630 case INPUT_SETLEDS:
631 if (m->m_source == TTY_PROC_NR) {
632 input_set_leds(KBDMUX_MINOR, m->m_input_linputdriver_setleds.led_mask);
634 break;
636 /* FALLTHROUGH */
637 default:
638 printf("INPUT: unexpected message %d from %d\n",
639 m->m_type, m->m_source);
644 * Initialize the input server.
646 static int
647 input_init(int UNUSED(type), sef_init_info_t *UNUSED(info))
649 message m;
650 int i, r;
652 /* Initialize input device structures. */
653 for (i = 0; i < INPUT_DEV_MAX; i++) {
654 devs[i].minor = input_revmap(i);
655 devs[i].owner = NONE;
656 devs[i].tail = 0;
657 devs[i].count = 0;
658 devs[i].opened = FALSE;
659 devs[i].suspended = FALSE;
660 devs[i].selector = NONE;
661 devs[i].leds = 0;
664 /* Subscribe to driver registration events for input drivers. */
665 if ((r = ds_subscribe("drv\\.inp\\..*", DSF_INITIAL)) != OK)
666 panic("INPUT: can't subscribe to driver events (%d)", r);
668 /* Announce our presence to VFS. */
669 chardriver_announce();
671 /* Announce our presence to TTY. */
672 memset(&m, 0, sizeof(m));
674 m.m_type = TTY_INPUT_UP;
676 if ((r = ipc_send(TTY_PROC_NR, &m)) != OK)
677 printf("INPUT: send to TTY failed (%d)\n", r);
679 return OK;
683 * Set callbacks and invoke SEF startup.
685 static void
686 input_startup(void)
688 sef_setcb_init_fresh(input_init);
690 sef_startup();
694 * Main program of the input server.
697 main(void)
699 input_startup();
701 chardriver_task(&input_tab);
703 return 0;