1/* Portions of this file were derived from the following files:
2 *
3 **********************************************************************
4 *
5 * xfree86/common/{xf86Io.c,xf86Kbd.c,xf86Events.c}
6 *
7 * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
8 *
9 * Permission to use, copy, modify, distribute, and sell this software and its
10 * documentation for any purpose is hereby granted without fee, provided that
11 * the above copyright notice appear in all copies and that both that
12 * copyright notice and this permission notice appear in supporting
13 * documentation, and that the name of Thomas Roell not be used in
14 * advertising or publicity pertaining to distribution of the software without
15 * specific, written prior permission.  Thomas Roell makes no representations
16 * about the suitability of this software for any purpose.  It is provided
17 * "as is" without express or implied warranty.
18 *
19 * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
20 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
21 * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
22 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
23 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
24 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
25 * PERFORMANCE OF THIS SOFTWARE.
26 *
27 **********************************************************************
28 *
29 * xfree86/common/xf86KbdLnx.c
30 *
31 * Linux version of keymapping setup. The kernel (since 0.99.14) has support
32 * for fully remapping the keyboard, but there are some differences between
33 * the Linux map and the SVR4 map (esp. in the extended keycodes). We also
34 * remove the restriction on what keycodes can be remapped.
35 * Orest Zborowski.
36 *
37 * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
38 *
39 * Permission to use, copy, modify, distribute, and sell this software and its
40 * documentation for any purpose is hereby granted without fee, provided that
41 * the above copyright notice appear in all copies and that both that
42 * copyright notice and this permission notice appear in supporting
43 * documentation, and that the name of Thomas Roell not be used in
44 * advertising or publicity pertaining to distribution of the software without
45 * specific, written prior permission.  Thomas Roell makes no representations
46 * about the suitability of this software for any purpose.  It is provided
47 * "as is" without express or implied warranty.
48 *
49 * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
50 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
51 * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
52 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
53 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
54 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
55 * PERFORMANCE OF THIS SOFTWARE.
56 *
57 **********************************************************************
58 *
59 * xfree86/os-support/linux/lnx_io.c
60 *
61 * Copyright 1992 by Orest Zborowski <obz@Kodak.com>
62 * Copyright 1993 by David Dawes <dawes@xfree86.org>
63 *
64 * Permission to use, copy, modify, distribute, and sell this software and its
65 * documentation for any purpose is hereby granted without fee, provided that
66 * the above copyright notice appear in all copies and that both that
67 * copyright notice and this permission notice appear in supporting
68 * documentation, and that the names of Orest Zborowski and David Dawes
69 * not be used in advertising or publicity pertaining to distribution of
70 * the software without specific, written prior permission.  Orest Zborowski
71 * and David Dawes make no representations about the suitability of this
72 * software for any purpose.  It is provided "as is" without express or
73 * implied warranty.
74 *
75 * OREST ZBOROWSKI AND DAVID DAWES DISCLAIMS ALL WARRANTIES WITH REGARD
76 * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
77 * FITNESS, IN NO EVENT SHALL OREST ZBOROWSKI OR DAVID DAWES BE LIABLE
78 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
79 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
80 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
81 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
82 *
83 */
84
85/*
86 * Copyright 2001-2003 Red Hat Inc., Durham, North Carolina.
87 *
88 * All Rights Reserved.
89 *
90 * Permission is hereby granted, free of charge, to any person obtaining
91 * a copy of this software and associated documentation files (the
92 * "Software"), to deal in the Software without restriction, including
93 * without limitation on the rights to use, copy, modify, merge,
94 * publish, distribute, sublicense, and/or sell copies of the Software,
95 * and to permit persons to whom the Software is furnished to do so,
96 * subject to the following conditions:
97 *
98 * The above copyright notice and this permission notice (including the
99 * next paragraph) shall be included in all copies or substantial
100 * portions of the Software.
101 *
102 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
103 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
104 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
105 * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
106 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
107 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
108 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
109 * SOFTWARE.
110 */
111
112/*
113 * Authors:
114 *   Rickard E. (Rik) Faith <faith@redhat.com>
115 *
116 */
117
118/** \file
119 *
120 * This code implements a low-level device driver for the Linux
121 * keyboard.  The code is derived from code by Thomas Roell, Orest
122 * Zborowski, and David Dawes (see the source code for complete
123 * references). */
124
125#ifdef HAVE_DMX_CONFIG_H
126#include <dmx-config.h>
127#endif
128
129/*****************************************************************************/
130/* Define some macros to make it easier to move this file to another
131 * part of the Xserver tree.  All calls to the dmx* layer are #defined
132 * here for the .c file.  The .h file will also have to be edited. */
133#include "dmxinputinit.h"
134#include "lnx-keyboard.h"
135
136#define GETPRIV       myPrivate *priv                            \
137                      = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private
138
139#define LOG0(f)       dmxLog(dmxDebug,f)
140#define LOG1(f,a)     dmxLog(dmxDebug,f,a)
141#define LOG2(f,a,b)   dmxLog(dmxDebug,f,a,b)
142#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c)
143#define FATAL0(f)     dmxLog(dmxFatal,f)
144#define FATAL1(f,a)   dmxLog(dmxFatal,f,a)
145#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b)
146#define MOTIONPROC    dmxMotionProcPtr
147#define ENQUEUEPROC   dmxEnqueueProcPtr
148#define CHECKPROC     dmxCheckSpecialProcPtr
149#define SWITCHRETPROC dmxVTSwitchReturnProcPtr
150#define BLOCK         DMXBlockType
151#define MESSAGE       "\033c\n\n\nDMX taking input from this console..."
152#define FINALMESSAGE  "\033cDMX terminated."
153
154/* End of interface definitions. */
155/*****************************************************************************/
156
157#include "inputstr.h"
158#include <X11/Xos.h>
159#include <sys/ioctl.h>
160#include <errno.h>
161#include <signal.h>
162#include <sys/vt.h>
163#include <sys/kd.h>
164#include <termios.h>
165#include "atKeynames.h"
166#if 00
167#include "xf86Keymap.h"
168#endif
169#include <linux/keyboard.h>
170#include <xkbsrv.h>
171
172#define NUM_AT2LNX (sizeof(at2lnx) / sizeof(at2lnx[0]))
173#define NUM_STATE_ENTRIES (256/32)
174
175
176/* Private area for Linux-style keyboards. */
177typedef struct _myPrivate {
178    int            fd;
179    int            vtno;
180    int            vtcurrent;
181    int            kbdtrans;
182    struct termios kbdtty;
183    int            kbdType;
184    CARD32         kbdState[NUM_STATE_ENTRIES];
185    DeviceIntPtr   pKeyboard;
186    unsigned char  prefix;
187
188    int            switched;
189    SWITCHRETPROC  switch_return;
190    void           *switch_return_data;
191
192                                /* For bell */
193    int            pitch;
194    unsigned long  duration;
195} myPrivate;
196
197static myPrivate *PRIV = NULL;
198
199#undef SYSCALL
200#define SYSCALL(call) while(((call) == -1) && (errno == EINTR))
201
202static int kbdLinuxKeyDown(myPrivate *priv, int keyCode)
203{
204    CARD8  byte = keyCode >> 5;
205    CARD32 bit  = 1 << (keyCode & 0x1f);
206
207    if (byte > NUM_STATE_ENTRIES) return 0;
208    return priv->kbdState[byte] & bit;
209}
210
211static void kbdLinuxKeyState(myPrivate *priv, int type, int keyCode)
212{
213    CARD8  byte = keyCode >> 5;
214    CARD32 bit  = 1 << (keyCode & 0x1f);
215
216    if (byte > NUM_STATE_ENTRIES) return;
217    if (type == KeyPress) priv->kbdState[byte] |= bit;
218    else                  priv->kbdState[byte] &= ~bit;
219}
220
221static KeySym linux_to_x[256] = {
222	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
223	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
224	XK_BackSpace,	XK_Tab,		XK_Linefeed,	NoSymbol,
225	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
226	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
227	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
228	NoSymbol,	NoSymbol,	NoSymbol,	XK_Escape,
229	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
230	XK_space,	XK_exclam,	XK_quotedbl,	XK_numbersign,
231	XK_dollar,	XK_percent,	XK_ampersand,	XK_apostrophe,
232	XK_parenleft,	XK_parenright,	XK_asterisk,	XK_plus,
233	XK_comma,	XK_minus,	XK_period,	XK_slash,
234	XK_0,		XK_1,		XK_2,		XK_3,
235	XK_4,		XK_5,		XK_6,		XK_7,
236	XK_8,		XK_9,		XK_colon,	XK_semicolon,
237	XK_less,	XK_equal,	XK_greater,	XK_question,
238	XK_at,		XK_A,		XK_B,		XK_C,
239	XK_D,		XK_E,		XK_F,		XK_G,
240	XK_H,		XK_I,		XK_J,		XK_K,
241	XK_L,		XK_M,		XK_N,		XK_O,
242	XK_P,		XK_Q,		XK_R,		XK_S,
243	XK_T,		XK_U,		XK_V,		XK_W,
244	XK_X,		XK_Y,		XK_Z,		XK_bracketleft,
245	XK_backslash,	XK_bracketright,XK_asciicircum,	XK_underscore,
246	XK_grave,	XK_a,		XK_b,		XK_c,
247	XK_d,		XK_e,		XK_f,		XK_g,
248	XK_h,		XK_i,		XK_j,		XK_k,
249	XK_l,		XK_m,		XK_n,		XK_o,
250	XK_p,		XK_q,		XK_r,		XK_s,
251	XK_t,		XK_u,		XK_v,		XK_w,
252	XK_x,		XK_y,		XK_z,		XK_braceleft,
253	XK_bar,		XK_braceright,	XK_asciitilde,	XK_BackSpace,
254	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
255	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
256	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
257	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
258	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
259	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
260	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
261	NoSymbol,	NoSymbol,	NoSymbol,	NoSymbol,
262	XK_nobreakspace,XK_exclamdown,	XK_cent,	XK_sterling,
263	XK_currency,	XK_yen,		XK_brokenbar,	XK_section,
264	XK_diaeresis,	XK_copyright,	XK_ordfeminine,	XK_guillemotleft,
265	XK_notsign,	XK_hyphen,	XK_registered,	XK_macron,
266	XK_degree,	XK_plusminus,	XK_twosuperior,	XK_threesuperior,
267	XK_acute,	XK_mu,		XK_paragraph,	XK_periodcentered,
268	XK_cedilla,	XK_onesuperior,	XK_masculine,	XK_guillemotright,
269	XK_onequarter,	XK_onehalf,	XK_threequarters,XK_questiondown,
270	XK_Agrave,	XK_Aacute,	XK_Acircumflex,	XK_Atilde,
271	XK_Adiaeresis,	XK_Aring,	XK_AE,		XK_Ccedilla,
272	XK_Egrave,	XK_Eacute,	XK_Ecircumflex,	XK_Ediaeresis,
273	XK_Igrave,	XK_Iacute,	XK_Icircumflex,	XK_Idiaeresis,
274	XK_ETH,		XK_Ntilde,	XK_Ograve,	XK_Oacute,
275	XK_Ocircumflex,	XK_Otilde,	XK_Odiaeresis,	XK_multiply,
276	XK_Ooblique,	XK_Ugrave,	XK_Uacute,	XK_Ucircumflex,
277	XK_Udiaeresis,	XK_Yacute,	XK_THORN,	XK_ssharp,
278	XK_agrave,	XK_aacute,	XK_acircumflex,	XK_atilde,
279	XK_adiaeresis,	XK_aring,	XK_ae,		XK_ccedilla,
280	XK_egrave,	XK_eacute,	XK_ecircumflex,	XK_ediaeresis,
281	XK_igrave,	XK_iacute,	XK_icircumflex,	XK_idiaeresis,
282	XK_eth,		XK_ntilde,	XK_ograve,	XK_oacute,
283	XK_ocircumflex,	XK_otilde,	XK_odiaeresis,	XK_division,
284	XK_oslash,	XK_ugrave,	XK_uacute,	XK_ucircumflex,
285	XK_udiaeresis,	XK_yacute,	XK_thorn,	XK_ydiaeresis
286};
287
288/*
289 * Maps the AT keycodes to Linux keycodes
290 */
291static unsigned char at2lnx[NUM_KEYCODES] =
292{
293	0x01,	/* KEY_Escape */	0x02,	/* KEY_1 */
294	0x03,	/* KEY_2 */		0x04,	/* KEY_3 */
295	0x05,	/* KEY_4 */		0x06,	/* KEY_5 */
296	0x07,	/* KEY_6 */		0x08,	/* KEY_7 */
297	0x09,	/* KEY_8 */		0x0a,	/* KEY_9 */
298	0x0b,	/* KEY_0 */		0x0c,	/* KEY_Minus */
299	0x0d,	/* KEY_Equal */		0x0e,	/* KEY_BackSpace */
300	0x0f,	/* KEY_Tab */		0x10,	/* KEY_Q */
301	0x11,	/* KEY_W */		0x12,	/* KEY_E */
302	0x13,	/* KEY_R */		0x14,	/* KEY_T */
303	0x15,	/* KEY_Y */		0x16,	/* KEY_U */
304	0x17,	/* KEY_I */		0x18,	/* KEY_O */
305	0x19,	/* KEY_P */		0x1a,	/* KEY_LBrace */
306	0x1b,	/* KEY_RBrace */	0x1c,	/* KEY_Enter */
307	0x1d,	/* KEY_LCtrl */		0x1e,	/* KEY_A */
308	0x1f,	/* KEY_S */		0x20,	/* KEY_D */
309	0x21,	/* KEY_F */		0x22,	/* KEY_G */
310	0x23,	/* KEY_H */		0x24,	/* KEY_J */
311	0x25,	/* KEY_K */		0x26,	/* KEY_L */
312	0x27,	/* KEY_SemiColon */	0x28,	/* KEY_Quote */
313	0x29,	/* KEY_Tilde */		0x2a,	/* KEY_ShiftL */
314	0x2b,	/* KEY_BSlash */	0x2c,	/* KEY_Z */
315	0x2d,	/* KEY_X */		0x2e,	/* KEY_C */
316	0x2f,	/* KEY_V */		0x30,	/* KEY_B */
317	0x31,	/* KEY_N */		0x32,	/* KEY_M */
318	0x33,	/* KEY_Comma */		0x34,	/* KEY_Period */
319	0x35,	/* KEY_Slash */		0x36,	/* KEY_ShiftR */
320	0x37,	/* KEY_KP_Multiply */	0x38,	/* KEY_Alt */
321	0x39,	/* KEY_Space */		0x3a,	/* KEY_CapsLock */
322	0x3b,	/* KEY_F1 */		0x3c,	/* KEY_F2 */
323	0x3d,	/* KEY_F3 */		0x3e,	/* KEY_F4 */
324	0x3f,	/* KEY_F5 */		0x40,	/* KEY_F6 */
325	0x41,	/* KEY_F7 */		0x42,	/* KEY_F8 */
326	0x43,	/* KEY_F9 */		0x44,	/* KEY_F10 */
327	0x45,	/* KEY_NumLock */	0x46,	/* KEY_ScrollLock */
328	0x47,	/* KEY_KP_7 */		0x48,	/* KEY_KP_8 */
329	0x49,	/* KEY_KP_9 */		0x4a,	/* KEY_KP_Minus */
330	0x4b,	/* KEY_KP_4 */		0x4c,	/* KEY_KP_5 */
331	0x4d,	/* KEY_KP_6 */		0x4e,	/* KEY_KP_Plus */
332	0x4f,	/* KEY_KP_1 */		0x50,	/* KEY_KP_2 */
333	0x51,	/* KEY_KP_3 */		0x52,	/* KEY_KP_0 */
334	0x53,	/* KEY_KP_Decimal */	0x54,	/* KEY_SysReqest */
335	0x00,	/* 0x55 */		0x56,	/* KEY_Less */
336	0x57,	/* KEY_F11 */		0x58,	/* KEY_F12 */
337	0x66,	/* KEY_Home */		0x67,	/* KEY_Up */
338	0x68,	/* KEY_PgUp */		0x69,	/* KEY_Left */
339	0x5d,	/* KEY_Begin */		0x6a,	/* KEY_Right */
340	0x6b,	/* KEY_End */		0x6c,	/* KEY_Down */
341	0x6d,	/* KEY_PgDown */	0x6e,	/* KEY_Insert */
342	0x6f,	/* KEY_Delete */	0x60,	/* KEY_KP_Enter */
343	0x61,	/* KEY_RCtrl */		0x77,	/* KEY_Pause */
344	0x63,	/* KEY_Print */		0x62,	/* KEY_KP_Divide */
345	0x64,	/* KEY_AltLang */	0x65,	/* KEY_Break */
346	0x00,	/* KEY_LMeta */		0x00,	/* KEY_RMeta */
347	0x7A,	/* KEY_Menu/FOCUS_PF11*/0x00,	/* 0x6e */
348	0x7B,	/* FOCUS_PF12 */	0x00,	/* 0x70 */
349	0x00,	/* 0x71 */		0x00,	/* 0x72 */
350	0x59,	/* FOCUS_PF2 */		0x78,	/* FOCUS_PF9 */
351	0x00,	/* 0x75 */		0x00,	/* 0x76 */
352	0x5A,	/* FOCUS_PF3 */		0x5B,	/* FOCUS_PF4 */
353	0x5C,	/* FOCUS_PF5 */		0x5D,	/* FOCUS_PF6 */
354	0x5E,	/* FOCUS_PF7 */		0x5F,	/* FOCUS_PF8 */
355	0x7C,	/* JAP_86 */		0x79,	/* FOCUS_PF10 */
356	0x00,	/* 0x7f */
357};
358
359/** Create a private structure for use within this file. */
360pointer kbdLinuxCreatePrivate(DeviceIntPtr pKeyboard)
361{
362    myPrivate *priv = calloc(1, sizeof(*priv));
363    priv->fd        = -1;
364    priv->pKeyboard = pKeyboard;
365    return priv;
366}
367
368/** Destroy a private structure. */
369void kbdLinuxDestroyPrivate(pointer priv)
370{
371    free(priv);
372}
373
374/** Ring the bell.
375 *
376 * Note: we completely ignore the \a volume, since Linux's ioctl()
377 * interface does not provide a way to control it.  If it did, the XBell
378 * manpage tells how the actual volume is a function of the percent and
379 * the (base) volume.
380 *
381 * Note that most of the other PC-based bell drivers compute the
382 * duration for KDMKTONE as a function of the volume and the duration.
383 * For some drivers, the duration is only measured in mS if the volume
384 * is 50, and is scaled by the volume for other values.  This seems
385 * confusing and possibly incorrect (the xset man page says that the
386 * bell will be "as closely as it can to the user's specifications" --
387 * if we ignore the volume and set the duration correctly, then we'll
388 * get one parameter "wrong" -- but if we use the volume to scale the
389 * duration, then we'll get both parameters "wrong"). */
390void kbdLinuxBell(DevicePtr pDev, int percent,
391                  int volume, int pitch, int duration)
392{
393    GETPRIV;
394
395    if (duration && pitch) {
396        ioctl(priv->fd,
397              KDMKTONE,
398              ((1193190 / pitch) & 0xffff) /* Low bits specify cycle time */
399              | (duration << 16)); /* High bits are duration in msec */
400    }
401}
402
403/** Set the LEDs. */
404void kbdLinuxCtrl(DevicePtr pDev, KeybdCtrl *ctrl)
405{
406    GETPRIV;
407
408    ioctl(priv->fd, KDSETLED, ctrl->leds & 0x07);
409}
410
411static int kbdLinuxGetFreeVTNumber(void)
412{
413    int        fd = -1;
414    int        vtno;
415    int        i;
416    const char *tty0[] = { "/dev/tty0", "/dev/vc/0", NULL };
417
418    for (i = 0; tty0[i]; i++)
419        if ((fd = open(tty0[i], O_WRONLY, 0)) >= 0) break;
420    if (fd < 0)
421        FATAL1("kbdLinuxGetFreeVTNumber: Cannot open tty0 (%s)\n",
422               strerror(errno));
423    if (ioctl(fd, VT_OPENQRY, &vtno) < 0 || vtno < 0)
424        FATAL0("kbdLinuxGetFreeVTNumber: Cannot find a free VT\n");
425    return vtno;
426}
427
428static int kbdLinuxOpenVT(int vtno)
429{
430    int        fd = -1;
431    int        i;
432    const char *vcs[] = { "/dev/vc/%d", "/dev/tty%d", NULL };
433    char       name[64];        /* RATS: Only used in XmuSnprintf */
434
435    for (i = 0; vcs[i]; i++) {
436        XmuSnprintf(name, sizeof(name), vcs[i], vtno);
437        if ((fd = open(name, O_RDWR | O_NONBLOCK, 0)) >= 0) break;
438    }
439    if (fd < 0)
440        FATAL2("kbdLinuxOpenVT: Cannot open VT %d (%s)\n",
441               vtno, strerror(errno));
442    return fd;
443}
444
445static int kbdLinuxGetCurrentVTNumber(int fd)
446{
447    struct vt_stat vts;
448
449    if (!ioctl(fd, VT_GETSTATE, &vts)) return vts.v_active;
450    return -1;
451}
452
453static int kbdLinuxActivate(int fd, int vtno, int setSig);
454
455/** Currently unused hook called prior to an VT switch. */
456void kbdLinuxVTPreSwitch(pointer p)
457{
458}
459
460/** Currently unused hook called after returning from a VT switch. */
461void kbdLinuxVTPostSwitch(pointer p)
462{
463}
464
465/** Tell the operating system to switch to \a vt.  The \a switch_return
466 * function is called with the \a switch_return_data when the VT is
467 * switched back to the pre-switch VT (i.e., the user returns to the DMX
468 * session). */
469int kbdLinuxVTSwitch(pointer p, int vt,
470                     void (*switch_return)(pointer),
471                     pointer switch_return_data)
472{
473    myPrivate *priv = p;
474
475    if (priv->switched) FATAL0("kbdLinuxVTSwitch: already switched...\n");
476    if (priv->vtno == vt) return 0;
477
478    PRIV                     = priv;
479    priv->switched           = 0; /* Will switch to 1 in handler */
480    priv->switch_return      = switch_return;
481    priv->switch_return_data = switch_return_data;
482    kbdLinuxActivate(priv->fd, vt, 0);
483    return 1;
484}
485
486/* RATS: This function is only ever used to handle SIGUSR1. */
487static void kbdLinuxVTSignalHandler(int sig)
488{
489    myPrivate *priv = PRIV;
490
491    signal(sig, kbdLinuxVTSignalHandler);
492    if (priv) {
493        ioctl(priv->fd, VT_RELDISP, VT_ACKACQ);
494        priv->switched = !priv->switched;
495        LOG2("kbdLinuxVTSignalHandler: got signal %d, switched = %d\n",
496             sig, priv->switched);
497        if (!priv->switched && priv->switch_return)
498            priv->switch_return(priv->switch_return_data);
499    }
500}
501
502static int kbdLinuxActivate(int fd, int vtno, int setSig)
503{
504    int            result;
505    struct vt_mode VT;
506
507    SYSCALL(result = ioctl(fd, VT_ACTIVATE, vtno));
508    if (result) FATAL0("kbdLinuxActivate: VT_ACTIVATE failed\n");
509    SYSCALL(result = ioctl(fd, VT_WAITACTIVE, vtno));
510    if (result) FATAL0("kbdLinuxActivate: VT_WAITACTIVE failed\n");
511    if (setSig) {
512        SYSCALL(result = ioctl(fd, VT_GETMODE, &VT));
513        if (result < 0) FATAL0("kbdLinuxActivate: VT_GETMODE failed\n");
514        VT.mode   = VT_PROCESS;
515        VT.relsig = SIGUSR1;
516        VT.acqsig = SIGUSR1;
517        if (ioctl(fd, VT_SETMODE, &VT))
518            FATAL0("kbdLinuxActivate: VT_SETMODE VT_PROCESS failed\n");
519        signal(SIGUSR1, kbdLinuxVTSignalHandler);
520    }
521    return Success;
522}
523
524static void kbdLinuxOpenConsole(DevicePtr pDev)
525{
526    GETPRIV;
527    const char *msg = MESSAGE;
528
529    if (priv->fd >= 0) return;
530    priv->vtno      = kbdLinuxGetFreeVTNumber();
531    priv->fd        = kbdLinuxOpenVT(priv->vtno);
532    priv->vtcurrent = kbdLinuxGetCurrentVTNumber(priv->fd);
533    LOG2("kbdLinuxOpenConsole: current VT %d; using free VT %d\n",
534         priv->vtcurrent, priv->vtno);
535    kbdLinuxActivate(priv->fd, priv->vtno, 1);
536    ioctl(priv->fd, KDSETMODE, KD_GRAPHICS); /* To turn off gpm */
537    if (msg) write(priv->fd, msg, strlen(msg));
538}
539
540static void kbdLinuxCloseConsole(DevicePtr pDev)
541{
542    GETPRIV;
543    struct vt_mode VT;
544    const char     *msg = FINALMESSAGE;
545
546    if (priv->fd < 0) return;
547
548    ioctl(priv->fd, KDSETMODE, KD_TEXT);
549    if (msg) write(priv->fd, msg, strlen(msg));
550    if (ioctl(priv->fd, VT_GETMODE, &VT) != -1) {
551        VT.mode = VT_AUTO;
552        ioctl(priv->fd, VT_SETMODE, &VT);
553    }
554
555    LOG1("kbdLinuxCloseConsole: switching to VT %d\n", priv->vtcurrent);
556    if (priv->vtcurrent >= 0) kbdLinuxActivate(priv->fd, priv->vtcurrent, 0);
557
558    close(priv->fd);
559    priv->fd = -1;
560}
561
562/** Initialize the \a pDev as a Linux keyboard. */
563void kbdLinuxInit(DevicePtr pDev)
564{
565    GETPRIV;
566
567    if (priv->fd <= 0) kbdLinuxOpenConsole(pDev);
568
569    ioctl(priv->fd, KDGKBMODE, &priv->kbdtrans);
570    if (tcgetattr(priv->fd, &priv->kbdtty) < 0)
571        FATAL1("kbdLinuxInit: tcgetattr failed (%s)\n", strerror(errno));
572}
573
574static int kbdLinuxPrefix0Mapping(unsigned char *scanCode)
575{
576                                /* Table from xfree86/common/xf86Events.c */
577    switch (*scanCode) {
578    case KEY_KP_7:        *scanCode = KEY_Home;      break; /* curs home */
579    case KEY_KP_8:        *scanCode = KEY_Up;        break; /* curs up */
580    case KEY_KP_9:        *scanCode = KEY_PgUp;      break; /* curs pgup */
581    case KEY_KP_4:        *scanCode = KEY_Left;      break; /* curs left */
582    case KEY_KP_5:        *scanCode = KEY_Begin;     break; /* curs begin */
583    case KEY_KP_6:        *scanCode = KEY_Right;     break; /* curs right */
584    case KEY_KP_1:        *scanCode = KEY_End;       break; /* curs end */
585    case KEY_KP_2:        *scanCode = KEY_Down;      break; /* curs down */
586    case KEY_KP_3:        *scanCode = KEY_PgDown;    break; /* curs pgdown */
587    case KEY_KP_0:        *scanCode = KEY_Insert;    break; /* curs insert */
588    case KEY_KP_Decimal:  *scanCode = KEY_Delete;    break; /* curs delete */
589    case KEY_Enter:       *scanCode = KEY_KP_Enter;  break; /* keypad enter */
590    case KEY_LCtrl:       *scanCode = KEY_RCtrl;     break; /* right ctrl */
591    case KEY_KP_Multiply: *scanCode = KEY_Print;     break; /* print */
592    case KEY_Slash:       *scanCode = KEY_KP_Divide; break; /* keyp divide */
593    case KEY_Alt:         *scanCode = KEY_AltLang;   break; /* right alt */
594    case KEY_ScrollLock:  *scanCode = KEY_Break;     break; /* curs break */
595    case 0x5b:            *scanCode = KEY_LMeta;     break;
596    case 0x5c:            *scanCode = KEY_RMeta;     break;
597    case 0x5d:            *scanCode = KEY_Menu;      break;
598    case KEY_F3:          *scanCode = KEY_F13;       break;
599    case KEY_F4:          *scanCode = KEY_F14;       break;
600    case KEY_F5:          *scanCode = KEY_F15;       break;
601    case KEY_F6:          *scanCode = KEY_F16;       break;
602    case KEY_F7:          *scanCode = KEY_F17;       break;
603    case KEY_KP_Plus:     *scanCode = KEY_KP_DEC;    break;
604        /*
605         * Ignore virtual shifts (E0 2A, E0 AA, E0 36, E0 B6)
606         */
607    case 0x2A:
608    case 0x36:
609        return 1;
610    default:
611        /*
612         * "Internet" keyboards are generating lots of new codes.
613         * Let them pass.  There is little consistency between them,
614         * so don't bother with symbolic names at this level.
615         */
616        scanCode += 0x78;
617    }
618    return 0;
619}
620
621static int kbdLinuxPrefixMapping(myPrivate *priv, unsigned char *scanCode)
622{
623    int           pressed = *scanCode & 0x80;
624    unsigned char code    = *scanCode & 0x7f;
625
626                                /* If we don't have a prefix, check for one */
627    if (!priv->prefix) {
628        switch (code) {
629        case KEY_Prefix0:
630        case KEY_Prefix1:
631            priv->prefix = code;
632            return 1;
633        }
634        return 0;               /* No change */
635    }
636
637                                /* We have a prefix from the last scanCode */
638    switch (priv->prefix) {
639    case KEY_Prefix0:
640        priv->prefix = 0;
641        if (kbdLinuxPrefix0Mapping(&code)) return 1; /* Skip sequence */
642        break;
643    case KEY_Prefix1:
644        priv->prefix = (code = KEY_LCtrl) ? KEY_LCtrl : 0;
645        return 1;                                       /* Use new prefix */
646    case KEY_LCtrl:
647        priv->prefix = 0;
648        if (code != KEY_NumLock) return 1;              /* Skip sequence*/
649        code = KEY_Pause;
650        break;
651    }
652
653    *scanCode = code | (pressed ? 0x80 : 0x00);
654    return 0;                                           /* Use old scanCode */
655}
656
657static void kbdLinuxConvert(DevicePtr pDev,
658                            unsigned char scanCode,
659                            ENQUEUEPROC enqueue,
660                            CHECKPROC checkspecial,
661                            BLOCK block)
662{
663    GETPRIV;
664    XkbSrvInfoPtr  xkbi = priv->pKeyboard->key->xkbInfo;
665    int            type;
666    KeySym         keySym   = NoSymbol;
667    int            keyCode;
668    int            switching;
669
670    /* Do special PC/AT prefix mapping -- may change scanCode! */
671    if (kbdLinuxPrefixMapping(priv, &scanCode)) return;
672
673    type    = (scanCode & 0x80) ? KeyRelease : KeyPress;
674    keyCode = (scanCode & 0x7f) + MIN_KEYCODE;
675
676    /* Handle repeats */
677
678    if (keyCode >= xkbi->desc->min_key_code &&
679        keyCode <= xkbi->desc->max_key_code) {
680
681        int effectiveGroup = XkbGetEffectiveGroup(xkbi,
682                                                  &xkbi->state,
683                                                  scanCode);
684        keySym = XkbKeySym(xkbi->desc, scanCode, effectiveGroup);
685#if 0
686        switch (keySym) {
687        case XK_Num_Lock:
688        case XK_Scroll_Lock:
689        case XK_Shift_Lock:
690        case XK_Caps_Lock:
691            /* Ignore releases and all but first press */
692            if (kbdLinuxModIgnore(priv, &xE, keySym)) return;
693            if (kbdLinuxKeyDown(priv, &xE)) xE.u.u.type = KeyRelease;
694            else                            xE.u.u.type = KeyPress;
695            break;
696        }
697#endif
698
699        /* If key is already down, ignore or autorepeat */
700        if (type == KeyPress && kbdLinuxKeyDown(priv, keyCode)) {
701            KbdFeedbackClassRec *feed = priv->pKeyboard->kbdfeed;
702
703            /* No auto-repeat? */
704            if ((feed && !feed->ctrl.autoRepeat)
705                || priv->pKeyboard->key->xkbInfo->desc->map->modmap[keyCode]
706                || (feed
707                    && !(feed->ctrl.autoRepeats[keyCode >> 3]
708                         & (1 << (keyCode & 7))))) return; /* Ignore */
709
710            /* Do auto-repeat */
711            enqueue(pDev, KeyRelease, keyCode, keySym, NULL, block);
712            type = KeyPress;
713        }
714
715        /* If key is already up, ignore */
716        if (type == KeyRelease && !kbdLinuxKeyDown(priv, keyCode)) return;
717    }
718
719    switching = 0;
720    if (checkspecial && type == KeyPress)
721        switching = checkspecial(pDev, keySym);
722    if (!switching) {
723        if (enqueue)
724            enqueue(pDev, type, keyCode, keySym, NULL, block);
725        kbdLinuxKeyState(priv, type, keyCode); /* Update our state bitmap */
726    }
727}
728
729/** Read an event from the \a pDev device.  If the event is a motion
730 * event, enqueue it with the \a motion function.  Otherwise, check for
731 * special keys with the \a checkspecial function and enqueue the event
732 * with the \a enqueue function.  The \a block type is passed to the
733 * functions so that they may block SIGIO handling as appropriate to the
734 * caller of this function. */
735void kbdLinuxRead(DevicePtr pDev,
736                  MOTIONPROC motion,
737                  ENQUEUEPROC enqueue,
738                  CHECKPROC checkspecial,
739                  BLOCK block)
740{
741    GETPRIV;
742    unsigned char buf[256];     /* RATS: Only used in length-limited call */
743    unsigned char *pt;
744    int           n;
745
746    while ((n = read(priv->fd, buf, sizeof(buf))) > 0)
747        for (pt = buf; n; --n, ++pt)
748            kbdLinuxConvert(pDev, *pt, enqueue, checkspecial, block);
749}
750
751/** Turn \a pDev on (i.e., take input from \a pDev). */
752int kbdLinuxOn(DevicePtr pDev)
753{
754    GETPRIV;
755    struct termios nTty;
756
757    ioctl(priv->fd, KDSKBMODE, K_RAW);
758
759    nTty             = priv->kbdtty;
760    nTty.c_iflag     = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP);
761    nTty.c_oflag     = 0;
762    nTty.c_cflag     = CREAD | CS8;
763    nTty.c_lflag     = 0;
764    nTty.c_cc[VTIME] = 0;
765    nTty.c_cc[VMIN]  = 1;
766    cfsetispeed(&nTty, B9600);
767    cfsetospeed(&nTty, B9600);
768    if (tcsetattr(priv->fd, TCSANOW, &nTty) < 0)
769        FATAL1("kbdLinuxOn: tcsetattr failed (%s)\n", strerror(errno));
770    return priv->fd;
771}
772
773/** Turn \a pDev off (i.e., stop taking input from \a pDev). */
774void kbdLinuxOff(DevicePtr pDev)
775{
776    GETPRIV;
777
778    ioctl(priv->fd, KDSKBMODE, priv->kbdtrans);
779    tcsetattr(priv->fd, TCSANOW, &priv->kbdtty);
780    kbdLinuxCloseConsole(pDev);
781}
782
783
784static void kbdLinuxReadKernelMapping(int fd, KeySymsPtr pKeySyms)
785{
786    KeySym        *k;
787    int           i;
788    int           maxkey;
789    static unsigned char tbl[GLYPHS_PER_KEY] = { /* RATS: Use ok */
790        0,	/* unshifted */
791        1,	/* shifted */
792        0,	/* modeswitch unshifted */
793        0	/* modeswitch shifted */
794    };
795
796  /*
797   * Read the mapping from the kernel.
798   * Since we're still using the XFree86 scancode->AT keycode mapping
799   * routines, we need to convert the AT keycodes to Linux keycodes,
800   * then translate the Linux keysyms into X keysyms.
801   *
802   * First, figure out which tables to use for the modeswitch columns
803   * above, from the XF86Config fields.
804   */
805  tbl[2] = 8;	/* alt */
806  tbl[3] = tbl[2] | 1;
807
808#if 00/*BP*/
809  k = map+GLYPHS_PER_KEY;
810#else
811  ErrorF("kbdLinuxReadKernelMapping() is broken/no-op'd\n");
812  return;
813#endif
814  maxkey = NUM_AT2LNX;
815
816  for (i = 0; i < maxkey; ++i) {
817      struct kbentry kbe;
818      int j;
819
820      kbe.kb_index = at2lnx[i];
821
822      for (j = 0; j < GLYPHS_PER_KEY; ++j, ++k) {
823          unsigned short kval;
824
825          *k = NoSymbol;
826
827          kbe.kb_table = tbl[j];
828          if (kbe.kb_index == 0 || ioctl(fd, KDGKBENT, &kbe)) continue;
829
830          kval = KVAL(kbe.kb_value);
831          switch (KTYP(kbe.kb_value)) {
832          case KT_LATIN:
833          case KT_LETTER: *k = linux_to_x[kval]; break;
834          case KT_FN:
835              if (kval <= 19) *k = XK_F1 + kval;
836              else switch (kbe.kb_value) {
837              case K_FIND:       *k = XK_Home; /* or XK_Find */      break;
838              case K_INSERT:     *k = XK_Insert;                     break;
839              case K_REMOVE:     *k = XK_Delete;                     break;
840              case K_SELECT:     *k = XK_End; /* or XK_Select */     break;
841              case K_PGUP:       *k = XK_Prior;                      break;
842              case K_PGDN:       *k = XK_Next;                       break;
843              case K_HELP:       *k = XK_Help;                       break;
844              case K_DO:         *k = XK_Execute;                    break;
845              case K_PAUSE:      *k = XK_Pause;                      break;
846              case K_MACRO:      *k = XK_Menu;                       break;
847              default:                                               break;
848              }
849              break;
850          case KT_SPEC:
851              switch (kbe.kb_value) {
852              case K_ENTER:      *k = XK_Return;                     break;
853              case K_BREAK:      *k = XK_Break;                      break;
854              case K_CAPS:       *k = XK_Caps_Lock;                  break;
855              case K_NUM:        *k = XK_Num_Lock;                   break;
856              case K_HOLD:       *k = XK_Scroll_Lock;                break;
857              case K_COMPOSE:    *k = XK_Multi_key;                  break;
858              default:                                               break;
859              }
860              break;
861          case KT_PAD:
862              switch (kbe.kb_value) {
863              case K_PPLUS:      *k = XK_KP_Add;                     break;
864              case K_PMINUS:     *k = XK_KP_Subtract;                break;
865              case K_PSTAR:      *k = XK_KP_Multiply;                break;
866              case K_PSLASH:     *k = XK_KP_Divide;                  break;
867              case K_PENTER:     *k = XK_KP_Enter;                   break;
868              case K_PCOMMA:     *k = XK_KP_Separator;               break;
869              case K_PDOT:       *k = XK_KP_Decimal;                 break;
870              case K_PPLUSMINUS: *k = XK_KP_Subtract;                break;
871              default:           if (kval <= 9) *k = XK_KP_0 + kval; break;
872              }
873              break;
874          case KT_DEAD:
875              /* KT_DEAD keys are for accelerated diacritical creation. */
876              switch (kbe.kb_value) {
877              case K_DGRAVE:     *k = XK_dead_grave;                 break;
878              case K_DACUTE:     *k = XK_dead_acute;                 break;
879              case K_DCIRCM:     *k = XK_dead_circumflex;            break;
880              case K_DTILDE:     *k = XK_dead_tilde;                 break;
881              case K_DDIERE:     *k = XK_dead_diaeresis;             break;
882              }
883              break;
884          case KT_CUR:
885              switch (kbe.kb_value) {
886              case K_DOWN:       *k = XK_Down;                       break;
887              case K_LEFT:       *k = XK_Left;                       break;
888              case K_RIGHT:      *k = XK_Right;                      break;
889              case K_UP:         *k = XK_Up;                         break;
890              }
891              break;
892          case KT_SHIFT:
893              switch (kbe.kb_value) {
894              case K_ALTGR:      *k = XK_Alt_R;                       break;
895              case K_ALT:
896                  *k = (kbe.kb_index == 0x64 ? XK_Alt_R : XK_Alt_L);
897                  break;
898              case K_CTRL:
899                  *k = (kbe.kb_index == 0x61 ? XK_Control_R : XK_Control_L);
900                  break;
901              case K_CTRLL:      *k = XK_Control_L;                   break;
902              case K_CTRLR:      *k = XK_Control_R;                   break;
903              case K_SHIFT:
904                  *k = (kbe.kb_index == 0x36 ? XK_Shift_R : XK_Shift_L);
905                  break;
906              case K_SHIFTL:     *k = XK_Shift_L;                     break;
907              case K_SHIFTR:     *k = XK_Shift_R;                     break;
908              default:                                                break;
909              }
910              break;
911          case KT_ASCII:
912              /* KT_ASCII keys accumulate a 3 digit decimal number that
913               * gets emitted when the shift state changes. We can't
914               * emulate that.
915               */
916              break;
917          case KT_LOCK:
918              if (kbe.kb_value == K_SHIFTLOCK) *k = XK_Shift_Lock;
919              break;
920          default:                                                    break;
921          }
922      }
923
924      if (k[-1] == k[-2])                   k[-1] = NoSymbol;
925      if (k[-2] == k[-3])                   k[-2] = NoSymbol;
926      if (k[-3] == k[-4])                   k[-3] = NoSymbol;
927      if (k[-4] == k[-2] && k[-3] == k[-1]) k[-2] = k[-1] = NoSymbol;
928      if (k[-1] == k[-4] && k[-2] == k[-3]
929          && k[-2] == NoSymbol)             k[-1] = NoSymbol;
930  }
931}
932
933static void kbdLinuxGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap)
934{
935    GETPRIV;
936    KeySym        *k, *mapCopy;
937    char          type;
938    int           i;
939
940#if 00/*BP*/
941    mapCopy = malloc(sizeof(map));
942    memcpy(mapCopy, map, sizeof(map));
943#else
944    ErrorF("kbdLinuxGetMap() is broken/no-op'd\n");
945    return;
946#endif
947
948    kbdLinuxReadKernelMapping(priv->fd, pKeySyms);
949
950    /* compute the modifier map */
951    for (i = 0; i < MAP_LENGTH; i++)
952        pModMap[i] = NoSymbol;  /* make sure it is restored */
953
954    for (k = mapCopy, i = MIN_KEYCODE;
955         i < NUM_KEYCODES + MIN_KEYCODE;
956         i++, k += 4) {
957        switch(*k) {
958        case XK_Shift_L:
959        case XK_Shift_R:     pModMap[i] = ShiftMask;      break;
960        case XK_Control_L:
961        case XK_Control_R:   pModMap[i] = ControlMask;    break;
962        case XK_Caps_Lock:   pModMap[i] = LockMask;       break;
963        case XK_Alt_L:
964        case XK_Alt_R:       pModMap[i] = AltMask;        break;
965        case XK_Num_Lock:    pModMap[i] = NumLockMask;    break;
966        case XK_Scroll_Lock: pModMap[i] = ScrollLockMask; break;
967        case XK_Kana_Lock:
968        case XK_Kana_Shift:  pModMap[i] = KanaMask;       break;
969        case XK_Mode_switch: pModMap[i] = AltLangMask;    break;
970        }
971    }
972
973    priv->kbdType = (ioctl(priv->fd, KDGKBTYPE, &type) < 0) ? KB_101 : type;
974
975    pKeySyms->map        = mapCopy; /* Must be XFree'able */
976    pKeySyms->mapWidth   = GLYPHS_PER_KEY;
977    pKeySyms->minKeyCode = MIN_KEYCODE;
978    pKeySyms->maxKeyCode = MAX_KEYCODE;
979}
980
981/** Fill the \a info structure with information needed to initialize \a
982 * pDev. */
983void kbdLinuxGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info)
984{
985    info->keyboard         = 1;
986    info->keyClass         = 1;
987    kbdLinuxGetMap(pDev, &info->keySyms, info->modMap);
988    info->focusClass       = 1;
989    info->kbdFeedbackClass = 1;
990}
991