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
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 kbdgen generic
32 * @brief HelenOS generic uspace keyboard handler.
33 * @ingroup kbd
34 * @{
35 */
36/** @file
37 */
38
39#include <adt/list.h>
40#include <ipc/services.h>
41#include <ipc/kbd.h>
42#include <sysinfo.h>
43#include <stdio.h>
44#include <unistd.h>
45#include <stdlib.h>
46#include <stdio.h>
47#include <ns.h>
48#include <ns_obsolete.h>
49#include <async.h>
50#include <async_obsolete.h>
51#include <errno.h>
52#include <adt/fifo.h>
53#include <io/console.h>
54#include <io/keycode.h>
55#include <devmap.h>
56#include <kbd.h>
57#include <kbd_port.h>
58#include <kbd_ctl.h>
59#include <layout.h>
60
61// FIXME: remove this header
62#include <kernel/ipc/ipc_methods.h>
63
64#define NAME "kbd"
65#define NAMESPACE "hid_in"
66
67static void kbd_devs_yield(void);
68static void kbd_devs_reclaim(void);
69
70int client_phone = -1;
71
72/** Currently active modifiers. */
73static unsigned mods = KM_NUM_LOCK;
74
75/** Currently pressed lock keys. We track these to tackle autorepeat. */
76static unsigned lock_keys;
77
78/** List of keyboard devices */
79static link_t kbd_devs;
80
81bool irc_service = false;
82int irc_phone = -1;
83
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
94void kbd_push_scancode(kbd_dev_t *kdev, int scancode)
95{
96/* printf("scancode: 0x%x\n", scancode);*/
97 (*kdev->ctl_ops->parse_scancode)(scancode);
98}
99
100void kbd_push_ev(kbd_dev_t *kdev, int type, unsigned int key)
101{
102 kbd_event_t ev;
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) {
116 if (type == KEY_PRESS)
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
129 if (mod_mask != 0) {
130 if (type == KEY_PRESS) {
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;
138
139 /* Update keyboard lock indicator lights. */
140 (*kdev->ctl_ops->set_ind)(mods);
141 } else {
142 lock_keys = lock_keys & ~mod_mask;
143 }
144 }
145/*
146 printf("type: %d\n", type);
147 printf("mods: 0x%x\n", mods);
148 printf("keycode: %u\n", key);
149*/
150 if (type == KEY_PRESS && (mods & KM_LCTRL) &&
151 key == KC_F1) {
152 active_layout = 0;
153 layout[active_layout]->reset();
154 return;
155 }
156
157 if (type == KEY_PRESS && (mods & KM_LCTRL) &&
158 key == KC_F2) {
159 active_layout = 1;
160 layout[active_layout]->reset();
161 return;
162 }
163
164 if (type == KEY_PRESS && (mods & KM_LCTRL) &&
165 key == KC_F3) {
166 active_layout = 2;
167 layout[active_layout]->reset();
168 return;
169 }
170
171 ev.type = type;
172 ev.key = key;
173 ev.mods = mods;
174
175 ev.c = layout[active_layout]->parse_ev(&ev);
176
177 async_obsolete_msg_4(client_phone, KBD_EVENT, ev.type, ev.key, ev.mods, ev.c);
178}
179
180static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
181{
182 ipc_callid_t callid;
183 ipc_call_t call;
184 int retval;
185
186 async_answer_0(iid, EOK);
187
188 while (true) {
189 callid = async_get_call(&call);
190
191 if (!IPC_GET_IMETHOD(call)) {
192 if (client_phone != -1) {
193 async_obsolete_hangup(client_phone);
194 client_phone = -1;
195 }
196
197 async_answer_0(callid, EOK);
198 return;
199 }
200
201 switch (IPC_GET_IMETHOD(call)) {
202 case IPC_M_CONNECT_TO_ME:
203 if (client_phone != -1) {
204 retval = ELIMIT;
205 break;
206 }
207 client_phone = IPC_GET_ARG5(call);
208 retval = 0;
209 break;
210 case KBD_YIELD:
211 kbd_devs_yield();
212 retval = 0;
213 break;
214 case KBD_RECLAIM:
215 kbd_devs_reclaim();
216 retval = 0;
217 break;
218 default:
219 retval = EINVAL;
220 }
221 async_answer_0(callid, retval);
222 }
223}
224
225/** Add new keyboard device. */
226static void kbd_add_dev(kbd_port_ops_t *port, kbd_ctl_ops_t *ctl)
227{
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. */
241 if (kdev->port_ops != NULL) {
242 if ((*kdev->port_ops->init)(kdev) != 0)
243 goto fail;
244 }
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 */
265#if defined(UARCH_amd64)
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);
294#endif
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)
308 kbd_add_dev(&z8530_port, &sun_ctl);
309 kbd_add_dev(&ns16550_port, &sun_ctl);
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 */
321 if (kdev->port_ops != NULL)
322 (*kdev->port_ops->yield)();
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 */
334 if (kdev->port_ops != NULL)
335 (*kdev->port_ops->reclaim)();
336 }
337}
338
339int main(int argc, char **argv)
340{
341 printf("%s: HelenOS Keyboard service\n", NAME);
342
343 sysarg_t fhc;
344 sysarg_t obio;
345
346 list_initialize(&kbd_devs);
347
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;
351
352 if (irc_service) {
353 while (irc_phone < 0)
354 irc_phone = service_obsolete_connect_blocking(SERVICE_IRC, 0, 0);
355 }
356
357 /* Add legacy devices. */
358 kbd_add_legacy_devs();
359
360 /* Add kbdev device */
361 kbd_add_dev(NULL, &kbdev_ctl);
362
363 /* Initialize (reset) layout. */
364 layout[active_layout]->reset();
365
366 /* Register driver */
367 int rc = devmap_driver_register(NAME, client_connection);
368 if (rc < 0) {
369 printf("%s: Unable to register driver (%d)\n", NAME, rc);
370 return -1;
371 }
372
373 char kbd[DEVMAP_NAME_MAXLEN + 1];
374 snprintf(kbd, DEVMAP_NAME_MAXLEN, "%s/%s", NAMESPACE, NAME);
375
376 devmap_handle_t devmap_handle;
377 if (devmap_device_register(kbd, &devmap_handle) != EOK) {
378 printf("%s: Unable to register device %s\n", NAME, kbd);
379 return -1;
380 }
381
382 printf(NAME ": Accepting connections\n");
383 async_manager();
384
385 /* Not reached. */
386 return 0;
387}
388
389/**
390 * @}
391 */
Note: See TracBrowser for help on using the repository browser.