source: mainline/uspace/srv/hid/input/input.c@ 63d46341

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 63d46341 was 984a9ba, checked in by Martin Decky <martin@…>, 8 years ago

do not expose the call capability handler from the async framework

Keep the call capability handler encapsulated within the async framework
and do not expose it explicitly via its API. Use the pointer to
ipc_call_t as the sole object identifying an IPC call in the code that
uses the async framework.

This plugs a major leak in the abstraction and also simplifies both the
async framework (slightly) and all IPC servers.

  • Property mode set to 100644
File size: 18.9 KB
Line 
1/*
2 * Copyright (c) 2006 Josef Cejka
3 * Copyright (c) 2011 Jiri Svoboda
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/**
31 * @addtogroup inputgen generic
32 * @brief HelenOS input server.
33 * @ingroup input
34 * @{
35 */
36/** @file
37 */
38
39#include <adt/fifo.h>
40#include <adt/list.h>
41#include <async.h>
42#include <config.h>
43#include <errno.h>
44#include <fibril.h>
45#include <fibril_synch.h>
46#include <io/chardev.h>
47#include <io/console.h>
48#include <io/keycode.h>
49#include <ipc/services.h>
50#include <ipc/input.h>
51#include <loc.h>
52#include <ns.h>
53#include <stdbool.h>
54#include <stdio.h>
55#include <stdlib.h>
56#include <str.h>
57#include <str_error.h>
58
59#include "input.h"
60#include "kbd.h"
61#include "kbd_port.h"
62#include "kbd_ctl.h"
63#include "layout.h"
64#include "mouse.h"
65#include "mouse_proto.h"
66#include "serial.h"
67
68#define NUM_LAYOUTS 4
69
70static layout_ops_t *layout[NUM_LAYOUTS] = {
71 &us_qwerty_ops,
72 &us_dvorak_ops,
73 &cz_ops,
74 &ar_ops
75};
76
77typedef struct {
78 /** Link into the list of clients */
79 link_t link;
80
81 /** Indicate whether the client is active */
82 bool active;
83
84 /** Client callback session */
85 async_sess_t *sess;
86} client_t;
87
88/** List of clients */
89static list_t clients;
90static client_t *active_client = NULL;
91
92/** Kernel override */
93static bool active = true;
94
95/** Serial console specified by the user */
96static char *serial_console;
97
98/** List of keyboard devices */
99static list_t kbd_devs;
100
101/** List of mouse devices */
102static list_t mouse_devs;
103
104/** List of serial devices */
105static list_t serial_devs;
106
107static FIBRIL_MUTEX_INITIALIZE(discovery_lock);
108
109static void *client_data_create(void)
110{
111 client_t *client = (client_t *) calloc(1, sizeof(client_t));
112 if (client == NULL)
113 return NULL;
114
115 link_initialize(&client->link);
116 client->active = false;
117 client->sess = NULL;
118
119 list_append(&client->link, &clients);
120
121 return client;
122}
123
124static void client_data_destroy(void *data)
125{
126 client_t *client = (client_t *) data;
127
128 list_remove(&client->link);
129 free(client);
130}
131
132void kbd_push_data(kbd_dev_t *kdev, sysarg_t data)
133{
134 (*kdev->ctl_ops->parse)(data);
135}
136
137void mouse_push_data(mouse_dev_t *mdev, sysarg_t data)
138{
139 (*mdev->proto_ops->parse)(data);
140}
141
142void kbd_push_event(kbd_dev_t *kdev, int type, unsigned int key)
143{
144 kbd_event_t ev;
145 unsigned int mod_mask;
146
147 switch (key) {
148 case KC_LCTRL:
149 mod_mask = KM_LCTRL;
150 break;
151 case KC_RCTRL:
152 mod_mask = KM_RCTRL;
153 break;
154 case KC_LSHIFT:
155 mod_mask = KM_LSHIFT;
156 break;
157 case KC_RSHIFT:
158 mod_mask = KM_RSHIFT;
159 break;
160 case KC_LALT:
161 mod_mask = KM_LALT;
162 break;
163 case KC_RALT:
164 mod_mask = KM_RALT;
165 break;
166 default:
167 mod_mask = 0;
168 }
169
170 if (mod_mask != 0) {
171 if (type == KEY_PRESS)
172 kdev->mods = kdev->mods | mod_mask;
173 else
174 kdev->mods = kdev->mods & ~mod_mask;
175 }
176
177 switch (key) {
178 case KC_CAPS_LOCK:
179 mod_mask = KM_CAPS_LOCK;
180 break;
181 case KC_NUM_LOCK:
182 mod_mask = KM_NUM_LOCK;
183 break;
184 case KC_SCROLL_LOCK:
185 mod_mask = KM_SCROLL_LOCK;
186 break;
187 default:
188 mod_mask = 0;
189 }
190
191 if (mod_mask != 0) {
192 if (type == KEY_PRESS) {
193 /*
194 * Only change lock state on transition from released
195 * to pressed. This prevents autorepeat from messing
196 * up the lock state.
197 */
198 kdev->mods = kdev->mods ^ (mod_mask & ~kdev->lock_keys);
199 kdev->lock_keys = kdev->lock_keys | mod_mask;
200
201 /* Update keyboard lock indicator lights. */
202 (*kdev->ctl_ops->set_ind)(kdev, kdev->mods);
203 } else {
204 kdev->lock_keys = kdev->lock_keys & ~mod_mask;
205 }
206 }
207
208 // TODO: More elegant layout switching
209
210 if ((type == KEY_PRESS) && (kdev->mods & KM_LCTRL) &&
211 (key == KC_F1)) {
212 layout_destroy(kdev->active_layout);
213 kdev->active_layout = layout_create(layout[0]);
214 return;
215 }
216
217 if ((type == KEY_PRESS) && (kdev->mods & KM_LCTRL) &&
218 (key == KC_F2)) {
219 layout_destroy(kdev->active_layout);
220 kdev->active_layout = layout_create(layout[1]);
221 return;
222 }
223
224 if ((type == KEY_PRESS) && (kdev->mods & KM_LCTRL) &&
225 (key == KC_F3)) {
226 layout_destroy(kdev->active_layout);
227 kdev->active_layout = layout_create(layout[2]);
228 return;
229 }
230
231 if ((type == KEY_PRESS) && (kdev->mods & KM_LCTRL) &&
232 (key == KC_F4)) {
233 layout_destroy(kdev->active_layout);
234 kdev->active_layout = layout_create(layout[3]);
235 return;
236 }
237
238 ev.type = type;
239 ev.key = key;
240 ev.mods = kdev->mods;
241
242 ev.c = layout_parse_ev(kdev->active_layout, &ev);
243
244 list_foreach(clients, link, client_t, client) {
245 if (client->active) {
246 async_exch_t *exch = async_exchange_begin(client->sess);
247 async_msg_4(exch, INPUT_EVENT_KEY, ev.type, ev.key, ev.mods, ev.c);
248 async_exchange_end(exch);
249 }
250 }
251}
252
253/** Mouse pointer has moved (relative mode). */
254void mouse_push_event_move(mouse_dev_t *mdev, int dx, int dy, int dz)
255{
256 list_foreach(clients, link, client_t, client) {
257 if (client->active) {
258 async_exch_t *exch = async_exchange_begin(client->sess);
259
260 if ((dx) || (dy))
261 async_msg_2(exch, INPUT_EVENT_MOVE, dx, dy);
262
263 if (dz) {
264 // TODO: Implement proper wheel support
265 keycode_t code = dz > 0 ? KC_UP : KC_DOWN;
266
267 for (unsigned int i = 0; i < 3; i++)
268 async_msg_4(exch, INPUT_EVENT_KEY, KEY_PRESS, code, 0, 0);
269
270 async_msg_4(exch, INPUT_EVENT_KEY, KEY_RELEASE, code, 0, 0);
271 }
272
273 async_exchange_end(exch);
274 }
275 }
276}
277
278/** Mouse pointer has moved (absolute mode). */
279void mouse_push_event_abs_move(mouse_dev_t *mdev, unsigned int x, unsigned int y,
280 unsigned int max_x, unsigned int max_y)
281{
282 list_foreach(clients, link, client_t, client) {
283 if (client->active) {
284 if ((max_x) && (max_y)) {
285 async_exch_t *exch = async_exchange_begin(client->sess);
286 async_msg_4(exch, INPUT_EVENT_ABS_MOVE, x, y, max_x, max_y);
287 async_exchange_end(exch);
288 }
289 }
290 }
291}
292
293/** Mouse button has been pressed. */
294void mouse_push_event_button(mouse_dev_t *mdev, int bnum, int press)
295{
296 list_foreach(clients, link, client_t, client) {
297 if (client->active) {
298 async_exch_t *exch = async_exchange_begin(client->sess);
299 async_msg_2(exch, INPUT_EVENT_BUTTON, bnum, press);
300 async_exchange_end(exch);
301 }
302 }
303}
304
305/** Arbitrate client actiovation */
306static void client_arbitration(void)
307{
308 /* Mutual exclusion of active clients */
309 list_foreach(clients, link, client_t, client)
310 client->active = ((active) && (client == active_client));
311
312 /* Notify clients about the arbitration */
313 list_foreach(clients, link, client_t, client) {
314 async_exch_t *exch = async_exchange_begin(client->sess);
315 async_msg_0(exch, client->active ?
316 INPUT_EVENT_ACTIVE : INPUT_EVENT_DEACTIVE);
317 async_exchange_end(exch);
318 }
319}
320
321/** New client connection */
322static void client_connection(ipc_call_t *icall, void *arg)
323{
324 client_t *client = (client_t *) async_get_client_data();
325 if (client == NULL) {
326 async_answer_0(icall, ENOMEM);
327 return;
328 }
329
330 async_answer_0(icall, EOK);
331
332 while (true) {
333 ipc_call_t call;
334 async_get_call(&call);
335
336 if (!IPC_GET_IMETHOD(call)) {
337 if (client->sess != NULL) {
338 async_hangup(client->sess);
339 client->sess = NULL;
340 }
341
342 async_answer_0(&call, EOK);
343 return;
344 }
345
346 async_sess_t *sess =
347 async_callback_receive_start(EXCHANGE_SERIALIZE, &call);
348 if (sess != NULL) {
349 if (client->sess == NULL) {
350 client->sess = sess;
351 async_answer_0(&call, EOK);
352 } else
353 async_answer_0(&call, ELIMIT);
354 } else {
355 switch (IPC_GET_IMETHOD(call)) {
356 case INPUT_ACTIVATE:
357 active_client = client;
358 client_arbitration();
359 async_answer_0(&call, EOK);
360 break;
361 default:
362 async_answer_0(&call, EINVAL);
363 }
364 }
365 }
366}
367
368static void kconsole_event_handler(ipc_call_t *call, void *arg)
369{
370 if (IPC_GET_ARG1(*call)) {
371 /* Kernel console activated */
372 active = false;
373 } else {
374 /* Kernel console deactivated */
375 active = true;
376 }
377
378 client_arbitration();
379}
380
381static kbd_dev_t *kbd_dev_new(void)
382{
383 kbd_dev_t *kdev = calloc(1, sizeof(kbd_dev_t));
384 if (kdev == NULL) {
385 printf("%s: Error allocating keyboard device. "
386 "Out of memory.\n", NAME);
387 return NULL;
388 }
389
390 link_initialize(&kdev->link);
391
392 kdev->mods = KM_NUM_LOCK;
393 kdev->lock_keys = 0;
394 kdev->active_layout = layout_create(layout[0]);
395
396 return kdev;
397}
398
399static mouse_dev_t *mouse_dev_new(void)
400{
401 mouse_dev_t *mdev = calloc(1, sizeof(mouse_dev_t));
402 if (mdev == NULL) {
403 printf("%s: Error allocating mouse device. "
404 "Out of memory.\n", NAME);
405 return NULL;
406 }
407
408 link_initialize(&mdev->link);
409
410 return mdev;
411}
412
413static serial_dev_t *serial_dev_new(void)
414{
415 serial_dev_t *sdev = calloc(1, sizeof(serial_dev_t));
416 if (sdev == NULL) {
417 printf("%s: Error allocating serial device. "
418 "Out of memory.\n", NAME);
419 return NULL;
420 }
421
422 sdev->kdev = kbd_dev_new();
423 if (sdev->kdev == NULL) {
424 free(sdev);
425 return NULL;
426 }
427
428 link_initialize(&sdev->link);
429
430 return sdev;
431}
432
433/** Add new legacy keyboard device. */
434static void kbd_add_dev(kbd_port_ops_t *port, kbd_ctl_ops_t *ctl)
435{
436 kbd_dev_t *kdev = kbd_dev_new();
437 if (kdev == NULL)
438 return;
439
440 kdev->port_ops = port;
441 kdev->ctl_ops = ctl;
442 kdev->svc_id = 0;
443
444 /* Initialize port driver. */
445 if ((*kdev->port_ops->init)(kdev) != 0)
446 goto fail;
447
448 /* Initialize controller driver. */
449 if ((*kdev->ctl_ops->init)(kdev) != 0) {
450 /* XXX Uninit port */
451 goto fail;
452 }
453
454 list_append(&kdev->link, &kbd_devs);
455 return;
456
457fail:
458 free(kdev);
459}
460
461/** Add new kbdev device.
462 *
463 * @param service_id Service ID of the keyboard device
464 *
465 */
466static int kbd_add_kbdev(service_id_t service_id, kbd_dev_t **kdevp)
467{
468 kbd_dev_t *kdev = kbd_dev_new();
469 if (kdev == NULL)
470 return -1;
471
472 kdev->svc_id = service_id;
473 kdev->port_ops = NULL;
474 kdev->ctl_ops = &kbdev_ctl;
475
476 errno_t rc = loc_service_get_name(service_id, &kdev->svc_name);
477 if (rc != EOK) {
478 kdev->svc_name = NULL;
479 goto fail;
480 }
481
482 /* Initialize controller driver. */
483 if ((*kdev->ctl_ops->init)(kdev) != 0) {
484 goto fail;
485 }
486
487 list_append(&kdev->link, &kbd_devs);
488 *kdevp = kdev;
489 return 0;
490
491fail:
492 if (kdev->svc_name != NULL)
493 free(kdev->svc_name);
494 free(kdev);
495 return -1;
496}
497
498/** Add new mousedev device.
499 *
500 * @param service_id Service ID of the mouse device
501 *
502 */
503static int mouse_add_mousedev(service_id_t service_id, mouse_dev_t **mdevp)
504{
505 mouse_dev_t *mdev = mouse_dev_new();
506 if (mdev == NULL)
507 return -1;
508
509 mdev->svc_id = service_id;
510 mdev->port_ops = NULL;
511 mdev->proto_ops = &mousedev_proto;
512
513 errno_t rc = loc_service_get_name(service_id, &mdev->svc_name);
514 if (rc != EOK) {
515 mdev->svc_name = NULL;
516 goto fail;
517 }
518
519 /* Initialize controller driver. */
520 if ((*mdev->proto_ops->init)(mdev) != 0) {
521 goto fail;
522 }
523
524 list_append(&mdev->link, &mouse_devs);
525 *mdevp = mdev;
526 return 0;
527
528fail:
529 free(mdev);
530 return -1;
531}
532
533static errno_t serial_consumer(void *arg)
534{
535 serial_dev_t *sdev = (serial_dev_t *) arg;
536
537 while (true) {
538 uint8_t data;
539 size_t nread;
540
541 chardev_read(sdev->chardev, &data, sizeof(data), &nread);
542 /* XXX Handle error */
543 kbd_push_data(sdev->kdev, data);
544 }
545
546 return EOK;
547}
548
549/** Add new serial console device.
550 *
551 * @param service_id Service ID of the chardev device
552 *
553 */
554static int serial_add_srldev(service_id_t service_id, serial_dev_t **sdevp)
555{
556 bool match = false;
557 errno_t rc;
558
559 serial_dev_t *sdev = serial_dev_new();
560 if (sdev == NULL)
561 return -1;
562
563 sdev->kdev->svc_id = service_id;
564
565 rc = loc_service_get_name(service_id, &sdev->kdev->svc_name);
566 if (rc != EOK)
567 goto fail;
568
569 list_append(&sdev->link, &serial_devs);
570
571 /*
572 * Is this the device the user wants to use as a serial console?
573 */
574 match = (serial_console != NULL) &&
575 !str_cmp(serial_console, sdev->kdev->svc_name);
576
577 if (match) {
578 sdev->kdev->ctl_ops = &stty_ctl;
579
580 /* Initialize controller driver. */
581 if ((*sdev->kdev->ctl_ops->init)(sdev->kdev) != 0) {
582 list_remove(&sdev->link);
583 goto fail;
584 }
585
586 sdev->sess = loc_service_connect(service_id, INTERFACE_DDF,
587 IPC_FLAG_BLOCKING);
588
589 rc = chardev_open(sdev->sess, &sdev->chardev);
590 if (rc != EOK) {
591 async_hangup(sdev->sess);
592 sdev->sess = NULL;
593 list_remove(&sdev->link);
594 goto fail;
595 }
596
597 fid_t fid = fibril_create(serial_consumer, sdev);
598 fibril_add_ready(fid);
599 }
600
601 *sdevp = sdev;
602 return 0;
603
604fail:
605 if (sdev->kdev->svc_name != NULL)
606 free(sdev->kdev->svc_name);
607 free(sdev->kdev);
608 free(sdev);
609 return -1;
610}
611
612
613/** Add legacy drivers/devices. */
614static void kbd_add_legacy_devs(void)
615{
616 /*
617 * Need to add these drivers based on config unless we can probe
618 * them automatically.
619 */
620#if defined(UARCH_arm32) && defined(MACHINE_gta02)
621 kbd_add_dev(&chardev_port, &stty_ctl);
622#endif
623#if defined(UARCH_ia64) && defined(MACHINE_ski)
624 kbd_add_dev(&chardev_port, &stty_ctl);
625#endif
626#if defined(MACHINE_msim)
627 kbd_add_dev(&chardev_port, &stty_ctl);
628#endif
629#if defined(UARCH_sparc64) && defined(PROCESSOR_sun4v)
630 kbd_add_dev(&chardev_port, &stty_ctl);
631#endif
632 /* Silence warning on abs32le about kbd_add_dev() being unused */
633 (void) kbd_add_dev;
634}
635
636static errno_t dev_check_new_kbdevs(void)
637{
638 category_id_t keyboard_cat;
639 service_id_t *svcs;
640 size_t count, i;
641 bool already_known;
642 errno_t rc;
643
644 rc = loc_category_get_id("keyboard", &keyboard_cat, IPC_FLAG_BLOCKING);
645 if (rc != EOK) {
646 printf("%s: Failed resolving category 'keyboard'.\n", NAME);
647 return ENOENT;
648 }
649
650 /*
651 * Check for new keyboard devices
652 */
653 rc = loc_category_get_svcs(keyboard_cat, &svcs, &count);
654 if (rc != EOK) {
655 printf("%s: Failed getting list of keyboard devices.\n",
656 NAME);
657 return EIO;
658 }
659
660 for (i = 0; i < count; i++) {
661 already_known = false;
662
663 /* Determine whether we already know this device. */
664 list_foreach(kbd_devs, link, kbd_dev_t, kdev) {
665 if (kdev->svc_id == svcs[i]) {
666 already_known = true;
667 break;
668 }
669 }
670
671 if (!already_known) {
672 kbd_dev_t *kdev;
673 if (kbd_add_kbdev(svcs[i], &kdev) == 0) {
674 printf("%s: Connected keyboard device '%s'\n",
675 NAME, kdev->svc_name);
676 }
677 }
678 }
679
680 free(svcs);
681
682 /* XXX Handle device removal */
683
684 return EOK;
685}
686
687static errno_t dev_check_new_mousedevs(void)
688{
689 category_id_t mouse_cat;
690 service_id_t *svcs;
691 size_t count, i;
692 bool already_known;
693 errno_t rc;
694
695 rc = loc_category_get_id("mouse", &mouse_cat, IPC_FLAG_BLOCKING);
696 if (rc != EOK) {
697 printf("%s: Failed resolving category 'mouse'.\n", NAME);
698 return ENOENT;
699 }
700
701 /*
702 * Check for new mouse devices
703 */
704 rc = loc_category_get_svcs(mouse_cat, &svcs, &count);
705 if (rc != EOK) {
706 printf("%s: Failed getting list of mouse devices.\n",
707 NAME);
708 return EIO;
709 }
710
711 for (i = 0; i < count; i++) {
712 already_known = false;
713
714 /* Determine whether we already know this device. */
715 list_foreach(mouse_devs, link, mouse_dev_t, mdev) {
716 if (mdev->svc_id == svcs[i]) {
717 already_known = true;
718 break;
719 }
720 }
721
722 if (!already_known) {
723 mouse_dev_t *mdev;
724 if (mouse_add_mousedev(svcs[i], &mdev) == 0) {
725 printf("%s: Connected mouse device '%s'\n",
726 NAME, mdev->svc_name);
727 }
728 }
729 }
730
731 free(svcs);
732
733 /* XXX Handle device removal */
734
735 return EOK;
736}
737
738static errno_t dev_check_new_serialdevs(void)
739{
740 category_id_t serial_cat;
741 service_id_t *svcs;
742 size_t count, i;
743 bool already_known;
744 errno_t rc;
745
746 rc = loc_category_get_id("serial", &serial_cat, IPC_FLAG_BLOCKING);
747 if (rc != EOK) {
748 printf("%s: Failed resolving category 'serial'.\n", NAME);
749 return ENOENT;
750 }
751
752 /*
753 * Check for new serial devices
754 */
755 rc = loc_category_get_svcs(serial_cat, &svcs, &count);
756 if (rc != EOK) {
757 printf("%s: Failed getting list of serial devices.\n",
758 NAME);
759 return EIO;
760 }
761
762 for (i = 0; i < count; i++) {
763 already_known = false;
764
765 /* Determine whether we already know this device. */
766 list_foreach(serial_devs, link, serial_dev_t, sdev) {
767 if (sdev->kdev->svc_id == svcs[i]) {
768 already_known = true;
769 break;
770 }
771 }
772
773 if (!already_known) {
774 serial_dev_t *sdev;
775 if (serial_add_srldev(svcs[i], &sdev) == 0) {
776 printf("%s: Connected serial device '%s'\n",
777 NAME, sdev->kdev->svc_name);
778 }
779 }
780 }
781
782 free(svcs);
783
784 /* XXX Handle device removal */
785
786 return EOK;
787}
788
789static errno_t dev_check_new(void)
790{
791 errno_t rc;
792
793 fibril_mutex_lock(&discovery_lock);
794
795 if (!serial_console) {
796 rc = dev_check_new_kbdevs();
797 if (rc != EOK) {
798 fibril_mutex_unlock(&discovery_lock);
799 return rc;
800 }
801
802 rc = dev_check_new_mousedevs();
803 if (rc != EOK) {
804 fibril_mutex_unlock(&discovery_lock);
805 return rc;
806 }
807 } else {
808 rc = dev_check_new_serialdevs();
809 if (rc != EOK) {
810 fibril_mutex_unlock(&discovery_lock);
811 return rc;
812 }
813 }
814
815 fibril_mutex_unlock(&discovery_lock);
816
817 return EOK;
818}
819
820static void cat_change_cb(void)
821{
822 dev_check_new();
823}
824
825/** Start listening for new devices. */
826static errno_t input_start_dev_discovery(void)
827{
828 errno_t rc = loc_register_cat_change_cb(cat_change_cb);
829 if (rc != EOK) {
830 printf("%s: Failed registering callback for device discovery: "
831 "%s\n", NAME, str_error(rc));
832 return rc;
833 }
834
835 return dev_check_new();
836}
837
838static void usage(char *name)
839{
840 printf("Usage: %s <service_name>\n", name);
841}
842
843int main(int argc, char **argv)
844{
845 errno_t rc;
846
847 if (argc < 2) {
848 usage(argv[0]);
849 return 1;
850 }
851
852 printf("%s: HelenOS input service\n", NAME);
853
854 list_initialize(&clients);
855 list_initialize(&kbd_devs);
856 list_initialize(&mouse_devs);
857 list_initialize(&serial_devs);
858
859 serial_console = config_get_value("console");
860
861 /* Add legacy keyboard devices. */
862 kbd_add_legacy_devs();
863
864 /* Register driver */
865 async_set_client_data_constructor(client_data_create);
866 async_set_client_data_destructor(client_data_destroy);
867 async_set_fallback_port_handler(client_connection, NULL);
868
869 rc = loc_server_register(NAME);
870 if (rc != EOK) {
871 printf("%s: Unable to register server\n", NAME);
872 return rc;
873 }
874
875 service_id_t service_id;
876 rc = loc_service_register(argv[1], &service_id);
877 if (rc != EOK) {
878 printf("%s: Unable to register service %s\n", NAME, argv[1]);
879 return rc;
880 }
881
882 /* Receive kernel notifications */
883 rc = async_event_subscribe(EVENT_KCONSOLE, kconsole_event_handler, NULL);
884 if (rc != EOK)
885 printf("%s: Failed to register kconsole notifications (%s)\n",
886 NAME, str_error(rc));
887
888 /* Start looking for new input devices */
889 input_start_dev_discovery();
890
891 printf("%s: Accepting connections\n", NAME);
892 task_retval(0);
893 async_manager();
894
895 /* Not reached. */
896 return 0;
897}
898
899/**
900 * @}
901 */
Note: See TracBrowser for help on using the repository browser.