xref: /minix3/minix/servers/input/input.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
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>
7 
8 #include "input.h"
9 
10 #define INPUT_DEBUG 0
11 
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);
21 
22 static struct input_dev devs[INPUT_DEV_MAX];
23 
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)
29 
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
39 };
40 
41 /*
42  * Map a minor number to an input device structure.
43  */
44 static struct input_dev *
input_map(devminor_t minor)45 input_map(devminor_t minor)
46 {
47 	/*
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.
51 	 */
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;
62 }
63 
64 /*
65  * Map an input device structure index to a minor number.
66  */
67 static devminor_t
input_revmap(int id)68 input_revmap(int id)
69 {
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);
80 }
81 
82 /*
83  * Open an input device.
84  */
85 static int
input_open(devminor_t minor,int UNUSED (access),endpoint_t UNUSED (user_endpt))86 input_open(devminor_t minor, int UNUSED(access), endpoint_t UNUSED(user_endpt))
87 {
88 	struct input_dev *input_dev;
89 
90 	if ((input_dev = input_map(minor)) == NULL)
91 		return ENXIO;
92 
93 	if (!input_dev_active(input_dev))
94 		return ENXIO;
95 
96 	if (input_dev->opened)
97 		return EBUSY;
98 
99 	input_dev->opened = TRUE;
100 
101 	return OK;
102 }
103 
104 /*
105  * Close an input device.
106  */
107 static int
input_close(devminor_t minor)108 input_close(devminor_t minor)
109 {
110 	struct input_dev *input_dev;
111 
112 	if ((input_dev = input_map(minor)) == NULL)
113 		return ENXIO;
114 
115 	if (!input_dev->opened) {
116 		printf("INPUT: closing already-closed device %d\n", minor);
117 		return EINVAL;
118 	}
119 
120 	input_dev->opened = FALSE;
121 	input_dev->tail = 0;
122 	input_dev->count = 0;
123 
124 	return OK;
125 }
126 
127 /*
128  * Copy input events to a reader.
129  */
130 static ssize_t
input_copy_events(endpoint_t endpt,cp_grant_id_t grant,unsigned int event_count,struct input_dev * input_dev)131 input_copy_events(endpoint_t endpt, cp_grant_id_t grant,
132 	unsigned int event_count, struct input_dev *input_dev)
133 {
134 	int r, nbytes, wrap_left;
135 	size_t event_size = sizeof(*input_dev->eventbuf);
136 
137 	if (input_dev->count < event_count)
138 		panic("input_copy_events: not enough input is ready");
139 
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;
143 
144 	if ((r = sys_safecopyto(endpt, grant, 0,
145 	    (vir_bytes)(input_dev->eventbuf + input_dev->tail), nbytes)) != OK)
146 		return r;
147 
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;
152 
153 	input_dev->tail = (input_dev->tail + event_count) % EVENTBUF_SIZE;
154 	input_dev->count -= event_count;
155 
156 	return event_size * event_count; /* bytes copied */
157 }
158 
159 /*
160  * Read from an input device.
161  */
162 static ssize_t
input_read(devminor_t minor,u64_t UNUSED (position),endpoint_t endpt,cp_grant_id_t grant,size_t size,int flags,cdev_id_t id)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)
165 {
166 	unsigned int event_count;
167 	struct input_dev *input_dev;
168 
169 	if ((input_dev = input_map(minor)) == NULL)
170 		return ENXIO;
171 
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;
175 
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;
180 
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;
185 
186 		input_dev->suspended = TRUE;
187 		input_dev->caller = endpt;
188 		input_dev->grant = grant;
189 		input_dev->req_id = id;
190 
191 		/* We should now wake up any selector, but that's lame.. */
192 		return EDONTREPLY;
193 	}
194 
195 	if (event_count > input_dev->count)
196 		event_count = input_dev->count;
197 
198 	return input_copy_events(endpt, grant, event_count, input_dev);
199 }
200 
201 /*
202  * Set keyboard LEDs on one or all keyboards.
203  */
204 static void
input_set_leds(devminor_t minor,unsigned int mask)205 input_set_leds(devminor_t minor, unsigned int mask)
206 {
207 	struct input_dev *dev;
208 	message m;
209 	int i, r;
210 
211 	/* Prepare the request message */
212 	memset(&m, 0, sizeof(m));
213 
214 	m.m_type = INPUT_SETLEDS;
215 	m.m_input_linputdriver_setleds.led_mask = mask;
216 
217 	/*
218 	 * Send the request to all matching keyboard devices.  As side effect,
219 	 * this approach discards the request on mouse devices.
220 	 */
221 	for (i = FIRST_KBD_DEV; i <= LAST_KBD_DEV; i++) {
222 		dev = &devs[i];
223 
224 		if (minor != KBDMUX_MINOR && minor != dev->minor)
225 			continue;
226 
227 		/* Save the new state; the driver might (re)start later. */
228 		dev->leds = mask;
229 
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);
234 		}
235 	}
236 }
237 
238 /*
239  * Process an IOCTL request.
240  */
241 static int
input_ioctl(devminor_t minor,unsigned long request,endpoint_t endpt,cp_grant_id_t grant,int flags,endpoint_t user_endpt,cdev_id_t id)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)
244 {
245 	struct input_dev *input_dev;
246 	kio_leds_t leds;
247 	unsigned int mask;
248 	int r;
249 
250 	if ((input_dev = input_map(minor)) == NULL)
251 		return ENXIO;
252 
253 	if (!input_dev_active(input_dev))
254 		return EIO;
255 
256 	switch (request) {
257 	case KIOCSLEDS:
258 		if ((r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &leds,
259 		    sizeof(leds))) != OK)
260 			return r;
261 
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);
269 
270 		input_set_leds(minor, mask);
271 
272 		return OK;
273 
274 	default:
275 		return ENOTTY;
276 	}
277 }
278 
279 /*
280  * Cancel a suspended read request.
281  */
282 static int
input_cancel(devminor_t minor,endpoint_t endpt,cdev_id_t id)283 input_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id)
284 {
285 	struct input_dev *input_dev;
286 
287 	if ((input_dev = input_map(minor)) == NULL)
288 		return ENXIO;
289 
290 	if (input_dev->suspended && input_dev->caller == endpt &&
291 	    input_dev->req_id == id) {
292 		input_dev->suspended = FALSE;
293 
294 		return EINTR;
295 	}
296 
297 	return EDONTREPLY;
298 }
299 
300 /*
301  * Perform a select call on an input device.
302  */
303 static int
input_select(devminor_t minor,unsigned int ops,endpoint_t endpt)304 input_select(devminor_t minor, unsigned int ops, endpoint_t endpt)
305 {
306 	struct input_dev *input_dev;
307 	int ready_ops;
308 
309 	if ((input_dev = input_map(minor)) == NULL)
310 		return ENXIO;
311 
312 	ready_ops = 0;
313 
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 */
321 	}
322 
323 	if (ops & CDEV_OP_WR) ready_ops |= CDEV_OP_WR;	/* immediate error */
324 
325 	return ready_ops;
326 }
327 
328 /*
329  * An input device receives an input event.  Enqueue it, and possibly unsuspend
330  * a read request or wake up a selector.
331  */
332 static void
input_process(struct input_dev * input_dev,const message * m)333 input_process(struct input_dev *input_dev, const message *m)
334 {
335 	unsigned int next;
336 	int r;
337 
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--;
342 
343 #if INPUT_DEBUG
344 		printf("INPUT: overflow on device %u\n", input_dev - devs);
345 #endif
346 	}
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++;
356 
357 	/*
358 	 * There is new input.  Revive a suspended reader if there was one.
359 	 * Otherwise see if we should reply to a select query.
360 	 */
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;
370 	}
371 }
372 
373 /*
374  * An input event has arrived from a driver.
375  */
376 static void
input_event(message * m)377 input_event(message *m)
378 {
379 	struct input_dev *input_dev, *mux_dev;
380 	int r, id;
381 
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;
386 
387 	/* The sender must owner the device. */
388 	input_dev = &devs[id];
389 	if (input_dev->owner != m->m_source)
390 		return;
391 
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];
398 
399 	/*
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.
403 	 */
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);
411 
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;
418 
419 		if ((r = ipc_send(TTY_PROC_NR, &fwd)) != OK)
420 			printf("INPUT: send to TTY failed (%d)\n", r);
421 	}
422 }
423 
424 /*
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.
429  */
430 static int
input_alloc_id(int mouse,endpoint_t owner,const char * label)431 input_alloc_id(int mouse, endpoint_t owner, const char *label)
432 {
433 	int n, id, start, end;
434 
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;
441 	}
442 
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;
449 			}
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;
453 		}
454 	}
455 
456 	if (id != INVALID_INPUT_ID) {
457 		devs[id].owner = owner;
458 		strlcpy(devs[id].label, label, sizeof(devs[id].label));
459 
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);
467 	}
468 
469 	return id;
470 }
471 
472 /*
473  * Register keyboard and/or a mouse devices for a driver.
474  */
475 static void
input_connect(endpoint_t owner,char * labelp,int typemask)476 input_connect(endpoint_t owner, char *labelp, int typemask)
477 {
478 	message m;
479 	char label[DS_MAX_KEYLEN];
480 	int r, kbd_id, mouse_id;
481 
482 #if INPUT_DEBUG
483 	printf("INPUT: connect request from %u (%s) for mask %x\n", owner,
484 	    labelp, typemask);
485 #endif
486 
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;
491 	}
492 	if (strcmp(label, labelp)) {
493 		printf("INPUT: ignoring driver %s label %s\n", label, labelp);
494 		return;
495 	}
496 
497 	kbd_id = INVALID_INPUT_ID;
498 	mouse_id = INVALID_INPUT_ID;
499 
500 	/*
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.
508 	 */
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);
513 
514 	memset(&m, 0, sizeof(m));
515 
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 */
521 
522 	if ((r = asynsend3(owner, &m, AMF_NOREPLY)) != OK)
523 		printf("INPUT: asynsend to %u failed (%d)\n", owner, r);
524 
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);
528 }
529 
530 /*
531  * Disconnect a device.
532  */
533 static void
input_disconnect(struct input_dev * input_dev)534 input_disconnect(struct input_dev *input_dev)
535 {
536 #if INPUT_DEBUG
537 	printf("INPUT: disconnected device %u\n", input_dev - devs);
538 #endif
539 
540 	if (input_dev->suspended) {
541 		chardriver_reply_task(input_dev->caller, input_dev->req_id,
542 		    EIO);
543 		input_dev->suspended = FALSE;
544 	}
545 
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;
550 	}
551 
552 	input_dev->owner = NONE;
553 }
554 
555 /*
556  * Check for driver status changes in the data store.
557  */
558 static void
input_check(void)559 input_check(void)
560 {
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;
567 
568 	len = strlen(driver_prefix);
569 
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;
575 		}
576 
577 		/* Only check for input driver registration events. */
578 		if (strncmp(key, driver_prefix, len))
579 			continue;
580 
581 		/* The prefix is followed by the driver's own label. */
582 		label = &key[len];
583 
584 		input_connect(owner, label, value);
585 	}
586 
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;
592 
593 		r = ds_retrieve_label_endpt(devs[i].label, &owner);
594 
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",
601 			    r);
602 	}
603 }
604 
605 /*
606  * Process messages not part of the character driver protocol.
607  */
608 static void
input_other(message * m,int ipc_status)609 input_other(message *m, int ipc_status)
610 {
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);
619 		}
620 		return;
621 	}
622 
623 	/* An input event from a registered driver. */
624 	switch (m->m_type) {
625 	case INPUT_EVENT:
626 		input_event(m);
627 
628 		break;
629 
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);
633 
634 			break;
635 		}
636 		/* FALLTHROUGH */
637 	default:
638 		printf("INPUT: unexpected message %d from %d\n",
639 		    m->m_type, m->m_source);
640 	}
641 }
642 
643 /*
644  * Initialize the input server.
645  */
646 static int
input_init(int UNUSED (type),sef_init_info_t * UNUSED (info))647 input_init(int UNUSED(type), sef_init_info_t *UNUSED(info))
648 {
649 	message m;
650 	int i, r;
651 
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;
662 	}
663 
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);
667 
668 	/* Announce our presence to VFS. */
669 	chardriver_announce();
670 
671 	/* Announce our presence to TTY. */
672 	memset(&m, 0, sizeof(m));
673 
674 	m.m_type = TTY_INPUT_UP;
675 
676 	if ((r = ipc_send(TTY_PROC_NR, &m)) != OK)
677 		printf("INPUT: send to TTY failed (%d)\n", r);
678 
679 	return OK;
680 }
681 
682 /*
683  * Set callbacks and invoke SEF startup.
684  */
685 static void
input_startup(void)686 input_startup(void)
687 {
688 	sef_setcb_init_fresh(input_init);
689 
690 	sef_startup();
691 }
692 
693 /*
694  * Main program of the input server.
695  */
696 int
main(void)697 main(void)
698 {
699 	input_startup();
700 
701 	chardriver_task(&input_tab);
702 
703 	return 0;
704 }
705