1 /* Keyboard/mouse input server. */
2 #include <minix/drivers.h>
3 #include <minix/chardriver.h>
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,
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
)];
65 * Map an input device structure index to a minor number.
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
);
79 panic("reverse-mapping invalid ID %d", id
);
83 * Open an input device.
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
)
93 if (!input_dev_active(input_dev
))
96 if (input_dev
->opened
)
99 input_dev
->opened
= TRUE
;
105 * Close an input device.
108 input_close(devminor_t minor
)
110 struct input_dev
*input_dev
;
112 if ((input_dev
= input_map(minor
)) == NULL
)
115 if (!input_dev
->opened
) {
116 printf("INPUT: closing already-closed device %d\n", minor
);
120 input_dev
->opened
= FALSE
;
122 input_dev
->count
= 0;
128 * Copy input events to a reader.
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
)
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
)
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.
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
)
172 /* We cannot accept more than one pending read request at once. */
173 if (!input_dev_active(input_dev
) || input_dev
->suspended
)
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)
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
)
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.. */
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.
205 input_set_leds(devminor_t minor
, unsigned int mask
)
207 struct input_dev
*dev
;
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
++) {
224 if (minor
!= KBDMUX_MINOR
&& minor
!= dev
->minor
)
227 /* Save the new state; the driver might (re)start later. */
230 if (dev
->owner
!= NONE
) {
231 if ((r
= asynsend3(dev
->owner
, &m
, AMF_NOREPLY
)) != OK
)
232 printf("INPUT: asynsend to %u failed (%d)\n",
239 * Process an IOCTL request.
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
;
250 if ((input_dev
= input_map(minor
)) == NULL
)
253 if (!input_dev_active(input_dev
))
258 if ((r
= sys_safecopyfrom(endpt
, grant
, 0, (vir_bytes
) &leds
,
259 sizeof(leds
))) != OK
)
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
);
280 * Cancel a suspended read request.
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
)
290 if (input_dev
->suspended
&& input_dev
->caller
== endpt
&&
291 input_dev
->req_id
== id
) {
292 input_dev
->suspended
= FALSE
;
301 * Perform a select call on an input device.
304 input_select(devminor_t minor
, unsigned int ops
, endpoint_t endpt
)
306 struct input_dev
*input_dev
;
309 if ((input_dev
= input_map(minor
)) == NULL
)
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 */
329 * An input device receives an input event. Enqueue it, and possibly unsuspend
330 * a read request or wake up a selector.
333 input_process(struct input_dev
*input_dev
, const message
*m
)
338 if (input_dev_buf_full(input_dev
)) {
339 /* Overflow. Overwrite the oldest event. */
340 input_dev
->tail
= (input_dev
->tail
+ 1) % EVENTBUF_SIZE
;
344 printf("INPUT: overflow on device %u\n", input_dev
- devs
);
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;
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,
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
,
369 input_dev
->selector
= NONE
;
374 * An input event has arrived from a driver.
377 input_event(message
*m
)
379 struct input_dev
*input_dev
, *mux_dev
;
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
)
387 /* The sender must owner the device. */
388 input_dev
= &devs
[id
];
389 if (input_dev
->owner
!= m
->m_source
)
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
];
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
404 if (input_dev
->opened
)
405 input_process(input_dev
, m
);
406 else if (mux_dev
->opened
)
407 input_process(mux_dev
, m
);
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
431 input_alloc_id(int mouse
, endpoint_t owner
, const char *label
)
433 int n
, id
, start
, end
;
436 start
= FIRST_KBD_DEV
;
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
;
450 /* Do not allocate the ID of a disconnected but open device. */
451 } else if (!devs
[n
].opened
&& id
== INVALID_INPUT_ID
) {
456 if (id
!= INVALID_INPUT_ID
) {
457 devs
[id
].owner
= owner
;
458 strlcpy(devs
[id
].label
, label
, sizeof(devs
[id
].label
));
461 printf("INPUT: connected device %u to %u (%s)\n", id
,
465 printf("INPUT: out of %s slots for new driver %d\n",
466 mouse
? "mouse" : "keyboard", owner
);
473 * Register keyboard and/or a mouse devices for a driver.
476 input_connect(endpoint_t owner
, char *labelp
, int typemask
)
479 char label
[DS_MAX_KEYLEN
];
480 int r
, kbd_id
, mouse_id
;
483 printf("INPUT: connect request from %u (%s) for mask %x\n", owner
,
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
);
492 if (strcmp(label
, labelp
)) {
493 printf("INPUT: ignoring driver %s label %s\n", label
, labelp
);
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.
534 input_disconnect(struct input_dev
*input_dev
)
537 printf("INPUT: disconnected device %u\n", input_dev
- devs
);
540 if (input_dev
->suspended
) {
541 chardriver_reply_task(input_dev
->caller
, input_dev
->req_id
,
543 input_dev
->suspended
= FALSE
;
546 if (input_dev
->selector
!= NONE
) {
547 chardriver_reply_select(input_dev
->selector
, input_dev
->minor
,
549 input_dev
->selector
= NONE
;
552 input_dev
->owner
= NONE
;
556 * Check for driver status changes in the data store.
561 char key
[DS_MAX_KEYLEN
], *label
;
562 const char *driver_prefix
= "drv.inp.";
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
);
577 /* Only check for input driver registration events. */
578 if (strncmp(key
, driver_prefix
, len
))
581 /* The prefix is followed by the driver's own label. */
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
)
593 r
= ds_retrieve_label_endpt(devs
[i
].label
, &owner
);
596 devs
[i
].owner
= owner
; /* not really necessary */
598 input_disconnect(&devs
[i
]);
600 printf("INPUT: ds_retrieve_label_endpt failed (%d)\n",
606 * Process messages not part of the character driver protocol.
609 input_other(message
*m
, int ipc_status
)
611 if (is_ipc_notify(ipc_status
)) {
612 switch (m
->m_source
) {
617 printf("INPUT: unexpected notify from %d\n",
623 /* An input event from a registered driver. */
631 if (m
->m_source
== TTY_PROC_NR
) {
632 input_set_leds(KBDMUX_MINOR
, m
->m_input_linputdriver_setleds
.led_mask
);
638 printf("INPUT: unexpected message %d from %d\n",
639 m
->m_type
, m
->m_source
);
644 * Initialize the input server.
647 input_init(int UNUSED(type
), sef_init_info_t
*UNUSED(info
))
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
;
658 devs
[i
].opened
= FALSE
;
659 devs
[i
].suspended
= FALSE
;
660 devs
[i
].selector
= NONE
;
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
);
683 * Set callbacks and invoke SEF startup.
688 sef_setcb_init_fresh(input_init
);
694 * Main program of the input server.
701 chardriver_task(&input_tab
);