1 /* Portions of this file were derived from the following files:
3 **********************************************************************
5 * xfree86/common/{xf86Io.c,xf86Kbd.c,xf86Events.c}
7 * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
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.
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.
27 **********************************************************************
29 * xfree86/common/xf86KbdLnx.c
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.
37 * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
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.
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.
57 **********************************************************************
59 * xfree86/os-support/linux/lnx_io.c
61 * Copyright 1992 by Orest Zborowski <obz@Kodak.com>
62 * Copyright 1993 by David Dawes <dawes@xfree86.org>
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
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.
86 * Copyright 2001-2003 Red Hat Inc., Durham, North Carolina.
88 * All Rights Reserved.
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:
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.
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
114 * Rickard E. (Rik) Faith <faith@redhat.com>
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
125 #ifdef HAVE_DMX_CONFIG_H
126 #include <dmx-config.h>
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"
136 #define GETPRIV myPrivate *priv \
137 = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private
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."
154 /* End of interface definitions. */
155 /*****************************************************************************/
157 #include "inputstr.h"
159 #include <sys/ioctl.h>
165 #include "atKeynames.h"
167 #include "xf86Keymap.h"
169 #include <linux/keyboard.h>
171 #define NUM_AT2LNX (sizeof(at2lnx) / sizeof(at2lnx[0]))
172 #define NUM_STATE_ENTRIES (256/32)
175 /* Private area for Linux-style keyboards. */
176 typedef struct _myPrivate
{
181 struct termios kbdtty
;
183 CARD32 kbdState
[NUM_STATE_ENTRIES
];
184 DeviceIntPtr pKeyboard
;
185 unsigned char prefix
;
188 SWITCHRETPROC switch_return
;
189 void *switch_return_data
;
193 unsigned long duration
;
196 static myPrivate
*PRIV
= NULL
;
199 #define SYSCALL(call) while(((call) == -1) && (errno == EINTR))
201 static int kbdLinuxKeyDown(myPrivate
*priv
, int keyCode
)
203 CARD8 byte
= keyCode
>> 5;
204 CARD32 bit
= 1 << (keyCode
& 0x1f);
206 if (byte
> NUM_STATE_ENTRIES
) return 0;
207 return priv
->kbdState
[byte
] & bit
;
210 static void kbdLinuxKeyState(myPrivate
*priv
, int type
, int keyCode
)
212 CARD8 byte
= keyCode
>> 5;
213 CARD32 bit
= 1 << (keyCode
& 0x1f);
215 if (byte
> NUM_STATE_ENTRIES
) return;
216 if (type
== KeyPress
) priv
->kbdState
[byte
] |= bit
;
217 else priv
->kbdState
[byte
] &= ~bit
;
220 static KeySym linux_to_x
[256] = {
221 NoSymbol
, NoSymbol
, NoSymbol
, NoSymbol
,
222 NoSymbol
, NoSymbol
, NoSymbol
, NoSymbol
,
223 XK_BackSpace
, XK_Tab
, XK_Linefeed
, NoSymbol
,
224 NoSymbol
, NoSymbol
, NoSymbol
, NoSymbol
,
225 NoSymbol
, NoSymbol
, NoSymbol
, NoSymbol
,
226 NoSymbol
, NoSymbol
, NoSymbol
, NoSymbol
,
227 NoSymbol
, NoSymbol
, NoSymbol
, XK_Escape
,
228 NoSymbol
, NoSymbol
, NoSymbol
, NoSymbol
,
229 XK_space
, XK_exclam
, XK_quotedbl
, XK_numbersign
,
230 XK_dollar
, XK_percent
, XK_ampersand
, XK_apostrophe
,
231 XK_parenleft
, XK_parenright
, XK_asterisk
, XK_plus
,
232 XK_comma
, XK_minus
, XK_period
, XK_slash
,
233 XK_0
, XK_1
, XK_2
, XK_3
,
234 XK_4
, XK_5
, XK_6
, XK_7
,
235 XK_8
, XK_9
, XK_colon
, XK_semicolon
,
236 XK_less
, XK_equal
, XK_greater
, XK_question
,
237 XK_at
, XK_A
, XK_B
, XK_C
,
238 XK_D
, XK_E
, XK_F
, XK_G
,
239 XK_H
, XK_I
, XK_J
, XK_K
,
240 XK_L
, XK_M
, XK_N
, XK_O
,
241 XK_P
, XK_Q
, XK_R
, XK_S
,
242 XK_T
, XK_U
, XK_V
, XK_W
,
243 XK_X
, XK_Y
, XK_Z
, XK_bracketleft
,
244 XK_backslash
, XK_bracketright
,XK_asciicircum
, XK_underscore
,
245 XK_grave
, XK_a
, XK_b
, XK_c
,
246 XK_d
, XK_e
, XK_f
, XK_g
,
247 XK_h
, XK_i
, XK_j
, XK_k
,
248 XK_l
, XK_m
, XK_n
, XK_o
,
249 XK_p
, XK_q
, XK_r
, XK_s
,
250 XK_t
, XK_u
, XK_v
, XK_w
,
251 XK_x
, XK_y
, XK_z
, XK_braceleft
,
252 XK_bar
, XK_braceright
, XK_asciitilde
, XK_BackSpace
,
253 NoSymbol
, NoSymbol
, NoSymbol
, NoSymbol
,
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 XK_nobreakspace
,XK_exclamdown
, XK_cent
, XK_sterling
,
262 XK_currency
, XK_yen
, XK_brokenbar
, XK_section
,
263 XK_diaeresis
, XK_copyright
, XK_ordfeminine
, XK_guillemotleft
,
264 XK_notsign
, XK_hyphen
, XK_registered
, XK_macron
,
265 XK_degree
, XK_plusminus
, XK_twosuperior
, XK_threesuperior
,
266 XK_acute
, XK_mu
, XK_paragraph
, XK_periodcentered
,
267 XK_cedilla
, XK_onesuperior
, XK_masculine
, XK_guillemotright
,
268 XK_onequarter
, XK_onehalf
, XK_threequarters
,XK_questiondown
,
269 XK_Agrave
, XK_Aacute
, XK_Acircumflex
, XK_Atilde
,
270 XK_Adiaeresis
, XK_Aring
, XK_AE
, XK_Ccedilla
,
271 XK_Egrave
, XK_Eacute
, XK_Ecircumflex
, XK_Ediaeresis
,
272 XK_Igrave
, XK_Iacute
, XK_Icircumflex
, XK_Idiaeresis
,
273 XK_ETH
, XK_Ntilde
, XK_Ograve
, XK_Oacute
,
274 XK_Ocircumflex
, XK_Otilde
, XK_Odiaeresis
, XK_multiply
,
275 XK_Ooblique
, XK_Ugrave
, XK_Uacute
, XK_Ucircumflex
,
276 XK_Udiaeresis
, XK_Yacute
, XK_THORN
, XK_ssharp
,
277 XK_agrave
, XK_aacute
, XK_acircumflex
, XK_atilde
,
278 XK_adiaeresis
, XK_aring
, XK_ae
, XK_ccedilla
,
279 XK_egrave
, XK_eacute
, XK_ecircumflex
, XK_ediaeresis
,
280 XK_igrave
, XK_iacute
, XK_icircumflex
, XK_idiaeresis
,
281 XK_eth
, XK_ntilde
, XK_ograve
, XK_oacute
,
282 XK_ocircumflex
, XK_otilde
, XK_odiaeresis
, XK_division
,
283 XK_oslash
, XK_ugrave
, XK_uacute
, XK_ucircumflex
,
284 XK_udiaeresis
, XK_yacute
, XK_thorn
, XK_ydiaeresis
288 * Maps the AT keycodes to Linux keycodes
290 static unsigned char at2lnx
[NUM_KEYCODES
] =
292 0x01, /* KEY_Escape */ 0x02, /* KEY_1 */
293 0x03, /* KEY_2 */ 0x04, /* KEY_3 */
294 0x05, /* KEY_4 */ 0x06, /* KEY_5 */
295 0x07, /* KEY_6 */ 0x08, /* KEY_7 */
296 0x09, /* KEY_8 */ 0x0a, /* KEY_9 */
297 0x0b, /* KEY_0 */ 0x0c, /* KEY_Minus */
298 0x0d, /* KEY_Equal */ 0x0e, /* KEY_BackSpace */
299 0x0f, /* KEY_Tab */ 0x10, /* KEY_Q */
300 0x11, /* KEY_W */ 0x12, /* KEY_E */
301 0x13, /* KEY_R */ 0x14, /* KEY_T */
302 0x15, /* KEY_Y */ 0x16, /* KEY_U */
303 0x17, /* KEY_I */ 0x18, /* KEY_O */
304 0x19, /* KEY_P */ 0x1a, /* KEY_LBrace */
305 0x1b, /* KEY_RBrace */ 0x1c, /* KEY_Enter */
306 0x1d, /* KEY_LCtrl */ 0x1e, /* KEY_A */
307 0x1f, /* KEY_S */ 0x20, /* KEY_D */
308 0x21, /* KEY_F */ 0x22, /* KEY_G */
309 0x23, /* KEY_H */ 0x24, /* KEY_J */
310 0x25, /* KEY_K */ 0x26, /* KEY_L */
311 0x27, /* KEY_SemiColon */ 0x28, /* KEY_Quote */
312 0x29, /* KEY_Tilde */ 0x2a, /* KEY_ShiftL */
313 0x2b, /* KEY_BSlash */ 0x2c, /* KEY_Z */
314 0x2d, /* KEY_X */ 0x2e, /* KEY_C */
315 0x2f, /* KEY_V */ 0x30, /* KEY_B */
316 0x31, /* KEY_N */ 0x32, /* KEY_M */
317 0x33, /* KEY_Comma */ 0x34, /* KEY_Period */
318 0x35, /* KEY_Slash */ 0x36, /* KEY_ShiftR */
319 0x37, /* KEY_KP_Multiply */ 0x38, /* KEY_Alt */
320 0x39, /* KEY_Space */ 0x3a, /* KEY_CapsLock */
321 0x3b, /* KEY_F1 */ 0x3c, /* KEY_F2 */
322 0x3d, /* KEY_F3 */ 0x3e, /* KEY_F4 */
323 0x3f, /* KEY_F5 */ 0x40, /* KEY_F6 */
324 0x41, /* KEY_F7 */ 0x42, /* KEY_F8 */
325 0x43, /* KEY_F9 */ 0x44, /* KEY_F10 */
326 0x45, /* KEY_NumLock */ 0x46, /* KEY_ScrollLock */
327 0x47, /* KEY_KP_7 */ 0x48, /* KEY_KP_8 */
328 0x49, /* KEY_KP_9 */ 0x4a, /* KEY_KP_Minus */
329 0x4b, /* KEY_KP_4 */ 0x4c, /* KEY_KP_5 */
330 0x4d, /* KEY_KP_6 */ 0x4e, /* KEY_KP_Plus */
331 0x4f, /* KEY_KP_1 */ 0x50, /* KEY_KP_2 */
332 0x51, /* KEY_KP_3 */ 0x52, /* KEY_KP_0 */
333 0x53, /* KEY_KP_Decimal */ 0x54, /* KEY_SysReqest */
334 0x00, /* 0x55 */ 0x56, /* KEY_Less */
335 0x57, /* KEY_F11 */ 0x58, /* KEY_F12 */
336 0x66, /* KEY_Home */ 0x67, /* KEY_Up */
337 0x68, /* KEY_PgUp */ 0x69, /* KEY_Left */
338 0x5d, /* KEY_Begin */ 0x6a, /* KEY_Right */
339 0x6b, /* KEY_End */ 0x6c, /* KEY_Down */
340 0x6d, /* KEY_PgDown */ 0x6e, /* KEY_Insert */
341 0x6f, /* KEY_Delete */ 0x60, /* KEY_KP_Enter */
342 0x61, /* KEY_RCtrl */ 0x77, /* KEY_Pause */
343 0x63, /* KEY_Print */ 0x62, /* KEY_KP_Divide */
344 0x64, /* KEY_AltLang */ 0x65, /* KEY_Break */
345 0x00, /* KEY_LMeta */ 0x00, /* KEY_RMeta */
346 0x7A, /* KEY_Menu/FOCUS_PF11*/0x00, /* 0x6e */
347 0x7B, /* FOCUS_PF12 */ 0x00, /* 0x70 */
348 0x00, /* 0x71 */ 0x00, /* 0x72 */
349 0x59, /* FOCUS_PF2 */ 0x78, /* FOCUS_PF9 */
350 0x00, /* 0x75 */ 0x00, /* 0x76 */
351 0x5A, /* FOCUS_PF3 */ 0x5B, /* FOCUS_PF4 */
352 0x5C, /* FOCUS_PF5 */ 0x5D, /* FOCUS_PF6 */
353 0x5E, /* FOCUS_PF7 */ 0x5F, /* FOCUS_PF8 */
354 0x7C, /* JAP_86 */ 0x79, /* FOCUS_PF10 */
358 /** Create a private structure for use within this file. */
359 pointer
kbdLinuxCreatePrivate(DeviceIntPtr pKeyboard
)
361 myPrivate
*priv
= xalloc(sizeof(*priv
));
362 memset(priv
, 0, sizeof(*priv
));
364 priv
->pKeyboard
= pKeyboard
;
368 /** Destroy a private structure. */
369 void kbdLinuxDestroyPrivate(pointer priv
)
371 if (priv
) xfree(priv
);
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
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"). */
390 void kbdLinuxBell(DevicePtr pDev
, int percent
,
391 int volume
, int pitch
, int duration
)
395 if (duration
&& pitch
) {
398 ((1193190 / pitch
) & 0xffff) /* Low bits specify cycle time */
399 | (duration
<< 16)); /* High bits are duration in msec */
404 void kbdLinuxCtrl(DevicePtr pDev
, KeybdCtrl
*ctrl
)
408 ioctl(priv
->fd
, KDSETLED
, ctrl
->leds
& 0x07);
411 static int kbdLinuxGetFreeVTNumber(void)
416 const char *tty0
[] = { "/dev/tty0", "/dev/vc/0", NULL
};
418 for (i
= 0; tty0
[i
]; i
++)
419 if ((fd
= open(tty0
[i
], O_WRONLY
, 0)) >= 0) break;
421 FATAL1("kbdLinuxGetFreeVTNumber: Cannot open tty0 (%s)\n",
423 if (ioctl(fd
, VT_OPENQRY
, &vtno
) < 0 || vtno
< 0)
424 FATAL0("kbdLinuxGetFreeVTNumber: Cannot find a free VT\n");
428 static int kbdLinuxOpenVT(int vtno
)
432 const char *vcs
[] = { "/dev/vc/%d", "/dev/tty%d", NULL
};
433 char name
[64]; /* RATS: Only used in XmuSnprintf */
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;
440 FATAL2("kbdLinuxOpenVT: Cannot open VT %d (%s)\n",
441 vtno
, strerror(errno
));
445 static int kbdLinuxGetCurrentVTNumber(int fd
)
449 if (!ioctl(fd
, VT_GETSTATE
, &vts
)) return vts
.v_active
;
453 static int kbdLinuxActivate(int fd
, int vtno
, int setSig
);
455 /** Currently unused hook called prior to an VT switch. */
456 void kbdLinuxVTPreSwitch(pointer p
)
460 /** Currently unused hook called after returning from a VT switch. */
461 void kbdLinuxVTPostSwitch(pointer p
)
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
469 int kbdLinuxVTSwitch(pointer p
, int vt
,
470 void (*switch_return
)(pointer
),
471 pointer switch_return_data
)
475 if (priv
->switched
) FATAL0("kbdLinuxVTSwitch: already switched...\n");
476 if (priv
->vtno
== vt
) return 0;
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);
486 /* RATS: This function is only ever used to handle SIGUSR1. */
487 static void kbdLinuxVTSignalHandler(int sig
)
489 myPrivate
*priv
= PRIV
;
491 signal(sig
, kbdLinuxVTSignalHandler
);
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
);
502 static int kbdLinuxActivate(int fd
, int vtno
, int setSig
)
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");
512 SYSCALL(result
= ioctl(fd
, VT_GETMODE
, &VT
));
513 if (result
< 0) FATAL0("kbdLinuxActivate: VT_GETMODE failed\n");
514 VT
.mode
= VT_PROCESS
;
517 if (ioctl(fd
, VT_SETMODE
, &VT
))
518 FATAL0("kbdLinuxActivate: VT_SETMODE VT_PROCESS failed\n");
519 signal(SIGUSR1
, kbdLinuxVTSignalHandler
);
524 static void kbdLinuxOpenConsole(DevicePtr pDev
)
527 const char *msg
= MESSAGE
;
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
));
540 static void kbdLinuxCloseConsole(DevicePtr pDev
)
544 const char *msg
= FINALMESSAGE
;
546 if (priv
->fd
< 0) return;
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) {
552 ioctl(priv
->fd
, VT_SETMODE
, &VT
);
555 LOG1("kbdLinuxCloseConsole: switching to VT %d\n", priv
->vtcurrent
);
556 if (priv
->vtcurrent
>= 0) kbdLinuxActivate(priv
->fd
, priv
->vtcurrent
, 0);
562 /** Initialize the \a pDev as a Linux keyboard. */
563 void kbdLinuxInit(DevicePtr pDev
)
567 if (priv
->fd
<= 0) kbdLinuxOpenConsole(pDev
);
569 ioctl(priv
->fd
, KDGKBMODE
, &priv
->kbdtrans
);
570 if (tcgetattr(priv
->fd
, &priv
->kbdtty
) < 0)
571 FATAL1("kbdLinuxInit: tcgetattr failed (%s)\n", strerror(errno
));
574 static int kbdLinuxPrefix0Mapping(unsigned char *scanCode
)
576 /* Table from xfree86/common/xf86Events.c */
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;
605 * Ignore virtual shifts (E0 2A, E0 AA, E0 36, E0 B6)
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.
621 static int kbdLinuxPrefixMapping(myPrivate
*priv
, unsigned char *scanCode
)
623 int pressed
= *scanCode
& 0x80;
624 unsigned char code
= *scanCode
& 0x7f;
626 /* If we don't have a prefix, check for one */
634 return 0; /* No change */
637 /* We have a prefix from the last scanCode */
638 switch (priv
->prefix
) {
641 if (kbdLinuxPrefix0Mapping(&code
)) return 1; /* Skip sequence */
644 priv
->prefix
= (code
= KEY_LCtrl
) ? KEY_LCtrl
: 0;
645 return 1; /* Use new prefix */
648 if (code
!= KEY_NumLock
) return 1; /* Skip sequence*/
653 *scanCode
= code
| (pressed
? 0x80 : 0x00);
654 return 0; /* Use old scanCode */
657 static void kbdLinuxConvert(DevicePtr pDev
,
658 unsigned char scanCode
,
660 CHECKPROC checkspecial
,
664 KeySymsPtr pKeySyms
= &priv
->pKeyboard
->key
->curKeySyms
;
666 KeySym keySym
= NoSymbol
;
670 /* Do special PC/AT prefix mapping -- may change scanCode! */
671 if (kbdLinuxPrefixMapping(priv
, &scanCode
)) return;
673 type
= (scanCode
& 0x80) ? KeyRelease
: KeyPress
;
674 keyCode
= (scanCode
& 0x7f) + MIN_KEYCODE
;
678 if (keyCode
>= pKeySyms
->minKeyCode
&& keyCode
<= pKeySyms
->maxKeyCode
) {
679 keySym
= pKeySyms
->map
[(keyCode
- pKeySyms
->minKeyCode
)
680 * pKeySyms
->mapWidth
];
687 /* Ignore releases and all but first press */
688 if (kbdLinuxModIgnore(priv
, &xE
, keySym
)) return;
689 if (kbdLinuxKeyDown(priv
, &xE
)) xE
.u
.u
.type
= KeyRelease
;
690 else xE
.u
.u
.type
= KeyPress
;
695 /* If key is already down, ignore or autorepeat */
696 if (type
== KeyPress
&& kbdLinuxKeyDown(priv
, keyCode
)) {
697 KbdFeedbackClassRec
*feed
= priv
->pKeyboard
->kbdfeed
;
699 /* No auto-repeat? */
700 if ((feed
&& !feed
->ctrl
.autoRepeat
)
701 || priv
->pKeyboard
->key
->modifierMap
[keyCode
]
703 && !(feed
->ctrl
.autoRepeats
[keyCode
>> 3]
704 & (1 << (keyCode
& 7))))) return; /* Ignore */
707 enqueue(pDev
, KeyRelease
, keyCode
, keySym
, NULL
, block
);
711 /* If key is already up, ignore */
712 if (type
== KeyRelease
&& !kbdLinuxKeyDown(priv
, keyCode
)) return;
716 if (checkspecial
&& type
== KeyPress
)
717 switching
= checkspecial(pDev
, keySym
);
720 enqueue(pDev
, type
, keyCode
, keySym
, NULL
, block
);
721 kbdLinuxKeyState(priv
, type
, keyCode
); /* Update our state bitmap */
725 /** Read an event from the \a pDev device. If the event is a motion
726 * event, enqueue it with the \a motion function. Otherwise, check for
727 * special keys with the \a checkspecial function and enqueue the event
728 * with the \a enqueue function. The \a block type is passed to the
729 * functions so that they may block SIGIO handling as appropriate to the
730 * caller of this function. */
731 void kbdLinuxRead(DevicePtr pDev
,
734 CHECKPROC checkspecial
,
738 unsigned char buf
[256]; /* RATS: Only used in length-limited call */
742 while ((n
= read(priv
->fd
, buf
, sizeof(buf
))) > 0)
743 for (pt
= buf
; n
; --n
, ++pt
)
744 kbdLinuxConvert(pDev
, *pt
, enqueue
, checkspecial
, block
);
747 /** Turn \a pDev on (i.e., take input from \a pDev). */
748 int kbdLinuxOn(DevicePtr pDev
)
753 ioctl(priv
->fd
, KDSKBMODE
, K_RAW
);
756 nTty
.c_iflag
= (IGNPAR
| IGNBRK
) & (~PARMRK
) & (~ISTRIP
);
758 nTty
.c_cflag
= CREAD
| CS8
;
760 nTty
.c_cc
[VTIME
] = 0;
762 cfsetispeed(&nTty
, B9600
);
763 cfsetospeed(&nTty
, B9600
);
764 if (tcsetattr(priv
->fd
, TCSANOW
, &nTty
) < 0)
765 FATAL1("kbdLinuxOn: tcsetattr failed (%s)\n", strerror(errno
));
769 /** Turn \a pDev off (i.e., stop taking input from \a pDev). */
770 void kbdLinuxOff(DevicePtr pDev
)
774 ioctl(priv
->fd
, KDSKBMODE
, priv
->kbdtrans
);
775 tcsetattr(priv
->fd
, TCSANOW
, &priv
->kbdtty
);
776 kbdLinuxCloseConsole(pDev
);
780 static void kbdLinuxReadKernelMapping(int fd
, KeySymsPtr pKeySyms
)
785 static unsigned char tbl
[GLYPHS_PER_KEY
] = { /* RATS: Use ok */
788 0, /* modeswitch unshifted */
789 0 /* modeswitch shifted */
793 * Read the mapping from the kernel.
794 * Since we're still using the XFree86 scancode->AT keycode mapping
795 * routines, we need to convert the AT keycodes to Linux keycodes,
796 * then translate the Linux keysyms into X keysyms.
798 * First, figure out which tables to use for the modeswitch columns
799 * above, from the XF86Config fields.
801 tbl
[2] = 8; /* alt */
805 k
= map
+GLYPHS_PER_KEY
;
807 ErrorF("kbdLinuxReadKernelMapping() is broken/no-op'd\n");
812 for (i
= 0; i
< maxkey
; ++i
) {
816 kbe
.kb_index
= at2lnx
[i
];
818 for (j
= 0; j
< GLYPHS_PER_KEY
; ++j
, ++k
) {
823 kbe
.kb_table
= tbl
[j
];
824 if (kbe
.kb_index
== 0 || ioctl(fd
, KDGKBENT
, &kbe
)) continue;
826 kval
= KVAL(kbe
.kb_value
);
827 switch (KTYP(kbe
.kb_value
)) {
829 case KT_LETTER
: *k
= linux_to_x
[kval
]; break;
831 if (kval
<= 19) *k
= XK_F1
+ kval
;
832 else switch (kbe
.kb_value
) {
833 case K_FIND
: *k
= XK_Home
; /* or XK_Find */ break;
834 case K_INSERT
: *k
= XK_Insert
; break;
835 case K_REMOVE
: *k
= XK_Delete
; break;
836 case K_SELECT
: *k
= XK_End
; /* or XK_Select */ break;
837 case K_PGUP
: *k
= XK_Prior
; break;
838 case K_PGDN
: *k
= XK_Next
; break;
839 case K_HELP
: *k
= XK_Help
; break;
840 case K_DO
: *k
= XK_Execute
; break;
841 case K_PAUSE
: *k
= XK_Pause
; break;
842 case K_MACRO
: *k
= XK_Menu
; break;
847 switch (kbe
.kb_value
) {
848 case K_ENTER
: *k
= XK_Return
; break;
849 case K_BREAK
: *k
= XK_Break
; break;
850 case K_CAPS
: *k
= XK_Caps_Lock
; break;
851 case K_NUM
: *k
= XK_Num_Lock
; break;
852 case K_HOLD
: *k
= XK_Scroll_Lock
; break;
853 case K_COMPOSE
: *k
= XK_Multi_key
; break;
858 switch (kbe
.kb_value
) {
859 case K_PPLUS
: *k
= XK_KP_Add
; break;
860 case K_PMINUS
: *k
= XK_KP_Subtract
; break;
861 case K_PSTAR
: *k
= XK_KP_Multiply
; break;
862 case K_PSLASH
: *k
= XK_KP_Divide
; break;
863 case K_PENTER
: *k
= XK_KP_Enter
; break;
864 case K_PCOMMA
: *k
= XK_KP_Separator
; break;
865 case K_PDOT
: *k
= XK_KP_Decimal
; break;
866 case K_PPLUSMINUS
: *k
= XK_KP_Subtract
; break;
867 default: if (kval
<= 9) *k
= XK_KP_0
+ kval
; break;
871 /* KT_DEAD keys are for accelerated diacritical creation. */
872 switch (kbe
.kb_value
) {
873 case K_DGRAVE
: *k
= XK_dead_grave
; break;
874 case K_DACUTE
: *k
= XK_dead_acute
; break;
875 case K_DCIRCM
: *k
= XK_dead_circumflex
; break;
876 case K_DTILDE
: *k
= XK_dead_tilde
; break;
877 case K_DDIERE
: *k
= XK_dead_diaeresis
; break;
881 switch (kbe
.kb_value
) {
882 case K_DOWN
: *k
= XK_Down
; break;
883 case K_LEFT
: *k
= XK_Left
; break;
884 case K_RIGHT
: *k
= XK_Right
; break;
885 case K_UP
: *k
= XK_Up
; break;
889 switch (kbe
.kb_value
) {
890 case K_ALTGR
: *k
= XK_Alt_R
; break;
892 *k
= (kbe
.kb_index
== 0x64 ? XK_Alt_R
: XK_Alt_L
);
895 *k
= (kbe
.kb_index
== 0x61 ? XK_Control_R
: XK_Control_L
);
897 case K_CTRLL
: *k
= XK_Control_L
; break;
898 case K_CTRLR
: *k
= XK_Control_R
; break;
900 *k
= (kbe
.kb_index
== 0x36 ? XK_Shift_R
: XK_Shift_L
);
902 case K_SHIFTL
: *k
= XK_Shift_L
; break;
903 case K_SHIFTR
: *k
= XK_Shift_R
; break;
908 /* KT_ASCII keys accumulate a 3 digit decimal number that
909 * gets emitted when the shift state changes. We can't
914 if (kbe
.kb_value
== K_SHIFTLOCK
) *k
= XK_Shift_Lock
;
920 if (k
[-1] == k
[-2]) k
[-1] = NoSymbol
;
921 if (k
[-2] == k
[-3]) k
[-2] = NoSymbol
;
922 if (k
[-3] == k
[-4]) k
[-3] = NoSymbol
;
923 if (k
[-4] == k
[-2] && k
[-3] == k
[-1]) k
[-2] = k
[-1] = NoSymbol
;
924 if (k
[-1] == k
[-4] && k
[-2] == k
[-3]
925 && k
[-2] == NoSymbol
) k
[-1] = NoSymbol
;
929 static void kbdLinuxGetMap(DevicePtr pDev
, KeySymsPtr pKeySyms
, CARD8
*pModMap
)
937 mapCopy
= xalloc(sizeof(map
));
938 memcpy(mapCopy
, map
, sizeof(map
));
940 ErrorF("kbdLinuxGetMap() is broken/no-op'd\n");
944 kbdLinuxReadKernelMapping(priv
->fd
, pKeySyms
);
946 /* compute the modifier map */
947 for (i
= 0; i
< MAP_LENGTH
; i
++)
948 pModMap
[i
] = NoSymbol
; /* make sure it is restored */
950 for (k
= mapCopy
, i
= MIN_KEYCODE
;
951 i
< NUM_KEYCODES
+ MIN_KEYCODE
;
955 case XK_Shift_R
: pModMap
[i
] = ShiftMask
; break;
957 case XK_Control_R
: pModMap
[i
] = ControlMask
; break;
958 case XK_Caps_Lock
: pModMap
[i
] = LockMask
; break;
960 case XK_Alt_R
: pModMap
[i
] = AltMask
; break;
961 case XK_Num_Lock
: pModMap
[i
] = NumLockMask
; break;
962 case XK_Scroll_Lock
: pModMap
[i
] = ScrollLockMask
; break;
964 case XK_Kana_Shift
: pModMap
[i
] = KanaMask
; break;
965 case XK_Mode_switch
: pModMap
[i
] = AltLangMask
; break;
969 priv
->kbdType
= (ioctl(priv
->fd
, KDGKBTYPE
, &type
) < 0) ? KB_101
: type
;
971 pKeySyms
->map
= mapCopy
; /* Must be XFree'able */
972 pKeySyms
->mapWidth
= GLYPHS_PER_KEY
;
973 pKeySyms
->minKeyCode
= MIN_KEYCODE
;
974 pKeySyms
->maxKeyCode
= MAX_KEYCODE
;
977 /** Fill the \a info structure with information needed to initialize \a
979 void kbdLinuxGetInfo(DevicePtr pDev
, DMXLocalInitInfoPtr info
)
983 kbdLinuxGetMap(pDev
, &info
->keySyms
, info
->modMap
);
984 info
->focusClass
= 1;
985 info
->kbdFeedbackClass
= 1;