source: mainline/uspace/srv/hid/kbd/generic/kbd.c@ f2f99ae

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f2f99ae was f2f99ae, checked in by Jiri Svoboda <jiri@…>, 14 years ago

Route USB keyboard through kbd server (new device polling needs fixing).

  • Property mode set to 100644
File size: 9.2 KB
RevLine 
[51d6f80]1/*
[df4ed85]2 * Copyright (c) 2006 Josef Cejka
[9be360ee]3 * Copyright (c) 2011 Jiri Svoboda
[51d6f80]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
[231a60a]30/**
31 * @addtogroup kbdgen generic
[215abc1]32 * @brief HelenOS generic uspace keyboard handler.
33 * @ingroup kbd
[ce5bcb4]34 * @{
[215abc1]35 */
[ce5bcb4]36/** @file
37 */
38
[9be360ee]39#include <adt/list.h>
[7ee6aff]40#include <ipc/services.h>
[e795203]41#include <ipc/kbd.h>
[3e5a814]42#include <sysinfo.h>
[51d6f80]43#include <stdio.h>
44#include <unistd.h>
45#include <stdlib.h>
[37458472]46#include <stdio.h>
[79ae36dd]47#include <ns.h>
48#include <ns_obsolete.h>
[fa09449]49#include <async.h>
[79ae36dd]50#include <async_obsolete.h>
[51d6f80]51#include <errno.h>
[d9c8c81]52#include <adt/fifo.h>
[215abc1]53#include <io/console.h>
54#include <io/keycode.h>
[47a350f]55#include <devmap.h>
[51d6f80]56#include <kbd.h>
[f89979b]57#include <kbd_port.h>
58#include <kbd_ctl.h>
59#include <layout.h>
[51d6f80]60
[79ae36dd]61// FIXME: remove this header
62#include <kernel/ipc/ipc_methods.h>
63
[47a350f]64#define NAME "kbd"
65#define NAMESPACE "hid_in"
[854387b]66
[9be360ee]67static void kbd_devs_yield(void);
68static void kbd_devs_reclaim(void);
69
[3f29834]70int client_phone = -1;
[d1eece6]71
72/** Currently active modifiers. */
[90e3d6a]73static unsigned mods = KM_NUM_LOCK;
[085bd54]74
[12b6796]75/** Currently pressed lock keys. We track these to tackle autorepeat. */
76static unsigned lock_keys;
77
[9be360ee]78/** List of keyboard devices */
79static link_t kbd_devs;
[b1bdc7a4]80
[57d129e]81bool irc_service = false;
82int irc_phone = -1;
[3e5a814]83
[0175246]84#define NUM_LAYOUTS 3
85
86static layout_op_t *layout[NUM_LAYOUTS] = {
87 &us_qwerty_op,
88 &us_dvorak_op,
89 &cz_op
90};
91
92static int active_layout = 0;
93
[9be360ee]94void kbd_push_scancode(kbd_dev_t *kdev, int scancode)
[f89979b]95{
[5ad8661]96/* printf("scancode: 0x%x\n", scancode);*/
[9be360ee]97 (*kdev->ctl_ops->parse_scancode)(scancode);
[f89979b]98}
99
[9be360ee]100void kbd_push_ev(kbd_dev_t *kdev, int type, unsigned int key)
[085bd54]101{
[79ae36dd]102 kbd_event_t ev;
[d1eece6]103 unsigned mod_mask;
104
105 switch (key) {
106 case KC_LCTRL: mod_mask = KM_LCTRL; break;
107 case KC_RCTRL: mod_mask = KM_RCTRL; break;
108 case KC_LSHIFT: mod_mask = KM_LSHIFT; break;
109 case KC_RSHIFT: mod_mask = KM_RSHIFT; break;
110 case KC_LALT: mod_mask = KM_LALT; break;
111 case KC_RALT: mod_mask = KM_RALT; break;
112 default: mod_mask = 0; break;
113 }
114
115 if (mod_mask != 0) {
[215abc1]116 if (type == KEY_PRESS)
[d1eece6]117 mods = mods | mod_mask;
118 else
119 mods = mods & ~mod_mask;
120 }
121
122 switch (key) {
123 case KC_CAPS_LOCK: mod_mask = KM_CAPS_LOCK; break;
124 case KC_NUM_LOCK: mod_mask = KM_NUM_LOCK; break;
125 case KC_SCROLL_LOCK: mod_mask = KM_SCROLL_LOCK; break;
126 default: mod_mask = 0; break;
127 }
128
[12b6796]129 if (mod_mask != 0) {
[215abc1]130 if (type == KEY_PRESS) {
[12b6796]131 /*
132 * Only change lock state on transition from released
133 * to pressed. This prevents autorepeat from messing
134 * up the lock state.
135 */
136 mods = mods ^ (mod_mask & ~lock_keys);
137 lock_keys = lock_keys | mod_mask;
[c145bc2]138
139 /* Update keyboard lock indicator lights. */
[9be360ee]140 (*kdev->ctl_ops->set_ind)(mods);
[12b6796]141 } else {
142 lock_keys = lock_keys & ~mod_mask;
143 }
144 }
[5ad8661]145/*
[f89979b]146 printf("type: %d\n", type);
147 printf("mods: 0x%x\n", mods);
148 printf("keycode: %u\n", key);
[5ad8661]149*/
[215abc1]150 if (type == KEY_PRESS && (mods & KM_LCTRL) &&
[0175246]151 key == KC_F1) {
152 active_layout = 0;
[d15815e2]153 layout[active_layout]->reset();
[0175246]154 return;
155 }
156
[215abc1]157 if (type == KEY_PRESS && (mods & KM_LCTRL) &&
[0175246]158 key == KC_F2) {
159 active_layout = 1;
[d15815e2]160 layout[active_layout]->reset();
[0175246]161 return;
162 }
163
[215abc1]164 if (type == KEY_PRESS && (mods & KM_LCTRL) &&
[0175246]165 key == KC_F3) {
166 active_layout = 2;
[d15815e2]167 layout[active_layout]->reset();
[0175246]168 return;
169 }
170
[f89979b]171 ev.type = type;
172 ev.key = key;
173 ev.mods = mods;
174
[0175246]175 ev.c = layout[active_layout]->parse_ev(&ev);
[f89979b]176
[79ae36dd]177 async_obsolete_msg_4(client_phone, KBD_EVENT, ev.type, ev.key, ev.mods, ev.c);
[085bd54]178}
179
[3f29834]180static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
[085bd54]181{
182 ipc_callid_t callid;
183 ipc_call_t call;
184 int retval;
185
[ffa2c8ef]186 async_answer_0(iid, EOK);
[085bd54]187
[79ae36dd]188 while (true) {
[085bd54]189 callid = async_get_call(&call);
[79ae36dd]190
191 if (!IPC_GET_IMETHOD(call)) {
[3f29834]192 if (client_phone != -1) {
[79ae36dd]193 async_obsolete_hangup(client_phone);
[3f29834]194 client_phone = -1;
[47a350f]195 }
196
[ffa2c8ef]197 async_answer_0(callid, EOK);
[085bd54]198 return;
[79ae36dd]199 }
200
201 switch (IPC_GET_IMETHOD(call)) {
[085bd54]202 case IPC_M_CONNECT_TO_ME:
[3f29834]203 if (client_phone != -1) {
[085bd54]204 retval = ELIMIT;
205 break;
206 }
[3f29834]207 client_phone = IPC_GET_ARG5(call);
[085bd54]208 retval = 0;
209 break;
[ccd1a14]210 case KBD_YIELD:
[9be360ee]211 kbd_devs_yield();
[ccd1a14]212 retval = 0;
213 break;
214 case KBD_RECLAIM:
[9be360ee]215 kbd_devs_reclaim();
[ccd1a14]216 retval = 0;
217 break;
[153a209]218 default:
219 retval = EINVAL;
[085bd54]220 }
[ffa2c8ef]221 async_answer_0(callid, retval);
[085bd54]222 }
223}
224
[9be360ee]225/** Add new keyboard device. */
226static void kbd_add_dev(kbd_port_ops_t *port, kbd_ctl_ops_t *ctl)
[b1bdc7a4]227{
[9be360ee]228 kbd_dev_t *kdev;
229
230 kdev = malloc(sizeof(kbd_dev_t));
231 if (kdev == NULL) {
232 printf(NAME ": Failed adding keyboard device. Out of memory.\n");
233 return;
234 }
235
236 link_initialize(&kdev->kbd_devs);
237 kdev->port_ops = port;
238 kdev->ctl_ops = ctl;
239
240 /* Initialize port driver. */
[f2f99ae]241 if (kdev->port_ops != NULL) {
242 if ((*kdev->port_ops->init)(kdev) != 0)
243 goto fail;
244 }
[9be360ee]245
246 /* Initialize controller driver. */
247 if ((*kdev->ctl_ops->init)(kdev) != 0) {
248 /* XXX Uninit port */
249 goto fail;
250 }
251
252 list_append(&kdev->kbd_devs, &kbd_devs);
253 return;
254fail:
255 free(kdev);
256}
257
258/** Add legacy drivers/devices. */
259static void kbd_add_legacy_devs(void)
260{
261 /*
262 * Need to add these drivers based on config unless we can probe
263 * them automatically.
264 */
[b1bdc7a4]265#if defined(UARCH_amd64)
[9be360ee]266 kbd_add_dev(&chardev_port, &pc_ctl);
267#endif
268#if defined(UARCH_arm32) && defined(MACHINE_gta02)
269 kbd_add_dev(&chardev_port, &stty_ctl);
270#endif
271#if defined(UARCH_arm32) && defined(MACHINE_testarm) && defined(CONFIG_FB)
272 kbd_add_dev(&gxemul_port, &gxe_fb_ctl);
273#endif
274#if defined(UARCH_arm32) && defined(MACHINE_testarm) && !defined(CONFIG_FB)
275 kbd_add_dev(&gxemul_port, &stty_ctl);
276#endif
277#if defined(UARCH_arm32) && defined(MACHINE_integratorcp)
278 kbd_add_dev(&pl050_port, &pc_ctl);
279#endif
280#if defined(UARCH_ia32)
281 kbd_add_dev(&chardev_port, &pc_ctl);
282#endif
283#if defined(MACHINE_i460GX)
284 kbd_add_dev(&chardev_port, &pc_ctl);
285#endif
286#if defined(MACHINE_ski)
287 kbd_add_dev(&ski_port, &stty_ctl);
288#endif
289#if defined(MACHINE_msim)
290 kbd_add_dev(&msim_port, &pc_ctl);
291#endif
292#if (defined(MACHINE_lgxemul) || defined(MACHINE_bgxemul)) && defined(CONFIG_FB)
293 kbd_add_dev(&gxemul_port, &gxe_fb_ctl);
[b1bdc7a4]294#endif
[9be360ee]295#if defined(MACHINE_lgxemul) || defined(MACHINE_bgxemul) && !defined(CONFIG_FB)
296 kbd_add_dev(&gxemul_port, &stty_ctl);
297#endif
298#if defined(UARCH_ppc32)
299 kbd_add_dev(&adb_port, &apple_ctl);
300#endif
301#if defined(UARCH_sparc64) && defined(PROCESSOR_sun4v)
302 kbd_add_dev(&niagara_port, &stty_ctl);
303#endif
304#if defined(UARCH_sparc64) && defined(MACHINE_serengeti)
305 kbd_add_dev(&sgcn_port, &stty_ctl);
306#endif
307#if defined(UARCH_sparc64) && defined(MACHINE_generic)
[4f3f9659]308 kbd_add_dev(&z8530_port, &sun_ctl);
309 kbd_add_dev(&ns16550_port, &sun_ctl);
[9be360ee]310#endif
311}
312
313static void kbd_devs_yield(void)
314{
315 /* For each keyboard device */
316 list_foreach(kbd_devs, kdev_link) {
317 kbd_dev_t *kdev = list_get_instance(kdev_link, kbd_dev_t,
318 kbd_devs);
319
320 /* Yield port */
[f2f99ae]321 if (kdev->port_ops != NULL)
322 (*kdev->port_ops->yield)();
[9be360ee]323 }
324}
325
326static void kbd_devs_reclaim(void)
327{
328 /* For each keyboard device */
329 list_foreach(kbd_devs, kdev_link) {
330 kbd_dev_t *kdev = list_get_instance(kdev_link, kbd_dev_t,
331 kbd_devs);
332
333 /* Reclaim port */
[f2f99ae]334 if (kdev->port_ops != NULL)
335 (*kdev->port_ops->reclaim)();
[9be360ee]336 }
[b1bdc7a4]337}
[085bd54]338
[51d6f80]339int main(int argc, char **argv)
340{
[d9fae235]341 printf("%s: HelenOS Keyboard service\n", NAME);
[e00938c]342
[d9fae235]343 sysarg_t fhc;
344 sysarg_t obio;
345
[9be360ee]346 list_initialize(&kbd_devs);
347
[57d129e]348 if (((sysinfo_get_value("kbd.cir.fhc", &fhc) == EOK) && (fhc))
349 || ((sysinfo_get_value("kbd.cir.obio", &obio) == EOK) && (obio)))
350 irc_service = true;
[3e5a814]351
[57d129e]352 if (irc_service) {
353 while (irc_phone < 0)
[79ae36dd]354 irc_phone = service_obsolete_connect_blocking(SERVICE_IRC, 0, 0);
[3e5a814]355 }
356
[9be360ee]357 /* Add legacy devices. */
358 kbd_add_legacy_devs();
[d15815e2]359
[f2f99ae]360 /* Add kbdev device */
361 kbd_add_dev(NULL, &kbdev_ctl);
362
[d15815e2]363 /* Initialize (reset) layout. */
364 layout[active_layout]->reset();
[51d6f80]365
[47a350f]366 /* Register driver */
[3f29834]367 int rc = devmap_driver_register(NAME, client_connection);
[47a350f]368 if (rc < 0) {
[d9fae235]369 printf("%s: Unable to register driver (%d)\n", NAME, rc);
[51d6f80]370 return -1;
[47a350f]371 }
372
373 char kbd[DEVMAP_NAME_MAXLEN + 1];
374 snprintf(kbd, DEVMAP_NAME_MAXLEN, "%s/%s", NAMESPACE, NAME);
[e00938c]375
[991f645]376 devmap_handle_t devmap_handle;
377 if (devmap_device_register(kbd, &devmap_handle) != EOK) {
[d9fae235]378 printf("%s: Unable to register device %s\n", NAME, kbd);
[47a350f]379 return -1;
380 }
381
[e00938c]382 printf(NAME ": Accepting connections\n");
[085bd54]383 async_manager();
[51c1b003]384
[f89979b]385 /* Not reached. */
[153a209]386 return 0;
[51d6f80]387}
[ce5bcb4]388
389/**
390 * @}
391 */
Note: See TracBrowser for help on using the repository browser.