1706f2543Smrg/*
2706f2543Smrg * Copyright � 1999 Keith Packard
3706f2543Smrg * XKB integration � 2006 Nokia Corporation, author: Tomas Frydrych <tf@o-hand.com>
4706f2543Smrg *
5706f2543Smrg * LinuxKeyboardRead() XKB code based on xf86KbdLnx.c:
6706f2543Smrg * Copyright � 1990,91 by Thomas Roell, Dinkelscherben, Germany.
7706f2543Smrg * Copyright � 1994-2001 by The XFree86 Project, Inc.
8706f2543Smrg *
9706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a
10706f2543Smrg * copy of this software and associated documentation files (the "Software"),
11706f2543Smrg * to deal in the Software without restriction, including without limitation
12706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the
14706f2543Smrg * Software is furnished to do so, subject to the following conditions:
15706f2543Smrg *
16706f2543Smrg * The above copyright notice and this permission notice shall be included in
17706f2543Smrg * all copies or substantial portions of the Software.
18706f2543Smrg *
19706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22706f2543Smrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
23706f2543Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24706f2543Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25706f2543Smrg * OTHER DEALINGS IN THE SOFTWARE.
26706f2543Smrg *
27706f2543Smrg * Except as contained in this notice, the name of the copyright holder(s)
28706f2543Smrg * and author(s) shall not be used in advertising or otherwise to promote
29706f2543Smrg * the sale, use or other dealings in this Software without prior written
30706f2543Smrg * authorization from the copyright holder(s) and author(s).
31706f2543Smrg */
32706f2543Smrg
33706f2543Smrg#ifdef HAVE_CONFIG_H
34706f2543Smrg#include <kdrive-config.h>
35706f2543Smrg#endif
36706f2543Smrg#include "kdrive.h"
37706f2543Smrg#include <linux/keyboard.h>
38706f2543Smrg#include <linux/kd.h>
39706f2543Smrg#define XK_PUBLISHING
40706f2543Smrg#include <X11/keysym.h>
41706f2543Smrg#include <termios.h>
42706f2543Smrg#include <sys/ioctl.h>
43706f2543Smrg
44706f2543Smrgextern int LinuxConsoleFd;
45706f2543Smrg
46706f2543Smrgstatic const KeySym linux_to_x[256] = {
47706f2543Smrg	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
48706f2543Smrg	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
49706f2543Smrg	XK_BackSpace,	XK_Tab,		XK_Linefeed,	NoSymbol,
50706f2543Smrg	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
51706f2543Smrg	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
52706f2543Smrg	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
53706f2543Smrg	NoSymbol,	NoSymbol,	NoSymbol,	XK_Escape,
54706f2543Smrg	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
55706f2543Smrg	XK_space,	XK_exclam,	XK_quotedbl,	XK_numbersign,
56706f2543Smrg	XK_dollar,	XK_percent,	XK_ampersand,	XK_apostrophe,
57706f2543Smrg	XK_parenleft,	XK_parenright,	XK_asterisk,	XK_plus,
58706f2543Smrg	XK_comma,	XK_minus,	XK_period,	XK_slash,
59706f2543Smrg	XK_0,		XK_1,		XK_2,		XK_3,
60706f2543Smrg	XK_4,		XK_5,		XK_6,		XK_7,
61706f2543Smrg	XK_8,		XK_9,		XK_colon,	XK_semicolon,
62706f2543Smrg	XK_less,	XK_equal,	XK_greater,	XK_question,
63706f2543Smrg	XK_at,		XK_A,		XK_B,		XK_C,
64706f2543Smrg	XK_D,		XK_E,		XK_F,		XK_G,
65706f2543Smrg	XK_H,		XK_I,		XK_J,		XK_K,
66706f2543Smrg	XK_L,		XK_M,		XK_N,		XK_O,
67706f2543Smrg	XK_P,		XK_Q,		XK_R,		XK_S,
68706f2543Smrg	XK_T,		XK_U,		XK_V,		XK_W,
69706f2543Smrg	XK_X,		XK_Y,		XK_Z,		XK_bracketleft,
70706f2543Smrg	XK_backslash,	XK_bracketright,XK_asciicircum,	XK_underscore,
71706f2543Smrg	XK_grave,	XK_a,		XK_b,		XK_c,
72706f2543Smrg	XK_d,		XK_e,		XK_f,		XK_g,
73706f2543Smrg	XK_h,		XK_i,		XK_j,		XK_k,
74706f2543Smrg	XK_l,		XK_m,		XK_n,		XK_o,
75706f2543Smrg	XK_p,		XK_q,		XK_r,		XK_s,
76706f2543Smrg	XK_t,		XK_u,		XK_v,		XK_w,
77706f2543Smrg	XK_x,		XK_y,		XK_z,		XK_braceleft,
78706f2543Smrg	XK_bar,		XK_braceright,	XK_asciitilde,	XK_BackSpace,
79706f2543Smrg	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
80706f2543Smrg	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
81706f2543Smrg	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
82706f2543Smrg	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
83706f2543Smrg	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
84706f2543Smrg	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
85706f2543Smrg	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
86706f2543Smrg	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
87706f2543Smrg	XK_nobreakspace,XK_exclamdown,	XK_cent,	XK_sterling,
88706f2543Smrg	XK_currency,	XK_yen,		XK_brokenbar,	XK_section,
89706f2543Smrg	XK_diaeresis,	XK_copyright,	XK_ordfeminine,	XK_guillemotleft,
90706f2543Smrg	XK_notsign,	XK_hyphen,	XK_registered,	XK_macron,
91706f2543Smrg	XK_degree,	XK_plusminus,	XK_twosuperior,	XK_threesuperior,
92706f2543Smrg	XK_acute,	XK_mu,		XK_paragraph,	XK_periodcentered,
93706f2543Smrg	XK_cedilla,	XK_onesuperior,	XK_masculine,	XK_guillemotright,
94706f2543Smrg	XK_onequarter,	XK_onehalf,	XK_threequarters,XK_questiondown,
95706f2543Smrg	XK_Agrave,	XK_Aacute,	XK_Acircumflex,	XK_Atilde,
96706f2543Smrg	XK_Adiaeresis,	XK_Aring,	XK_AE,		XK_Ccedilla,
97706f2543Smrg	XK_Egrave,	XK_Eacute,	XK_Ecircumflex,	XK_Ediaeresis,
98706f2543Smrg	XK_Igrave,	XK_Iacute,	XK_Icircumflex,	XK_Idiaeresis,
99706f2543Smrg	XK_ETH,		XK_Ntilde,	XK_Ograve,	XK_Oacute,
100706f2543Smrg	XK_Ocircumflex,	XK_Otilde,	XK_Odiaeresis,	XK_multiply,
101706f2543Smrg	XK_Ooblique,	XK_Ugrave,	XK_Uacute,	XK_Ucircumflex,
102706f2543Smrg	XK_Udiaeresis,	XK_Yacute,	XK_THORN,	XK_ssharp,
103706f2543Smrg	XK_agrave,	XK_aacute,	XK_acircumflex,	XK_atilde,
104706f2543Smrg	XK_adiaeresis,	XK_aring,	XK_ae,		XK_ccedilla,
105706f2543Smrg	XK_egrave,	XK_eacute,	XK_ecircumflex,	XK_ediaeresis,
106706f2543Smrg	XK_igrave,	XK_iacute,	XK_icircumflex,	XK_idiaeresis,
107706f2543Smrg	XK_eth,		XK_ntilde,	XK_ograve,	XK_oacute,
108706f2543Smrg	XK_ocircumflex,	XK_otilde,	XK_odiaeresis,	XK_division,
109706f2543Smrg	XK_oslash,	XK_ugrave,	XK_uacute,	XK_ucircumflex,
110706f2543Smrg	XK_udiaeresis,	XK_yacute,	XK_thorn,	XK_ydiaeresis
111706f2543Smrg};
112706f2543Smrg
113706f2543Smrg/*
114706f2543Smrg * Getting a keycode from scancode
115706f2543Smrg *
116706f2543Smrg * With XKB
117706f2543Smrg * --------
118706f2543Smrg *
119706f2543Smrg * We have to enqueue keyboard events using standard X keycodes which correspond
120706f2543Smrg * to AT scancode + 8; this means that we need to translate the Linux scancode
121706f2543Smrg * provided by the kernel to an AT scancode -- this translation is not linear
122706f2543Smrg * and requires that we use a LUT.
123706f2543Smrg *
124706f2543Smrg *
125706f2543Smrg * Without XKB
126706f2543Smrg * -----------
127706f2543Smrg *
128706f2543Smrg * We can use custom keycodes, which makes things simpler; we define our custom
129706f2543Smrg * keycodes as Linux scancodes + KD_KEY_OFFSET
130706f2543Smrg*/
131706f2543Smrg
132706f2543Smrg/*
133706f2543Smrg   This LUT translates AT scancodes into Linux ones -- the keymap we create
134706f2543Smrg   for the core X keyboard protocol has to be AT-scancode based so that it
135706f2543Smrg   corresponds to the Xkb keymap.
136706f2543Smrg*/
137706f2543Smrg#if 0
138706f2543Smrgstatic unsigned char at2lnx[] =
139706f2543Smrg{
140706f2543Smrg	0x0,    /* no valid scancode */
141706f2543Smrg	0x01,	/* KEY_Escape */	0x02,	/* KEY_1 */
142706f2543Smrg	0x03,	/* KEY_2 */		0x04,	/* KEY_3 */
143706f2543Smrg	0x05,	/* KEY_4 */		0x06,	/* KEY_5 */
144706f2543Smrg	0x07,	/* KEY_6 */		0x08,	/* KEY_7 */
145706f2543Smrg	0x09,	/* KEY_8 */		0x0a,	/* KEY_9 */
146706f2543Smrg	0x0b,	/* KEY_0 */		0x0c,	/* KEY_Minus */
147706f2543Smrg	0x0d,	/* KEY_Equal */		0x0e,	/* KEY_BackSpace */
148706f2543Smrg	0x0f,	/* KEY_Tab */		0x10,	/* KEY_Q */
149706f2543Smrg	0x11,	/* KEY_W */		0x12,	/* KEY_E */
150706f2543Smrg	0x13,	/* KEY_R */		0x14,	/* KEY_T */
151706f2543Smrg	0x15,	/* KEY_Y */		0x16,	/* KEY_U */
152706f2543Smrg	0x17,	/* KEY_I */		0x18,	/* KEY_O */
153706f2543Smrg	0x19,	/* KEY_P */		0x1a,	/* KEY_LBrace */
154706f2543Smrg	0x1b,	/* KEY_RBrace */	0x1c,	/* KEY_Enter */
155706f2543Smrg	0x1d,	/* KEY_LCtrl */		0x1e,	/* KEY_A */
156706f2543Smrg	0x1f,	/* KEY_S */		0x20,	/* KEY_D */
157706f2543Smrg	0x21,	/* KEY_F */		0x22,	/* KEY_G */
158706f2543Smrg	0x23,	/* KEY_H */		0x24,	/* KEY_J */
159706f2543Smrg	0x25,	/* KEY_K */		0x26,	/* KEY_L */
160706f2543Smrg	0x27,	/* KEY_SemiColon */	0x28,	/* KEY_Quote */
161706f2543Smrg	0x29,	/* KEY_Tilde */		0x2a,	/* KEY_ShiftL */
162706f2543Smrg	0x2b,	/* KEY_BSlash */	0x2c,	/* KEY_Z */
163706f2543Smrg	0x2d,	/* KEY_X */		0x2e,	/* KEY_C */
164706f2543Smrg	0x2f,	/* KEY_V */		0x30,	/* KEY_B */
165706f2543Smrg	0x31,	/* KEY_N */		0x32,	/* KEY_M */
166706f2543Smrg	0x33,	/* KEY_Comma */		0x34,	/* KEY_Period */
167706f2543Smrg	0x35,	/* KEY_Slash */		0x36,	/* KEY_ShiftR */
168706f2543Smrg	0x37,	/* KEY_KP_Multiply */	0x38,	/* KEY_Alt */
169706f2543Smrg	0x39,	/* KEY_Space */		0x3a,	/* KEY_CapsLock */
170706f2543Smrg	0x3b,	/* KEY_F1 */		0x3c,	/* KEY_F2 */
171706f2543Smrg	0x3d,	/* KEY_F3 */		0x3e,	/* KEY_F4 */
172706f2543Smrg	0x3f,	/* KEY_F5 */		0x40,	/* KEY_F6 */
173706f2543Smrg	0x41,	/* KEY_F7 */		0x42,	/* KEY_F8 */
174706f2543Smrg	0x43,	/* KEY_F9 */		0x44,	/* KEY_F10 */
175706f2543Smrg	0x45,	/* KEY_NumLock */	0x46,	/* KEY_ScrollLock */
176706f2543Smrg	0x47,	/* KEY_KP_7 */		0x48,	/* KEY_KP_8 */
177706f2543Smrg	0x49,	/* KEY_KP_9 */		0x4a,	/* KEY_KP_Minus */
178706f2543Smrg	0x4b,	/* KEY_KP_4 */		0x4c,	/* KEY_KP_5 */
179706f2543Smrg	0x4d,	/* KEY_KP_6 */		0x4e,	/* KEY_KP_Plus */
180706f2543Smrg	0x4f,	/* KEY_KP_1 */		0x50,	/* KEY_KP_2 */
181706f2543Smrg	0x51,	/* KEY_KP_3 */		0x52,	/* KEY_KP_0 */
182706f2543Smrg	0x53,	/* KEY_KP_Decimal */	0x54,	/* KEY_SysReqest */
183706f2543Smrg	0x00,	/* 0x55 */		0x56,	/* KEY_Less */
184706f2543Smrg	0x57,	/* KEY_F11 */		0x58,	/* KEY_F12 */
185706f2543Smrg	0x66,	/* KEY_Home */		0x67,	/* KEY_Up */
186706f2543Smrg	0x68,	/* KEY_PgUp */		0x69,	/* KEY_Left */
187706f2543Smrg	0x5d,	/* KEY_Begin */		0x6a,	/* KEY_Right */
188706f2543Smrg	0x6b,	/* KEY_End */		0x6c,	/* KEY_Down */
189706f2543Smrg	0x6d,	/* KEY_PgDown */	0x6e,	/* KEY_Insert */
190706f2543Smrg	0x6f,	/* KEY_Delete */	0x60,	/* KEY_KP_Enter */
191706f2543Smrg	0x61,	/* KEY_RCtrl */		0x77,	/* KEY_Pause */
192706f2543Smrg	0x63,	/* KEY_Print */		0x62,	/* KEY_KP_Divide */
193706f2543Smrg	0x64,	/* KEY_AltLang */	0x65,	/* KEY_Break */
194706f2543Smrg	0x00,	/* KEY_LMeta */		0x00,	/* KEY_RMeta */
195706f2543Smrg	0x7A,	/* KEY_Menu/FOCUS_PF11*/0x00,	/* 0x6e */
196706f2543Smrg	0x7B,	/* FOCUS_PF12 */	0x00,	/* 0x70 */
197706f2543Smrg	0x00,	/* 0x71 */		0x00,	/* 0x72 */
198706f2543Smrg	0x59,	/* FOCUS_PF2 */		0x78,	/* FOCUS_PF9 */
199706f2543Smrg	0x00,	/* 0x75 */		0x00,	/* 0x76 */
200706f2543Smrg	0x5A,	/* FOCUS_PF3 */		0x5B,	/* FOCUS_PF4 */
201706f2543Smrg	0x5C,	/* FOCUS_PF5 */		0x5D,	/* FOCUS_PF6 */
202706f2543Smrg	0x5E,	/* FOCUS_PF7 */		0x5F,	/* FOCUS_PF8 */
203706f2543Smrg	0x7C,	/* JAP_86 */		0x79,	/* FOCUS_PF10 */
204706f2543Smrg	0x00,	/* 0x7f */
205706f2543Smrg};
206706f2543Smrg
207706f2543Smrg#define NUM_AT_KEYS (sizeof(at2lnx)/sizeof(at2lnx[0]))
208706f2543Smrg#define LNX_KEY_INDEX(n) n < NUM_AT_KEYS ? at2lnx[n] : 0
209706f2543Smrg
210706f2543Smrgstatic unsigned char tbl[KD_MAX_WIDTH] =
211706f2543Smrg{
212706f2543Smrg    0,
213706f2543Smrg    1 << KG_SHIFT,
214706f2543Smrg    (1 << KG_ALTGR),
215706f2543Smrg    (1 << KG_ALTGR) | (1 << KG_SHIFT)
216706f2543Smrg};
217706f2543Smrg#endif
218706f2543Smrg
219706f2543Smrgstatic void
220706f2543SmrgreadKernelMapping(KdKeyboardInfo *ki)
221706f2543Smrg{
222706f2543Smrg#if 0
223706f2543Smrg    KeySym	    *k;
224706f2543Smrg    int		    i, j;
225706f2543Smrg    struct kbentry  kbe;
226706f2543Smrg    int		    minKeyCode, maxKeyCode;
227706f2543Smrg    int		    row;
228706f2543Smrg    int             fd;
229706f2543Smrg
230706f2543Smrg    if (!ki)
231706f2543Smrg        return;
232706f2543Smrg
233706f2543Smrg    fd = LinuxConsoleFd;
234706f2543Smrg
235706f2543Smrg    minKeyCode = NR_KEYS;
236706f2543Smrg    maxKeyCode = 0;
237706f2543Smrg    row = 0;
238706f2543Smrg    ki->keySyms.mapWidth = KD_MAX_WIDTH;
239706f2543Smrg    for (i = 0; i < NR_KEYS && row < KD_MAX_LENGTH; ++i)
240706f2543Smrg    {
241706f2543Smrg        kbe.kb_index = LNX_KEY_INDEX(i);
242706f2543Smrg
243706f2543Smrg        k = ki->keySyms.map + row * ki->keySyms.mapWidth;
244706f2543Smrg
245706f2543Smrg	for (j = 0; j < ki->keySyms.mapWidth; ++j)
246706f2543Smrg	{
247706f2543Smrg	    unsigned short kval;
248706f2543Smrg
249706f2543Smrg	    k[j] = NoSymbol;
250706f2543Smrg
251706f2543Smrg	    kbe.kb_table = tbl[j];
252706f2543Smrg	    kbe.kb_value = 0;
253706f2543Smrg	    if (ioctl(fd, KDGKBENT, &kbe))
254706f2543Smrg		continue;
255706f2543Smrg
256706f2543Smrg	    kval = KVAL(kbe.kb_value);
257706f2543Smrg	    switch (KTYP(kbe.kb_value))
258706f2543Smrg	    {
259706f2543Smrg	    case KT_LATIN:
260706f2543Smrg	    case KT_LETTER:
261706f2543Smrg		k[j] = linux_to_x[kval];
262706f2543Smrg		break;
263706f2543Smrg
264706f2543Smrg	    case KT_FN:
265706f2543Smrg		if (kval <= 19)
266706f2543Smrg		    k[j] = XK_F1 + kval;
267706f2543Smrg		else switch (kbe.kb_value)
268706f2543Smrg		{
269706f2543Smrg		case K_FIND:
270706f2543Smrg		    k[j] = XK_Home; /* or XK_Find */
271706f2543Smrg		    break;
272706f2543Smrg		case K_INSERT:
273706f2543Smrg		    k[j] = XK_Insert;
274706f2543Smrg		    break;
275706f2543Smrg		case K_REMOVE:
276706f2543Smrg		    k[j] = XK_Delete;
277706f2543Smrg		    break;
278706f2543Smrg		case K_SELECT:
279706f2543Smrg		    k[j] = XK_End; /* or XK_Select */
280706f2543Smrg		    break;
281706f2543Smrg		case K_PGUP:
282706f2543Smrg		    k[j] = XK_Prior;
283706f2543Smrg		    break;
284706f2543Smrg		case K_PGDN:
285706f2543Smrg		    k[j] = XK_Next;
286706f2543Smrg		    break;
287706f2543Smrg		case K_HELP:
288706f2543Smrg		    k[j] = XK_Help;
289706f2543Smrg		    break;
290706f2543Smrg		case K_DO:
291706f2543Smrg		    k[j] = XK_Execute;
292706f2543Smrg		    break;
293706f2543Smrg		case K_PAUSE:
294706f2543Smrg		    k[j] = XK_Pause;
295706f2543Smrg		    break;
296706f2543Smrg		case K_MACRO:
297706f2543Smrg		    k[j] = XK_Menu;
298706f2543Smrg		    break;
299706f2543Smrg		default:
300706f2543Smrg		    break;
301706f2543Smrg		}
302706f2543Smrg		break;
303706f2543Smrg
304706f2543Smrg	    case KT_SPEC:
305706f2543Smrg		switch (kbe.kb_value)
306706f2543Smrg		{
307706f2543Smrg		case K_ENTER:
308706f2543Smrg		    k[j] = XK_Return;
309706f2543Smrg		    break;
310706f2543Smrg		case K_BREAK:
311706f2543Smrg		    k[j] = XK_Break;
312706f2543Smrg		    break;
313706f2543Smrg		case K_CAPS:
314706f2543Smrg		    k[j] = XK_Caps_Lock;
315706f2543Smrg		    break;
316706f2543Smrg		case K_NUM:
317706f2543Smrg		    k[j] = XK_Num_Lock;
318706f2543Smrg		    break;
319706f2543Smrg		case K_HOLD:
320706f2543Smrg		    k[j] = XK_Scroll_Lock;
321706f2543Smrg		    break;
322706f2543Smrg		case K_COMPOSE:
323706f2543Smrg		    k[j] = XK_Multi_key;
324706f2543Smrg		    break;
325706f2543Smrg		default:
326706f2543Smrg		    break;
327706f2543Smrg		}
328706f2543Smrg		break;
329706f2543Smrg
330706f2543Smrg	    case KT_PAD:
331706f2543Smrg		switch (kbe.kb_value)
332706f2543Smrg		{
333706f2543Smrg		case K_PPLUS:
334706f2543Smrg		    k[j] = XK_KP_Add;
335706f2543Smrg		    break;
336706f2543Smrg		case K_PMINUS:
337706f2543Smrg		    k[j] = XK_KP_Subtract;
338706f2543Smrg		    break;
339706f2543Smrg		case K_PSTAR:
340706f2543Smrg		    k[j] = XK_KP_Multiply;
341706f2543Smrg		    break;
342706f2543Smrg		case K_PSLASH:
343706f2543Smrg		    k[j] = XK_KP_Divide;
344706f2543Smrg		    break;
345706f2543Smrg		case K_PENTER:
346706f2543Smrg		    k[j] = XK_KP_Enter;
347706f2543Smrg		    break;
348706f2543Smrg		case K_PCOMMA:
349706f2543Smrg		    k[j] = XK_KP_Separator;
350706f2543Smrg		    break;
351706f2543Smrg		case K_PDOT:
352706f2543Smrg		    k[j] = XK_KP_Decimal;
353706f2543Smrg		    break;
354706f2543Smrg		case K_PPLUSMINUS:
355706f2543Smrg		    k[j] = XK_KP_Subtract;
356706f2543Smrg		    break;
357706f2543Smrg		default:
358706f2543Smrg		    if (kval <= 9)
359706f2543Smrg			k[j] = XK_KP_0 + kval;
360706f2543Smrg		    break;
361706f2543Smrg		}
362706f2543Smrg		break;
363706f2543Smrg
364706f2543Smrg		/*
365706f2543Smrg		 * KT_DEAD keys are for accelerated diacritical creation.
366706f2543Smrg		 */
367706f2543Smrg	    case KT_DEAD:
368706f2543Smrg		switch (kbe.kb_value)
369706f2543Smrg		{
370706f2543Smrg		case K_DGRAVE:
371706f2543Smrg		    k[j] = XK_dead_grave;
372706f2543Smrg		    break;
373706f2543Smrg		case K_DACUTE:
374706f2543Smrg		    k[j] = XK_dead_acute;
375706f2543Smrg		    break;
376706f2543Smrg		case K_DCIRCM:
377706f2543Smrg		    k[j] = XK_dead_circumflex;
378706f2543Smrg		    break;
379706f2543Smrg		case K_DTILDE:
380706f2543Smrg		    k[j] = XK_dead_tilde;
381706f2543Smrg		    break;
382706f2543Smrg		case K_DDIERE:
383706f2543Smrg		    k[j] = XK_dead_diaeresis;
384706f2543Smrg		    break;
385706f2543Smrg		}
386706f2543Smrg		break;
387706f2543Smrg
388706f2543Smrg	    case KT_CUR:
389706f2543Smrg		switch (kbe.kb_value)
390706f2543Smrg		{
391706f2543Smrg		case K_DOWN:
392706f2543Smrg		    k[j] = XK_Down;
393706f2543Smrg		    break;
394706f2543Smrg		case K_LEFT:
395706f2543Smrg		    k[j] = XK_Left;
396706f2543Smrg		    break;
397706f2543Smrg		case K_RIGHT:
398706f2543Smrg		    k[j] = XK_Right;
399706f2543Smrg		    break;
400706f2543Smrg		case K_UP:
401706f2543Smrg		    k[j] = XK_Up;
402706f2543Smrg		    break;
403706f2543Smrg		}
404706f2543Smrg		break;
405706f2543Smrg
406706f2543Smrg	    case KT_SHIFT:
407706f2543Smrg		switch (kbe.kb_value)
408706f2543Smrg		{
409706f2543Smrg		case K_ALTGR:
410706f2543Smrg		    k[j] = XK_Mode_switch;
411706f2543Smrg		    break;
412706f2543Smrg		case K_ALT:
413706f2543Smrg		    k[j] = (kbe.kb_index == 0x64 ?
414706f2543Smrg			  XK_Alt_R : XK_Alt_L);
415706f2543Smrg		    break;
416706f2543Smrg		case K_CTRL:
417706f2543Smrg		    k[j] = (kbe.kb_index == 0x61 ?
418706f2543Smrg			  XK_Control_R : XK_Control_L);
419706f2543Smrg		    break;
420706f2543Smrg		case K_CTRLL:
421706f2543Smrg		    k[j] = XK_Control_L;
422706f2543Smrg		    break;
423706f2543Smrg		case K_CTRLR:
424706f2543Smrg		    k[j] = XK_Control_R;
425706f2543Smrg		    break;
426706f2543Smrg		case K_SHIFT:
427706f2543Smrg		    k[j] = (kbe.kb_index == 0x36 ?
428706f2543Smrg			  XK_Shift_R : XK_Shift_L);
429706f2543Smrg		    break;
430706f2543Smrg		case K_SHIFTL:
431706f2543Smrg		    k[j] = XK_Shift_L;
432706f2543Smrg		    break;
433706f2543Smrg		case K_SHIFTR:
434706f2543Smrg		    k[j] = XK_Shift_R;
435706f2543Smrg		    break;
436706f2543Smrg		default:
437706f2543Smrg		    break;
438706f2543Smrg		}
439706f2543Smrg		break;
440706f2543Smrg
441706f2543Smrg		/*
442706f2543Smrg		 * KT_ASCII keys accumulate a 3 digit decimal number that gets
443706f2543Smrg		 * emitted when the shift state changes. We can't emulate that.
444706f2543Smrg		 */
445706f2543Smrg	    case KT_ASCII:
446706f2543Smrg		break;
447706f2543Smrg
448706f2543Smrg	    case KT_LOCK:
449706f2543Smrg		if (kbe.kb_value == K_SHIFTLOCK)
450706f2543Smrg		    k[j] = XK_Shift_Lock;
451706f2543Smrg		break;
452706f2543Smrg
453706f2543Smrg#ifdef KT_X
454706f2543Smrg	    case KT_X:
455706f2543Smrg		/* depends on new keyboard symbols in file linux/keyboard.h */
456706f2543Smrg		if(kbe.kb_value == K_XMENU) k[j] = XK_Menu;
457706f2543Smrg		if(kbe.kb_value == K_XTELEPHONE) k[j] = XK_telephone;
458706f2543Smrg		break;
459706f2543Smrg#endif
460706f2543Smrg#ifdef KT_XF
461706f2543Smrg	    case KT_XF:
462706f2543Smrg		/* special linux keysyms which map directly to XF86 keysyms */
463706f2543Smrg		k[j] = (kbe.kb_value & 0xFF) + 0x1008FF00;
464706f2543Smrg		break;
465706f2543Smrg#endif
466706f2543Smrg
467706f2543Smrg	    default:
468706f2543Smrg		break;
469706f2543Smrg	    }
470706f2543Smrg	    if (i < minKeyCode)
471706f2543Smrg		minKeyCode = i;
472706f2543Smrg	    if (i > maxKeyCode)
473706f2543Smrg		maxKeyCode = i;
474706f2543Smrg	}
475706f2543Smrg
476706f2543Smrg	if (minKeyCode == NR_KEYS)
477706f2543Smrg	    continue;
478706f2543Smrg
479706f2543Smrg	if (k[3] == k[2]) k[3] = NoSymbol;
480706f2543Smrg	if (k[2] == k[1]) k[2] = NoSymbol;
481706f2543Smrg	if (k[1] == k[0]) k[1] = NoSymbol;
482706f2543Smrg	if (k[0] == k[2] && k[1] == k[3]) k[2] = k[3] = NoSymbol;
483706f2543Smrg	if (k[3] == k[0] && k[2] == k[1] && k[2] == NoSymbol) k[3] =NoSymbol;
484706f2543Smrg	row++;
485706f2543Smrg    }
486706f2543Smrg    ki->minScanCode = minKeyCode;
487706f2543Smrg    ki->maxScanCode = maxKeyCode;
488706f2543Smrg#endif
489706f2543Smrg}
490706f2543Smrg
491706f2543Smrg/*
492706f2543Smrg * We need these to handle extended scancodes correctly (I could just use the
493706f2543Smrg * numbers below, but this makes the code more readable
494706f2543Smrg */
495706f2543Smrg
496706f2543Smrg/* The prefix codes */
497706f2543Smrg#define KEY_Prefix0      /* special               0x60  */   96
498706f2543Smrg#define KEY_Prefix1      /* special               0x61  */   97
499706f2543Smrg
500706f2543Smrg/* The raw scancodes */
501706f2543Smrg#define KEY_Enter        /* Enter                 0x1c  */   28
502706f2543Smrg#define KEY_LCtrl        /* Ctrl(left)            0x1d  */   29
503706f2543Smrg#define KEY_Slash        /* / (Slash)   ?         0x35  */   53
504706f2543Smrg#define KEY_KP_Multiply  /* *                     0x37  */   55
505706f2543Smrg#define KEY_Alt          /* Alt(left)             0x38  */   56
506706f2543Smrg#define KEY_F3           /* F3                    0x3d  */   61
507706f2543Smrg#define KEY_F4           /* F4                    0x3e  */   62
508706f2543Smrg#define KEY_F5           /* F5                    0x3f  */   63
509706f2543Smrg#define KEY_F6           /* F6                    0x40  */   64
510706f2543Smrg#define KEY_F7           /* F7                    0x41  */   65
511706f2543Smrg#define KEY_ScrollLock   /* ScrollLock            0x46  */   70
512706f2543Smrg#define KEY_KP_7         /* 7           Home      0x47  */   71
513706f2543Smrg#define KEY_KP_8         /* 8           Up        0x48  */   72
514706f2543Smrg#define KEY_KP_9         /* 9           PgUp      0x49  */   73
515706f2543Smrg#define KEY_KP_Minus     /* - (Minus)             0x4a  */   74
516706f2543Smrg#define KEY_KP_4         /* 4           Left      0x4b  */   75
517706f2543Smrg#define KEY_KP_5         /* 5                     0x4c  */   76
518706f2543Smrg#define KEY_KP_6         /* 6           Right     0x4d  */   77
519706f2543Smrg#define KEY_KP_Plus      /* + (Plus)              0x4e  */   78
520706f2543Smrg#define KEY_KP_1         /* 1           End       0x4f  */   79
521706f2543Smrg#define KEY_KP_2         /* 2           Down      0x50  */   80
522706f2543Smrg#define KEY_KP_3         /* 3           PgDown    0x51  */   81
523706f2543Smrg#define KEY_KP_0         /* 0           Insert    0x52  */   82
524706f2543Smrg#define KEY_KP_Decimal   /* . (Decimal) Delete    0x53  */   83
525706f2543Smrg#define KEY_Home         /* Home                  0x59  */   89
526706f2543Smrg#define KEY_Up           /* Up                    0x5a  */   90
527706f2543Smrg#define KEY_PgUp         /* PgUp                  0x5b  */   91
528706f2543Smrg#define KEY_Left         /* Left                  0x5c  */   92
529706f2543Smrg#define KEY_Begin        /* Begin                 0x5d  */   93
530706f2543Smrg#define KEY_Right        /* Right                 0x5e  */   94
531706f2543Smrg#define KEY_End          /* End                   0x5f  */   95
532706f2543Smrg#define KEY_Down         /* Down                  0x60  */   96
533706f2543Smrg#define KEY_PgDown       /* PgDown                0x61  */   97
534706f2543Smrg#define KEY_Insert       /* Insert                0x62  */   98
535706f2543Smrg#define KEY_Delete       /* Delete                0x63  */   99
536706f2543Smrg#define KEY_KP_Enter     /* Enter                 0x64  */  100
537706f2543Smrg#define KEY_RCtrl        /* Ctrl(right)           0x65  */  101
538706f2543Smrg#define KEY_Pause        /* Pause                 0x66  */  102
539706f2543Smrg#define KEY_Print        /* Print                 0x67  */  103
540706f2543Smrg#define KEY_KP_Divide    /* Divide                0x68  */  104
541706f2543Smrg#define KEY_AltLang      /* AtlLang(right)        0x69  */  105
542706f2543Smrg#define KEY_Break        /* Break                 0x6a  */  106
543706f2543Smrg#define KEY_LMeta        /* Left Meta             0x6b  */  107
544706f2543Smrg#define KEY_RMeta        /* Right Meta            0x6c  */  108
545706f2543Smrg#define KEY_Menu         /* Menu                  0x6d  */  109
546706f2543Smrg#define KEY_F13          /* F13                   0x6e  */  110
547706f2543Smrg#define KEY_F14          /* F14                   0x6f  */  111
548706f2543Smrg#define KEY_F15          /* F15                   0x70  */  112
549706f2543Smrg#define KEY_F16          /* F16                   0x71  */  113
550706f2543Smrg#define KEY_F17          /* F17                   0x72  */  114
551706f2543Smrg#define KEY_KP_DEC       /* KP_DEC                0x73  */  115
552706f2543Smrg
553706f2543Smrgstatic void
554706f2543SmrgLinuxKeyboardRead (int fd, void *closure)
555706f2543Smrg{
556706f2543Smrg    unsigned char   buf[256], *b;
557706f2543Smrg    int		    n;
558706f2543Smrg    unsigned char   prefix = 0, scancode = 0;
559706f2543Smrg
560706f2543Smrg    while ((n = read (fd, buf, sizeof (buf))) > 0) {
561706f2543Smrg	b = buf;
562706f2543Smrg	while (n--) {
563706f2543Smrg            /*
564706f2543Smrg             * With xkb we use RAW mode for reading the console, which allows us
565706f2543Smrg             * process extended scancodes.
566706f2543Smrg             *
567706f2543Smrg             * See if this is a prefix extending the following keycode
568706f2543Smrg             */
569706f2543Smrg            if (!prefix && ((b[0] & 0x7f) == KEY_Prefix0))
570706f2543Smrg            {
571706f2543Smrg                    prefix = KEY_Prefix0;
572706f2543Smrg                    /* swallow this up */
573706f2543Smrg                    b++;
574706f2543Smrg                    continue;
575706f2543Smrg            }
576706f2543Smrg            else if (!prefix && ((b[0] & 0x7f) == KEY_Prefix1))
577706f2543Smrg            {
578706f2543Smrg                    prefix = KEY_Prefix1;
579706f2543Smrg                    /* swallow this up */
580706f2543Smrg                    b++;
581706f2543Smrg                    continue;
582706f2543Smrg            }
583706f2543Smrg            scancode = b[0] & 0x7f;
584706f2543Smrg
585706f2543Smrg            switch (prefix) {
586706f2543Smrg                    /* from xf86Events.c */
587706f2543Smrg                    case KEY_Prefix0:
588706f2543Smrg                    {
589706f2543Smrg                        switch (scancode) {
590706f2543Smrg                            case KEY_KP_7:
591706f2543Smrg                                scancode = KEY_Home;      break;  /* curs home */
592706f2543Smrg                            case KEY_KP_8:
593706f2543Smrg                                scancode = KEY_Up;        break;  /* curs up */
594706f2543Smrg                            case KEY_KP_9:
595706f2543Smrg                                scancode = KEY_PgUp;      break;  /* curs pgup */
596706f2543Smrg                            case KEY_KP_4:
597706f2543Smrg                                scancode = KEY_Left;      break;  /* curs left */
598706f2543Smrg                            case KEY_KP_5:
599706f2543Smrg                                scancode = KEY_Begin;     break;  /* curs begin */
600706f2543Smrg                            case KEY_KP_6:
601706f2543Smrg                                scancode = KEY_Right;     break;  /* curs right */
602706f2543Smrg                            case KEY_KP_1:
603706f2543Smrg                                scancode = KEY_End;       break;  /* curs end */
604706f2543Smrg                            case KEY_KP_2:
605706f2543Smrg                                scancode = KEY_Down;      break;  /* curs down */
606706f2543Smrg                            case KEY_KP_3:
607706f2543Smrg                                scancode = KEY_PgDown;    break;  /* curs pgdown */
608706f2543Smrg                            case KEY_KP_0:
609706f2543Smrg                                scancode = KEY_Insert;    break;  /* curs insert */
610706f2543Smrg                            case KEY_KP_Decimal:
611706f2543Smrg                                scancode = KEY_Delete;    break;  /* curs delete */
612706f2543Smrg                            case KEY_Enter:
613706f2543Smrg                                scancode = KEY_KP_Enter;  break;  /* keypad enter */
614706f2543Smrg                            case KEY_LCtrl:
615706f2543Smrg                                scancode = KEY_RCtrl;     break;  /* right ctrl */
616706f2543Smrg                            case KEY_KP_Multiply:
617706f2543Smrg                                scancode = KEY_Print;     break;  /* print */
618706f2543Smrg                            case KEY_Slash:
619706f2543Smrg                                scancode = KEY_KP_Divide; break;  /* keyp divide */
620706f2543Smrg                            case KEY_Alt:
621706f2543Smrg                                scancode = KEY_AltLang;   break;  /* right alt */
622706f2543Smrg                            case KEY_ScrollLock:
623706f2543Smrg                                scancode = KEY_Break;     break;  /* curs break */
624706f2543Smrg                            case 0x5b:
625706f2543Smrg                                scancode = KEY_LMeta;     break;
626706f2543Smrg                            case 0x5c:
627706f2543Smrg                                scancode = KEY_RMeta;     break;
628706f2543Smrg                            case 0x5d:
629706f2543Smrg                                scancode = KEY_Menu;      break;
630706f2543Smrg                            case KEY_F3:
631706f2543Smrg                                scancode = KEY_F13;       break;
632706f2543Smrg                            case KEY_F4:
633706f2543Smrg                                scancode = KEY_F14;       break;
634706f2543Smrg                            case KEY_F5:
635706f2543Smrg                                scancode = KEY_F15;       break;
636706f2543Smrg                            case KEY_F6:
637706f2543Smrg                                scancode = KEY_F16;       break;
638706f2543Smrg                            case KEY_F7:
639706f2543Smrg                                scancode = KEY_F17;       break;
640706f2543Smrg                            case KEY_KP_Plus:
641706f2543Smrg                                scancode = KEY_KP_DEC;    break;
642706f2543Smrg                            /* Ignore virtual shifts (E0 2A, E0 AA, E0 36, E0 B6) */
643706f2543Smrg                            case 0x2A:
644706f2543Smrg                            case 0x36:
645706f2543Smrg                                b++;
646706f2543Smrg                                prefix = 0;
647706f2543Smrg                                continue;
648706f2543Smrg                            default:
649706f2543Smrg                                 /*
650706f2543Smrg                                  * "Internet" keyboards are generating lots of new
651706f2543Smrg                                  * codes.  Let them pass.  There is little consistency
652706f2543Smrg                                  * between them, so don't bother with symbolic names at
653706f2543Smrg                                  * this level.
654706f2543Smrg                                  */
655706f2543Smrg                                scancode += 0x78;
656706f2543Smrg                        }
657706f2543Smrg                        break;
658706f2543Smrg                    }
659706f2543Smrg
660706f2543Smrg                    case KEY_Prefix1:
661706f2543Smrg                    {
662706f2543Smrg                        /* we do no handle these */
663706f2543Smrg                        b++;
664706f2543Smrg                        prefix = 0;
665706f2543Smrg                        continue;
666706f2543Smrg                    }
667706f2543Smrg
668706f2543Smrg                    default: /* should not happen*/
669706f2543Smrg                    case 0: /* do nothing */
670706f2543Smrg                        ;
671706f2543Smrg            }
672706f2543Smrg
673706f2543Smrg            prefix = 0;
674706f2543Smrg	    KdEnqueueKeyboardEvent (closure, scancode, b[0] & 0x80);
675706f2543Smrg	    b++;
676706f2543Smrg	}
677706f2543Smrg    }
678706f2543Smrg}
679706f2543Smrg
680706f2543Smrgstatic int		LinuxKbdTrans;
681706f2543Smrgstatic struct termios	LinuxTermios;
682706f2543Smrg
683706f2543Smrgstatic Status
684706f2543SmrgLinuxKeyboardEnable (KdKeyboardInfo *ki)
685706f2543Smrg{
686706f2543Smrg    struct termios nTty;
687706f2543Smrg    unsigned char   buf[256];
688706f2543Smrg    int		    n;
689706f2543Smrg    int             fd;
690706f2543Smrg
691706f2543Smrg    if (!ki)
692706f2543Smrg        return !Success;
693706f2543Smrg
694706f2543Smrg    fd = LinuxConsoleFd;
695706f2543Smrg    ki->driverPrivate = (void *) (intptr_t) fd;
696706f2543Smrg
697706f2543Smrg    ioctl (fd, KDGKBMODE, &LinuxKbdTrans);
698706f2543Smrg    tcgetattr (fd, &LinuxTermios);
699706f2543Smrg    ioctl(fd, KDSKBMODE, K_RAW);
700706f2543Smrg    nTty = LinuxTermios;
701706f2543Smrg    nTty.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP);
702706f2543Smrg    nTty.c_oflag = 0;
703706f2543Smrg    nTty.c_cflag = CREAD | CS8;
704706f2543Smrg    nTty.c_lflag = 0;
705706f2543Smrg    nTty.c_cc[VTIME]=0;
706706f2543Smrg    nTty.c_cc[VMIN]=1;
707706f2543Smrg    cfsetispeed(&nTty, 9600);
708706f2543Smrg    cfsetospeed(&nTty, 9600);
709706f2543Smrg    tcsetattr(fd, TCSANOW, &nTty);
710706f2543Smrg    /*
711706f2543Smrg     * Flush any pending keystrokes
712706f2543Smrg     */
713706f2543Smrg    while ((n = read (fd, buf, sizeof (buf))) > 0)
714706f2543Smrg	;
715706f2543Smrg    KdRegisterFd (fd, LinuxKeyboardRead, ki);
716706f2543Smrg    return Success;
717706f2543Smrg}
718706f2543Smrg
719706f2543Smrgstatic void
720706f2543SmrgLinuxKeyboardDisable (KdKeyboardInfo *ki)
721706f2543Smrg{
722706f2543Smrg    int fd;
723706f2543Smrg
724706f2543Smrg    if (!ki)
725706f2543Smrg        return;
726706f2543Smrg
727706f2543Smrg    fd = (int) (intptr_t) ki->driverPrivate;
728706f2543Smrg
729706f2543Smrg    KdUnregisterFd(ki, fd, FALSE);
730706f2543Smrg    ioctl(fd, KDSKBMODE, LinuxKbdTrans);
731706f2543Smrg    tcsetattr(fd, TCSANOW, &LinuxTermios);
732706f2543Smrg}
733706f2543Smrg
734706f2543Smrgstatic Status
735706f2543SmrgLinuxKeyboardInit (KdKeyboardInfo *ki)
736706f2543Smrg{
737706f2543Smrg    if (!ki)
738706f2543Smrg        return !Success;
739706f2543Smrg
740706f2543Smrg    free(ki->path);
741706f2543Smrg    ki->path = strdup("console");
742706f2543Smrg    free(ki->name);
743706f2543Smrg    ki->name = strdup("Linux console keyboard");
744706f2543Smrg
745706f2543Smrg    readKernelMapping (ki);
746706f2543Smrg
747706f2543Smrg    return Success;
748706f2543Smrg}
749706f2543Smrg
750706f2543Smrgstatic void
751706f2543SmrgLinuxKeyboardLeds (KdKeyboardInfo *ki, int leds)
752706f2543Smrg{
753706f2543Smrg    if (!ki)
754706f2543Smrg        return;
755706f2543Smrg
756706f2543Smrg    ioctl ((int)(intptr_t)ki->driverPrivate, KDSETLED, leds & 7);
757706f2543Smrg}
758706f2543Smrg
759706f2543SmrgKdKeyboardDriver LinuxKeyboardDriver = {
760706f2543Smrg    "keyboard",
761706f2543Smrg    .Init = LinuxKeyboardInit,
762706f2543Smrg    .Enable = LinuxKeyboardEnable,
763706f2543Smrg    .Leds = LinuxKeyboardLeds,
764706f2543Smrg    .Disable = LinuxKeyboardDisable,
765706f2543Smrg};
766