source: mainline/uspace/srv/hid/input/input.c@ f5837524

Last change on this file since f5837524 was f5837524, checked in by Jakub Jermar <jakub@…>, 7 years ago

Use user-defined labels instead of phone hashes

This commit changes the way how the async framework maps incomming calls
to connections. Instead of abusing the kernel addresses of attached
phones as identifiers, the IPC_M_CONNECT_TO_ME and IPC_M_CONNECT_ME_TO
messages allow the server to specify an arbitrary label which is
remembered in the connected phone and consequently imprinted on each
call which is routed through this phone.

The async framework uses the address of the connection structure as the
label. This removes the need for a connection hash table because each
incoming call already remembers the connection in its label.

To disambiguate this new label and the other user-defined label used for
answers, the call structure now has the request_label member for the
former and answer_label member for the latter.

This commit also moves the kernel definition of ipc_data_t to abi/ and
removes the uspace redefinition thereof. Finally, when forwarding the
IPC_M_CONNECT_TO_ME call, the phone capability and the kernel object
allocated in request_process are now correctly disposed of.

  • Property mode set to 100644
File size: 19.0 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_5(icall, EOK, 0, 0, 0, 0, async_get_label());
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/** Add legacy drivers/devices. */
613static void kbd_add_legacy_devs(void)
614{
615 /*
616 * Need to add these drivers based on config unless we can probe
617 * them automatically.
618 */
619#if defined(UARCH_arm32) && defined(MACHINE_gta02)
620 kbd_add_dev(&chardev_port, &stty_ctl);
621#endif
622#if defined(UARCH_ia64) && defined(MACHINE_ski)
623 kbd_add_dev(&chardev_port, &stty_ctl);
624#endif
625#if defined(MACHINE_msim)
626 kbd_add_dev(&chardev_port, &stty_ctl);
627#endif
628#if defined(UARCH_sparc64) && defined(PROCESSOR_sun4v)
629 kbd_add_dev(&chardev_port, &stty_ctl);
630#endif
631 /* Silence warning on abs32le about kbd_add_dev() being unused */
632 (void) kbd_add_dev;
633}
634
635static errno_t dev_check_new_kbdevs(void)
636{
637 category_id_t keyboard_cat;
638 service_id_t *svcs;
639 size_t count, i;
640 bool already_known;
641 errno_t rc;
642
643 rc = loc_category_get_id("keyboard", &keyboard_cat, IPC_FLAG_BLOCKING);
644 if (rc != EOK) {
645 printf("%s: Failed resolving category 'keyboard'.\n", NAME);
646 return ENOENT;
647 }
648
649 /*
650 * Check for new keyboard devices
651 */
652 rc = loc_category_get_svcs(keyboard_cat, &svcs, &count);
653 if (rc != EOK) {
654 printf("%s: Failed getting list of keyboard devices.\n",
655 NAME);
656 return EIO;
657 }
658
659 for (i = 0; i < count; i++) {
660 already_known = false;
661
662 /* Determine whether we already know this device. */
663 list_foreach(kbd_devs, link, kbd_dev_t, kdev) {
664 if (kdev->svc_id == svcs[i]) {
665 already_known = true;
666 break;
667 }
668 }
669
670 if (!already_known) {
671 kbd_dev_t *kdev;
672 if (kbd_add_kbdev(svcs[i], &kdev) == 0) {
673 printf("%s: Connected keyboard device '%s'\n",
674 NAME, kdev->svc_name);
675 }
676 }
677 }
678
679 free(svcs);
680
681 /* XXX Handle device removal */
682
683 return EOK;
684}
685
686static errno_t dev_check_new_mousedevs(void)
687{
688 category_id_t mouse_cat;
689 service_id_t *svcs;
690 size_t count, i;
691 bool already_known;
692 errno_t rc;
693
694 rc = loc_category_get_id("mouse", &mouse_cat, IPC_FLAG_BLOCKING);
695 if (rc != EOK) {
696 printf("%s: Failed resolving category 'mouse'.\n", NAME);
697 return ENOENT;
698 }
699
700 /*
701 * Check for new mouse devices
702 */
703 rc = loc_category_get_svcs(mouse_cat, &svcs, &count);
704 if (rc != EOK) {
705 printf("%s: Failed getting list of mouse devices.\n",
706 NAME);
707 return EIO;
708 }
709
710 for (i = 0; i < count; i++) {
711 already_known = false;
712
713 /* Determine whether we already know this device. */
714 list_foreach(mouse_devs, link, mouse_dev_t, mdev) {
715 if (mdev->svc_id == svcs[i]) {
716 already_known = true;
717 break;
718 }
719 }
720
721 if (!already_known) {
722 mouse_dev_t *mdev;
723 if (mouse_add_mousedev(svcs[i], &mdev) == 0) {
724 printf("%s: Connected mouse device '%s'\n",
725 NAME, mdev->svc_name);
726 }
727 }
728 }
729
730 free(svcs);
731
732 /* XXX Handle device removal */
733
734 return EOK;
735}
736
737static errno_t dev_check_new_serialdevs(void)
738{
739 category_id_t serial_cat;
740 service_id_t *svcs;
741 size_t count, i;
742 bool already_known;
743 errno_t rc;
744
745 rc = loc_category_get_id("serial", &serial_cat, IPC_FLAG_BLOCKING);
746 if (rc != EOK) {
747 printf("%s: Failed resolving category 'serial'.\n", NAME);
748 return ENOENT;
749 }
750
751 /*
752 * Check for new serial devices
753 */
754 rc = loc_category_get_svcs(serial_cat, &svcs, &count);
755 if (rc != EOK) {
756 printf("%s: Failed getting list of serial devices.\n",
757 NAME);
758 return EIO;
759 }
760
761 for (i = 0; i < count; i++) {
762 already_known = false;
763
764 /* Determine whether we already know this device. */
765 list_foreach(serial_devs, link, serial_dev_t, sdev) {
766 if (sdev->kdev->svc_id == svcs[i]) {
767 already_known = true;
768 break;
769 }
770 }
771
772 if (!already_known) {
773 serial_dev_t *sdev;
774 if (serial_add_srldev(svcs[i], &sdev) == 0) {
775 printf("%s: Connected serial device '%s'\n",
776 NAME, sdev->kdev->svc_name);
777 }
778 }
779 }
780
781 free(svcs);
782
783 /* XXX Handle device removal */
784
785 return EOK;
786}
787
788static errno_t dev_check_new(void)
789{
790 errno_t rc;
791
792 fibril_mutex_lock(&discovery_lock);
793
794 if (!serial_console) {
795 rc = dev_check_new_kbdevs();
796 if (rc != EOK) {
797 fibril_mutex_unlock(&discovery_lock);
798 return rc;
799 }
800
801 rc = dev_check_new_mousedevs();
802 if (rc != EOK) {
803 fibril_mutex_unlock(&discovery_lock);
804 return rc;
805 }
806 } else {
807 rc = dev_check_new_serialdevs();
808 if (rc != EOK) {
809 fibril_mutex_unlock(&discovery_lock);
810 return rc;
811 }
812 }
813
814 fibril_mutex_unlock(&discovery_lock);
815
816 return EOK;
817}
818
819static void cat_change_cb(void *arg)
820{
821 dev_check_new();
822}
823
824/** Start listening for new devices. */
825static errno_t input_start_dev_discovery(void)
826{
827 errno_t rc = loc_register_cat_change_cb(cat_change_cb, NULL);
828 if (rc != EOK) {
829 printf("%s: Failed registering callback for device discovery: "
830 "%s\n", NAME, str_error(rc));
831 return rc;
832 }
833
834 return dev_check_new();
835}
836
837static void usage(char *name)
838{
839 printf("Usage: %s <service_name>\n", name);
840}
841
842int main(int argc, char **argv)
843{
844 errno_t rc;
845
846 if (argc < 2) {
847 usage(argv[0]);
848 return 1;
849 }
850
851 printf("%s: HelenOS input service\n", NAME);
852
853 list_initialize(&clients);
854 list_initialize(&kbd_devs);
855 list_initialize(&mouse_devs);
856 list_initialize(&serial_devs);
857
858 serial_console = config_get_value("console");
859
860 /* Add legacy keyboard devices. */
861 kbd_add_legacy_devs();
862
863 /* Register driver */
864 async_set_client_data_constructor(client_data_create);
865 async_set_client_data_destructor(client_data_destroy);
866 async_set_fallback_port_handler(client_connection, NULL);
867
868 rc = loc_server_register(NAME);
869 if (rc != EOK) {
870 printf("%s: Unable to register server\n", NAME);
871 return rc;
872 }
873
874 service_id_t service_id;
875 rc = loc_service_register(argv[1], &service_id);
876 if (rc != EOK) {
877 printf("%s: Unable to register service %s\n", NAME, argv[1]);
878 return rc;
879 }
880
881 /* Receive kernel notifications */
882 rc = async_event_subscribe(EVENT_KCONSOLE, kconsole_event_handler, NULL);
883 if (rc != EOK)
884 printf("%s: Failed to register kconsole notifications (%s)\n",
885 NAME, str_error(rc));
886
887 /* Start looking for new input devices */
888 input_start_dev_discovery();
889
890 printf("%s: Accepting connections\n", NAME);
891 task_retval(0);
892 async_manager();
893
894 /* Not reached. */
895 return 0;
896}
897
898/**
899 * @}
900 */
Note: See TracBrowser for help on using the repository browser.