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

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

Control keyboard port modules through ops structures. Allows compiling in
all modules at the same time.

  • Property mode set to 100644
File size: 7.4 KB
Line 
1/*
2 * Copyright (c) 2006 Josef Cejka
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/**
30 * @addtogroup kbdgen generic
31 * @brief HelenOS generic uspace keyboard handler.
32 * @ingroup kbd
33 * @{
34 */
35/** @file
36 */
37
38#include <ipc/services.h>
39#include <ipc/kbd.h>
40#include <sysinfo.h>
41#include <stdio.h>
42#include <unistd.h>
43#include <stdlib.h>
44#include <stdio.h>
45#include <ns.h>
46#include <ns_obsolete.h>
47#include <async.h>
48#include <async_obsolete.h>
49#include <errno.h>
50#include <adt/fifo.h>
51#include <io/console.h>
52#include <io/keycode.h>
53#include <devmap.h>
54#include <kbd.h>
55#include <kbd_port.h>
56#include <kbd_ctl.h>
57#include <layout.h>
58
59// FIXME: remove this header
60#include <kernel/ipc/ipc_methods.h>
61
62#define NAME "kbd"
63#define NAMESPACE "hid_in"
64
65int client_phone = -1;
66
67/** Currently active modifiers. */
68static unsigned mods = KM_NUM_LOCK;
69
70/** Currently pressed lock keys. We track these to tackle autorepeat. */
71static unsigned lock_keys;
72
73static kbd_port_ops_t *kbd_port;
74
75bool irc_service = false;
76int irc_phone = -1;
77
78#define NUM_LAYOUTS 3
79
80static layout_op_t *layout[NUM_LAYOUTS] = {
81 &us_qwerty_op,
82 &us_dvorak_op,
83 &cz_op
84};
85
86static int active_layout = 0;
87
88void kbd_push_scancode(int scancode)
89{
90/* printf("scancode: 0x%x\n", scancode);*/
91 kbd_ctl_parse_scancode(scancode);
92}
93
94void kbd_push_ev(int type, unsigned int key)
95{
96 kbd_event_t ev;
97 unsigned mod_mask;
98
99 switch (key) {
100 case KC_LCTRL: mod_mask = KM_LCTRL; break;
101 case KC_RCTRL: mod_mask = KM_RCTRL; break;
102 case KC_LSHIFT: mod_mask = KM_LSHIFT; break;
103 case KC_RSHIFT: mod_mask = KM_RSHIFT; break;
104 case KC_LALT: mod_mask = KM_LALT; break;
105 case KC_RALT: mod_mask = KM_RALT; break;
106 default: mod_mask = 0; break;
107 }
108
109 if (mod_mask != 0) {
110 if (type == KEY_PRESS)
111 mods = mods | mod_mask;
112 else
113 mods = mods & ~mod_mask;
114 }
115
116 switch (key) {
117 case KC_CAPS_LOCK: mod_mask = KM_CAPS_LOCK; break;
118 case KC_NUM_LOCK: mod_mask = KM_NUM_LOCK; break;
119 case KC_SCROLL_LOCK: mod_mask = KM_SCROLL_LOCK; break;
120 default: mod_mask = 0; break;
121 }
122
123 if (mod_mask != 0) {
124 if (type == KEY_PRESS) {
125 /*
126 * Only change lock state on transition from released
127 * to pressed. This prevents autorepeat from messing
128 * up the lock state.
129 */
130 mods = mods ^ (mod_mask & ~lock_keys);
131 lock_keys = lock_keys | mod_mask;
132
133 /* Update keyboard lock indicator lights. */
134 kbd_ctl_set_ind(mods);
135 } else {
136 lock_keys = lock_keys & ~mod_mask;
137 }
138 }
139/*
140 printf("type: %d\n", type);
141 printf("mods: 0x%x\n", mods);
142 printf("keycode: %u\n", key);
143*/
144 if (type == KEY_PRESS && (mods & KM_LCTRL) &&
145 key == KC_F1) {
146 active_layout = 0;
147 layout[active_layout]->reset();
148 return;
149 }
150
151 if (type == KEY_PRESS && (mods & KM_LCTRL) &&
152 key == KC_F2) {
153 active_layout = 1;
154 layout[active_layout]->reset();
155 return;
156 }
157
158 if (type == KEY_PRESS && (mods & KM_LCTRL) &&
159 key == KC_F3) {
160 active_layout = 2;
161 layout[active_layout]->reset();
162 return;
163 }
164
165 ev.type = type;
166 ev.key = key;
167 ev.mods = mods;
168
169 ev.c = layout[active_layout]->parse_ev(&ev);
170
171 async_obsolete_msg_4(client_phone, KBD_EVENT, ev.type, ev.key, ev.mods, ev.c);
172}
173
174static void client_connection(ipc_callid_t iid, ipc_call_t *icall)
175{
176 ipc_callid_t callid;
177 ipc_call_t call;
178 int retval;
179
180 async_answer_0(iid, EOK);
181
182 while (true) {
183 callid = async_get_call(&call);
184
185 if (!IPC_GET_IMETHOD(call)) {
186 if (client_phone != -1) {
187 async_obsolete_hangup(client_phone);
188 client_phone = -1;
189 }
190
191 async_answer_0(callid, EOK);
192 return;
193 }
194
195 switch (IPC_GET_IMETHOD(call)) {
196 case IPC_M_CONNECT_TO_ME:
197 if (client_phone != -1) {
198 retval = ELIMIT;
199 break;
200 }
201 client_phone = IPC_GET_ARG5(call);
202 retval = 0;
203 break;
204 case KBD_YIELD:
205 (*kbd_port->yield)();
206 retval = 0;
207 break;
208 case KBD_RECLAIM:
209 (*kbd_port->reclaim)();
210 retval = 0;
211 break;
212 default:
213 retval = EINVAL;
214 }
215 async_answer_0(callid, retval);
216 }
217}
218
219static kbd_port_ops_t *kbd_select_port(void)
220{
221 kbd_port_ops_t *kbd_port;
222
223#if defined(UARCH_amd64)
224 kbd_port = &chardev_port;
225#elif defined(UARCH_arm32) && defined(MACHINE_gta02)
226 kbd_port = &chardev_port;
227#elif defined(UARCH_arm32) && defined(MACHINE_testarm)
228 kbd_port = &gxemul_port;
229#elif defined(UARCH_arm32) && defined(MACHINE_integratorcp)
230 kbd_port = &pl050_port;
231#elif defined(UARCH_ia32)
232 kbd_port = &chardev_port;
233#elif defined(MACHINE_i460GX)
234 kbd_port = &chardev_port;
235#elif defined(MACHINE_ski)
236 kbd_port = &ski_port;
237#elif defined(MACHINE_msim)
238 kbd_port = &msim_port;
239#elif defined(MACHINE_lgxemul) || defined(MACHINE_bgxemul)
240 kbd_port = &gxemul_port;
241#elif defined(UARCH_ppc32)
242 kbd_port = &adb_port;
243#elif defined(UARCH_sparc64) && defined(PROCESSOR_sun4v)
244 kbd_port = &niagara_port;
245#elif defined(UARCH_sparc64) && defined(MACHINE_serengeti)
246 kbd_port = &sgcn_port;
247#elif defined(UARCH_sparc64) && defined(MACHINE_generic)
248 kbd_port = &sun_port;
249#else
250 kbd_port = &dummy_port;
251#endif
252 return kbd_port;
253}
254
255int main(int argc, char **argv)
256{
257 printf("%s: HelenOS Keyboard service\n", NAME);
258
259 sysarg_t fhc;
260 sysarg_t obio;
261
262 if (((sysinfo_get_value("kbd.cir.fhc", &fhc) == EOK) && (fhc))
263 || ((sysinfo_get_value("kbd.cir.obio", &obio) == EOK) && (obio)))
264 irc_service = true;
265
266 if (irc_service) {
267 while (irc_phone < 0)
268 irc_phone = service_obsolete_connect_blocking(SERVICE_IRC, 0, 0);
269 }
270
271 /* Select port driver. */
272 kbd_port = kbd_select_port();
273
274 /* Initialize port driver. */
275 if ((*kbd_port->init)() != 0)
276 return -1;
277
278 /* Initialize controller driver. */
279 if (kbd_ctl_init(kbd_port) != 0)
280 return -1;
281
282 /* Initialize (reset) layout. */
283 layout[active_layout]->reset();
284
285 /* Register driver */
286 int rc = devmap_driver_register(NAME, client_connection);
287 if (rc < 0) {
288 printf("%s: Unable to register driver (%d)\n", NAME, rc);
289 return -1;
290 }
291
292 char kbd[DEVMAP_NAME_MAXLEN + 1];
293 snprintf(kbd, DEVMAP_NAME_MAXLEN, "%s/%s", NAMESPACE, NAME);
294
295 devmap_handle_t devmap_handle;
296 if (devmap_device_register(kbd, &devmap_handle) != EOK) {
297 printf("%s: Unable to register device %s\n", NAME, kbd);
298 return -1;
299 }
300
301 printf(NAME ": Accepting connections\n");
302 async_manager();
303
304 /* Not reached. */
305 return 0;
306}
307
308/**
309 * @}
310 */
Note: See TracBrowser for help on using the repository browser.