Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / dmx / input / lnx-keyboard.c
CommitLineData
a09e091a
JB
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/* Private area for Linux-style keyboards. */
176typedef struct _myPrivate {
177 int fd;
178 int vtno;
179 int vtcurrent;
180 int kbdtrans;
181 struct termios kbdtty;
182 int kbdType;
183 CARD32 kbdState[NUM_STATE_ENTRIES];
184 DeviceIntPtr pKeyboard;
185 unsigned char prefix;
186
187 int switched;
188 SWITCHRETPROC switch_return;
189 void *switch_return_data;
190
191 /* For bell */
192 int pitch;
193 unsigned long duration;
194} myPrivate;
195
196static myPrivate *PRIV = NULL;
197
198#undef SYSCALL
199#define SYSCALL(call) while(((call) == -1) && (errno == EINTR))
200
201static int
202kbdLinuxKeyDown(myPrivate * priv, int keyCode)
203{
204 CARD8 byte = keyCode >> 5;
205 CARD32 bit = 1 << (keyCode & 0x1f);
206
207 if (byte > NUM_STATE_ENTRIES)
208 return 0;
209 return priv->kbdState[byte] & bit;
210}
211
212static void
213kbdLinuxKeyState(myPrivate * priv, int type, int keyCode)
214{
215 CARD8 byte = keyCode >> 5;
216 CARD32 bit = 1 << (keyCode & 0x1f);
217
218 if (byte > NUM_STATE_ENTRIES)
219 return;
220 if (type == KeyPress)
221 priv->kbdState[byte] |= bit;
222 else
223 priv->kbdState[byte] &= ~bit;
224}
225
226static KeySym linux_to_x[256] = {
227 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
228 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
229 XK_BackSpace, XK_Tab, XK_Linefeed, NoSymbol,
230 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
231 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
232 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
233 NoSymbol, NoSymbol, NoSymbol, XK_Escape,
234 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
235 XK_space, XK_exclam, XK_quotedbl, XK_numbersign,
236 XK_dollar, XK_percent, XK_ampersand, XK_apostrophe,
237 XK_parenleft, XK_parenright, XK_asterisk, XK_plus,
238 XK_comma, XK_minus, XK_period, XK_slash,
239 XK_0, XK_1, XK_2, XK_3,
240 XK_4, XK_5, XK_6, XK_7,
241 XK_8, XK_9, XK_colon, XK_semicolon,
242 XK_less, XK_equal, XK_greater, XK_question,
243 XK_at, XK_A, XK_B, XK_C,
244 XK_D, XK_E, XK_F, XK_G,
245 XK_H, XK_I, XK_J, XK_K,
246 XK_L, XK_M, XK_N, XK_O,
247 XK_P, XK_Q, XK_R, XK_S,
248 XK_T, XK_U, XK_V, XK_W,
249 XK_X, XK_Y, XK_Z, XK_bracketleft,
250 XK_backslash, XK_bracketright, XK_asciicircum, XK_underscore,
251 XK_grave, XK_a, XK_b, XK_c,
252 XK_d, XK_e, XK_f, XK_g,
253 XK_h, XK_i, XK_j, XK_k,
254 XK_l, XK_m, XK_n, XK_o,
255 XK_p, XK_q, XK_r, XK_s,
256 XK_t, XK_u, XK_v, XK_w,
257 XK_x, XK_y, XK_z, XK_braceleft,
258 XK_bar, XK_braceright, XK_asciitilde, XK_BackSpace,
259 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
260 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
261 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
262 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
263 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
264 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
265 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
266 NoSymbol, NoSymbol, NoSymbol, NoSymbol,
267 XK_nobreakspace, XK_exclamdown, XK_cent, XK_sterling,
268 XK_currency, XK_yen, XK_brokenbar, XK_section,
269 XK_diaeresis, XK_copyright, XK_ordfeminine, XK_guillemotleft,
270 XK_notsign, XK_hyphen, XK_registered, XK_macron,
271 XK_degree, XK_plusminus, XK_twosuperior, XK_threesuperior,
272 XK_acute, XK_mu, XK_paragraph, XK_periodcentered,
273 XK_cedilla, XK_onesuperior, XK_masculine, XK_guillemotright,
274 XK_onequarter, XK_onehalf, XK_threequarters, XK_questiondown,
275 XK_Agrave, XK_Aacute, XK_Acircumflex, XK_Atilde,
276 XK_Adiaeresis, XK_Aring, XK_AE, XK_Ccedilla,
277 XK_Egrave, XK_Eacute, XK_Ecircumflex, XK_Ediaeresis,
278 XK_Igrave, XK_Iacute, XK_Icircumflex, XK_Idiaeresis,
279 XK_ETH, XK_Ntilde, XK_Ograve, XK_Oacute,
280 XK_Ocircumflex, XK_Otilde, XK_Odiaeresis, XK_multiply,
281 XK_Ooblique, XK_Ugrave, XK_Uacute, XK_Ucircumflex,
282 XK_Udiaeresis, XK_Yacute, XK_THORN, XK_ssharp,
283 XK_agrave, XK_aacute, XK_acircumflex, XK_atilde,
284 XK_adiaeresis, XK_aring, XK_ae, XK_ccedilla,
285 XK_egrave, XK_eacute, XK_ecircumflex, XK_ediaeresis,
286 XK_igrave, XK_iacute, XK_icircumflex, XK_idiaeresis,
287 XK_eth, XK_ntilde, XK_ograve, XK_oacute,
288 XK_ocircumflex, XK_otilde, XK_odiaeresis, XK_division,
289 XK_oslash, XK_ugrave, XK_uacute, XK_ucircumflex,
290 XK_udiaeresis, XK_yacute, XK_thorn, XK_ydiaeresis
291};
292
293/*
294 * Maps the AT keycodes to Linux keycodes
295 */
296static unsigned char at2lnx[NUM_KEYCODES] = {
297 0x01, /* KEY_Escape */ 0x02, /* KEY_1 */
298 0x03, /* KEY_2 */ 0x04, /* KEY_3 */
299 0x05, /* KEY_4 */ 0x06, /* KEY_5 */
300 0x07, /* KEY_6 */ 0x08, /* KEY_7 */
301 0x09, /* KEY_8 */ 0x0a, /* KEY_9 */
302 0x0b, /* KEY_0 */ 0x0c, /* KEY_Minus */
303 0x0d, /* KEY_Equal */ 0x0e, /* KEY_BackSpace */
304 0x0f, /* KEY_Tab */ 0x10, /* KEY_Q */
305 0x11, /* KEY_W */ 0x12, /* KEY_E */
306 0x13, /* KEY_R */ 0x14, /* KEY_T */
307 0x15, /* KEY_Y */ 0x16, /* KEY_U */
308 0x17, /* KEY_I */ 0x18, /* KEY_O */
309 0x19, /* KEY_P */ 0x1a, /* KEY_LBrace */
310 0x1b, /* KEY_RBrace */ 0x1c, /* KEY_Enter */
311 0x1d, /* KEY_LCtrl */ 0x1e, /* KEY_A */
312 0x1f, /* KEY_S */ 0x20, /* KEY_D */
313 0x21, /* KEY_F */ 0x22, /* KEY_G */
314 0x23, /* KEY_H */ 0x24, /* KEY_J */
315 0x25, /* KEY_K */ 0x26, /* KEY_L */
316 0x27, /* KEY_SemiColon */ 0x28, /* KEY_Quote */
317 0x29, /* KEY_Tilde */ 0x2a, /* KEY_ShiftL */
318 0x2b, /* KEY_BSlash */ 0x2c, /* KEY_Z */
319 0x2d, /* KEY_X */ 0x2e, /* KEY_C */
320 0x2f, /* KEY_V */ 0x30, /* KEY_B */
321 0x31, /* KEY_N */ 0x32, /* KEY_M */
322 0x33, /* KEY_Comma */ 0x34, /* KEY_Period */
323 0x35, /* KEY_Slash */ 0x36, /* KEY_ShiftR */
324 0x37, /* KEY_KP_Multiply */ 0x38, /* KEY_Alt */
325 0x39, /* KEY_Space */ 0x3a, /* KEY_CapsLock */
326 0x3b, /* KEY_F1 */ 0x3c, /* KEY_F2 */
327 0x3d, /* KEY_F3 */ 0x3e, /* KEY_F4 */
328 0x3f, /* KEY_F5 */ 0x40, /* KEY_F6 */
329 0x41, /* KEY_F7 */ 0x42, /* KEY_F8 */
330 0x43, /* KEY_F9 */ 0x44, /* KEY_F10 */
331 0x45, /* KEY_NumLock */ 0x46, /* KEY_ScrollLock */
332 0x47, /* KEY_KP_7 */ 0x48, /* KEY_KP_8 */
333 0x49, /* KEY_KP_9 */ 0x4a, /* KEY_KP_Minus */
334 0x4b, /* KEY_KP_4 */ 0x4c, /* KEY_KP_5 */
335 0x4d, /* KEY_KP_6 */ 0x4e, /* KEY_KP_Plus */
336 0x4f, /* KEY_KP_1 */ 0x50, /* KEY_KP_2 */
337 0x51, /* KEY_KP_3 */ 0x52, /* KEY_KP_0 */
338 0x53, /* KEY_KP_Decimal */ 0x54, /* KEY_SysReqest */
339 0x00, /* 0x55 */ 0x56, /* KEY_Less */
340 0x57, /* KEY_F11 */ 0x58, /* KEY_F12 */
341 0x66, /* KEY_Home */ 0x67, /* KEY_Up */
342 0x68, /* KEY_PgUp */ 0x69, /* KEY_Left */
343 0x5d, /* KEY_Begin */ 0x6a, /* KEY_Right */
344 0x6b, /* KEY_End */ 0x6c, /* KEY_Down */
345 0x6d, /* KEY_PgDown */ 0x6e, /* KEY_Insert */
346 0x6f, /* KEY_Delete */ 0x60, /* KEY_KP_Enter */
347 0x61, /* KEY_RCtrl */ 0x77, /* KEY_Pause */
348 0x63, /* KEY_Print */ 0x62, /* KEY_KP_Divide */
349 0x64, /* KEY_AltLang */ 0x65, /* KEY_Break */
350 0x00, /* KEY_LMeta */ 0x00, /* KEY_RMeta */
351 0x7A, /* KEY_Menu/FOCUS_PF11 */ 0x00, /* 0x6e */
352 0x7B, /* FOCUS_PF12 */ 0x00, /* 0x70 */
353 0x00, /* 0x71 */ 0x00, /* 0x72 */
354 0x59, /* FOCUS_PF2 */ 0x78, /* FOCUS_PF9 */
355 0x00, /* 0x75 */ 0x00, /* 0x76 */
356 0x5A, /* FOCUS_PF3 */ 0x5B, /* FOCUS_PF4 */
357 0x5C, /* FOCUS_PF5 */ 0x5D, /* FOCUS_PF6 */
358 0x5E, /* FOCUS_PF7 */ 0x5F, /* FOCUS_PF8 */
359 0x7C, /* JAP_86 */ 0x79, /* FOCUS_PF10 */
360 0x00, /* 0x7f */
361};
362
363/** Create a private structure for use within this file. */
364pointer
365kbdLinuxCreatePrivate(DeviceIntPtr pKeyboard)
366{
367 myPrivate *priv = calloc(1, sizeof(*priv));
368
369 priv->fd = -1;
370 priv->pKeyboard = pKeyboard;
371 return priv;
372}
373
374/** Destroy a private structure. */
375void
376kbdLinuxDestroyPrivate(pointer priv)
377{
378 free(priv);
379}
380
381/** Ring the bell.
382 *
383 * Note: we completely ignore the \a volume, since Linux's ioctl()
384 * interface does not provide a way to control it. If it did, the XBell
385 * manpage tells how the actual volume is a function of the percent and
386 * the (base) volume.
387 *
388 * Note that most of the other PC-based bell drivers compute the
389 * duration for KDMKTONE as a function of the volume and the duration.
390 * For some drivers, the duration is only measured in mS if the volume
391 * is 50, and is scaled by the volume for other values. This seems
392 * confusing and possibly incorrect (the xset man page says that the
393 * bell will be "as closely as it can to the user's specifications" --
394 * if we ignore the volume and set the duration correctly, then we'll
395 * get one parameter "wrong" -- but if we use the volume to scale the
396 * duration, then we'll get both parameters "wrong"). */
397void
398kbdLinuxBell(DevicePtr pDev, int percent, int volume, int pitch, int duration)
399{
400 GETPRIV;
401
402 if (duration && pitch) {
403 ioctl(priv->fd, KDMKTONE, ((1193190 / pitch) & 0xffff) /* Low bits specify cycle time */
404 |(duration << 16)); /* High bits are duration in msec */
405 }
406}
407
408/** Set the LEDs. */
409void
410kbdLinuxCtrl(DevicePtr pDev, KeybdCtrl * ctrl)
411{
412 GETPRIV;
413
414 ioctl(priv->fd, KDSETLED, ctrl->leds & 0x07);
415}
416
417static int
418kbdLinuxGetFreeVTNumber(void)
419{
420 int fd = -1;
421 int vtno;
422 int i;
423 const char *tty0[] = { "/dev/tty0", "/dev/vc/0", NULL };
424
425 for (i = 0; tty0[i]; i++)
426 if ((fd = open(tty0[i], O_WRONLY, 0)) >= 0)
427 break;
428 if (fd < 0)
429 FATAL1("kbdLinuxGetFreeVTNumber: Cannot open tty0 (%s)\n",
430 strerror(errno));
431 if (ioctl(fd, VT_OPENQRY, &vtno) < 0 || vtno < 0)
432 FATAL0("kbdLinuxGetFreeVTNumber: Cannot find a free VT\n");
433 return vtno;
434}
435
436static int
437kbdLinuxOpenVT(int vtno)
438{
439 int fd = -1;
440 int i;
441 const char *vcs[] = { "/dev/vc/", "/dev/tty", NULL };
442 char name[64]; /* RATS: Only used in snprintf */
443
444 for (i = 0; vcs[i]; i++) {
445 snprintf(name, sizeof(name), "%s%d", vcs[i], vtno);
446 if ((fd = open(name, O_RDWR | O_NONBLOCK, 0)) >= 0)
447 break;
448 }
449 if (fd < 0)
450 FATAL2("kbdLinuxOpenVT: Cannot open VT %d (%s)\n",
451 vtno, strerror(errno));
452 return fd;
453}
454
455static int
456kbdLinuxGetCurrentVTNumber(int fd)
457{
458 struct vt_stat vts;
459
460 if (!ioctl(fd, VT_GETSTATE, &vts))
461 return vts.v_active;
462 return -1;
463}
464
465static int kbdLinuxActivate(int fd, int vtno, int setSig);
466
467/** Currently unused hook called prior to an VT switch. */
468void
469kbdLinuxVTPreSwitch(pointer p)
470{
471}
472
473/** Currently unused hook called after returning from a VT switch. */
474void
475kbdLinuxVTPostSwitch(pointer p)
476{
477}
478
479/** Tell the operating system to switch to \a vt. The \a switch_return
480 * function is called with the \a switch_return_data when the VT is
481 * switched back to the pre-switch VT (i.e., the user returns to the DMX
482 * session). */
483int
484kbdLinuxVTSwitch(pointer p, int vt,
485 void (*switch_return) (pointer), pointer switch_return_data)
486{
487 myPrivate *priv = p;
488
489 if (priv->switched)
490 FATAL0("kbdLinuxVTSwitch: already switched...\n");
491 if (priv->vtno == vt)
492 return 0;
493
494 PRIV = priv;
495 priv->switched = 0; /* Will switch to 1 in handler */
496 priv->switch_return = switch_return;
497 priv->switch_return_data = switch_return_data;
498 kbdLinuxActivate(priv->fd, vt, 0);
499 return 1;
500}
501
502/* RATS: This function is only ever used to handle SIGUSR1. */
503static void
504kbdLinuxVTSignalHandler(int sig)
505{
506 myPrivate *priv = PRIV;
507
508 signal(sig, kbdLinuxVTSignalHandler);
509 if (priv) {
510 ioctl(priv->fd, VT_RELDISP, VT_ACKACQ);
511 priv->switched = !priv->switched;
512 LOG2("kbdLinuxVTSignalHandler: got signal %d, switched = %d\n",
513 sig, priv->switched);
514 if (!priv->switched && priv->switch_return)
515 priv->switch_return(priv->switch_return_data);
516 }
517}
518
519static int
520kbdLinuxActivate(int fd, int vtno, int setSig)
521{
522 int result;
523 struct vt_mode VT;
524
525 SYSCALL(result = ioctl(fd, VT_ACTIVATE, vtno));
526 if (result)
527 FATAL0("kbdLinuxActivate: VT_ACTIVATE failed\n");
528 SYSCALL(result = ioctl(fd, VT_WAITACTIVE, vtno));
529 if (result)
530 FATAL0("kbdLinuxActivate: VT_WAITACTIVE failed\n");
531 if (setSig) {
532 SYSCALL(result = ioctl(fd, VT_GETMODE, &VT));
533 if (result < 0)
534 FATAL0("kbdLinuxActivate: VT_GETMODE failed\n");
535 VT.mode = VT_PROCESS;
536 VT.relsig = SIGUSR1;
537 VT.acqsig = SIGUSR1;
538 if (ioctl(fd, VT_SETMODE, &VT))
539 FATAL0("kbdLinuxActivate: VT_SETMODE VT_PROCESS failed\n");
540 signal(SIGUSR1, kbdLinuxVTSignalHandler);
541 }
542 return Success;
543}
544
545static void
546kbdLinuxOpenConsole(DevicePtr pDev)
547{
548 GETPRIV;
549 const char *msg = MESSAGE;
550
551 if (priv->fd >= 0)
552 return;
553 priv->vtno = kbdLinuxGetFreeVTNumber();
554 priv->fd = kbdLinuxOpenVT(priv->vtno);
555 priv->vtcurrent = kbdLinuxGetCurrentVTNumber(priv->fd);
556 LOG2("kbdLinuxOpenConsole: current VT %d; using free VT %d\n",
557 priv->vtcurrent, priv->vtno);
558 kbdLinuxActivate(priv->fd, priv->vtno, 1);
559 ioctl(priv->fd, KDSETMODE, KD_GRAPHICS); /* To turn off gpm */
560 if (msg)
561 write(priv->fd, msg, strlen(msg));
562}
563
564static void
565kbdLinuxCloseConsole(DevicePtr pDev)
566{
567 GETPRIV;
568 struct vt_mode VT;
569 const char *msg = FINALMESSAGE;
570
571 if (priv->fd < 0)
572 return;
573
574 ioctl(priv->fd, KDSETMODE, KD_TEXT);
575 if (msg)
576 write(priv->fd, msg, strlen(msg));
577 if (ioctl(priv->fd, VT_GETMODE, &VT) != -1) {
578 VT.mode = VT_AUTO;
579 ioctl(priv->fd, VT_SETMODE, &VT);
580 }
581
582 LOG1("kbdLinuxCloseConsole: switching to VT %d\n", priv->vtcurrent);
583 if (priv->vtcurrent >= 0)
584 kbdLinuxActivate(priv->fd, priv->vtcurrent, 0);
585
586 close(priv->fd);
587 priv->fd = -1;
588}
589
590/** Initialize the \a pDev as a Linux keyboard. */
591void
592kbdLinuxInit(DevicePtr pDev)
593{
594 GETPRIV;
595
596 if (priv->fd <= 0)
597 kbdLinuxOpenConsole(pDev);
598
599 ioctl(priv->fd, KDGKBMODE, &priv->kbdtrans);
600 if (tcgetattr(priv->fd, &priv->kbdtty) < 0)
601 FATAL1("kbdLinuxInit: tcgetattr failed (%s)\n", strerror(errno));
602}
603
604static int
605kbdLinuxPrefix0Mapping(unsigned char *scanCode)
606{
607 /* Table from xfree86/common/xf86Events.c */
608 switch (*scanCode) {
609 case KEY_KP_7:
610 *scanCode = KEY_Home;
611 break; /* curs home */
612 case KEY_KP_8:
613 *scanCode = KEY_Up;
614 break; /* curs up */
615 case KEY_KP_9:
616 *scanCode = KEY_PgUp;
617 break; /* curs pgup */
618 case KEY_KP_4:
619 *scanCode = KEY_Left;
620 break; /* curs left */
621 case KEY_KP_5:
622 *scanCode = KEY_Begin;
623 break; /* curs begin */
624 case KEY_KP_6:
625 *scanCode = KEY_Right;
626 break; /* curs right */
627 case KEY_KP_1:
628 *scanCode = KEY_End;
629 break; /* curs end */
630 case KEY_KP_2:
631 *scanCode = KEY_Down;
632 break; /* curs down */
633 case KEY_KP_3:
634 *scanCode = KEY_PgDown;
635 break; /* curs pgdown */
636 case KEY_KP_0:
637 *scanCode = KEY_Insert;
638 break; /* curs insert */
639 case KEY_KP_Decimal:
640 *scanCode = KEY_Delete;
641 break; /* curs delete */
642 case KEY_Enter:
643 *scanCode = KEY_KP_Enter;
644 break; /* keypad enter */
645 case KEY_LCtrl:
646 *scanCode = KEY_RCtrl;
647 break; /* right ctrl */
648 case KEY_KP_Multiply:
649 *scanCode = KEY_Print;
650 break; /* print */
651 case KEY_Slash:
652 *scanCode = KEY_KP_Divide;
653 break; /* keyp divide */
654 case KEY_Alt:
655 *scanCode = KEY_AltLang;
656 break; /* right alt */
657 case KEY_ScrollLock:
658 *scanCode = KEY_Break;
659 break; /* curs break */
660 case 0x5b:
661 *scanCode = KEY_LMeta;
662 break;
663 case 0x5c:
664 *scanCode = KEY_RMeta;
665 break;
666 case 0x5d:
667 *scanCode = KEY_Menu;
668 break;
669 case KEY_F3:
670 *scanCode = KEY_F13;
671 break;
672 case KEY_F4:
673 *scanCode = KEY_F14;
674 break;
675 case KEY_F5:
676 *scanCode = KEY_F15;
677 break;
678 case KEY_F6:
679 *scanCode = KEY_F16;
680 break;
681 case KEY_F7:
682 *scanCode = KEY_F17;
683 break;
684 case KEY_KP_Plus:
685 *scanCode = KEY_KP_DEC;
686 break;
687 /*
688 * Ignore virtual shifts (E0 2A, E0 AA, E0 36, E0 B6)
689 */
690 case 0x2A:
691 case 0x36:
692 return 1;
693 default:
694 /*
695 * "Internet" keyboards are generating lots of new codes.
696 * Let them pass. There is little consistency between them,
697 * so don't bother with symbolic names at this level.
698 */
699 scanCode += 0x78;
700 }
701 return 0;
702}
703
704static int
705kbdLinuxPrefixMapping(myPrivate * priv, unsigned char *scanCode)
706{
707 int pressed = *scanCode & 0x80;
708 unsigned char code = *scanCode & 0x7f;
709
710 /* If we don't have a prefix, check for one */
711 if (!priv->prefix) {
712 switch (code) {
713 case KEY_Prefix0:
714 case KEY_Prefix1:
715 priv->prefix = code;
716 return 1;
717 }
718 return 0; /* No change */
719 }
720
721 /* We have a prefix from the last scanCode */
722 switch (priv->prefix) {
723 case KEY_Prefix0:
724 priv->prefix = 0;
725 if (kbdLinuxPrefix0Mapping(&code))
726 return 1; /* Skip sequence */
727 break;
728 case KEY_Prefix1:
729 priv->prefix = (code = KEY_LCtrl) ? KEY_LCtrl : 0;
730 return 1; /* Use new prefix */
731 case KEY_LCtrl:
732 priv->prefix = 0;
733 if (code != KEY_NumLock)
734 return 1; /* Skip sequence */
735 code = KEY_Pause;
736 break;
737 }
738
739 *scanCode = code | (pressed ? 0x80 : 0x00);
740 return 0; /* Use old scanCode */
741}
742
743static void
744kbdLinuxConvert(DevicePtr pDev,
745 unsigned char scanCode,
746 ENQUEUEPROC enqueue, CHECKPROC checkspecial, BLOCK block)
747{
748 GETPRIV;
749 XkbSrvInfoPtr xkbi = priv->pKeyboard->key->xkbInfo;
750 int type;
751 KeySym keySym = NoSymbol;
752 int keyCode;
753 int switching;
754
755 /* Do special PC/AT prefix mapping -- may change scanCode! */
756 if (kbdLinuxPrefixMapping(priv, &scanCode))
757 return;
758
759 type = (scanCode & 0x80) ? KeyRelease : KeyPress;
760 keyCode = (scanCode & 0x7f) + MIN_KEYCODE;
761
762 /* Handle repeats */
763
764 if (keyCode >= xkbi->desc->min_key_code &&
765 keyCode <= xkbi->desc->max_key_code) {
766
767 int effectiveGroup = XkbGetEffectiveGroup(xkbi,
768 &xkbi->state,
769 scanCode);
770
771 keySym = XkbKeySym(xkbi->desc, scanCode, effectiveGroup);
772#if 0
773 switch (keySym) {
774 case XK_Num_Lock:
775 case XK_Scroll_Lock:
776 case XK_Shift_Lock:
777 case XK_Caps_Lock:
778 /* Ignore releases and all but first press */
779 if (kbdLinuxModIgnore(priv, &xE, keySym))
780 return;
781 if (kbdLinuxKeyDown(priv, &xE))
782 xE.u.u.type = KeyRelease;
783 else
784 xE.u.u.type = KeyPress;
785 break;
786 }
787#endif
788
789 /* If key is already down, ignore or autorepeat */
790 if (type == KeyPress && kbdLinuxKeyDown(priv, keyCode)) {
791 KbdFeedbackClassRec *feed = priv->pKeyboard->kbdfeed;
792
793 /* No auto-repeat? */
794 if ((feed && !feed->ctrl.autoRepeat)
795 || priv->pKeyboard->key->xkbInfo->desc->map->modmap[keyCode]
796 || (feed && !(feed->ctrl.autoRepeats[keyCode >> 3]
797 & (1 << (keyCode & 7)))))
798 return; /* Ignore */
799
800 /* Do auto-repeat */
801 enqueue(pDev, KeyRelease, keyCode, keySym, NULL, block);
802 type = KeyPress;
803 }
804
805 /* If key is already up, ignore */
806 if (type == KeyRelease && !kbdLinuxKeyDown(priv, keyCode))
807 return;
808 }
809
810 switching = 0;
811 if (checkspecial && type == KeyPress)
812 switching = checkspecial(pDev, keySym);
813 if (!switching) {
814 if (enqueue)
815 enqueue(pDev, type, keyCode, keySym, NULL, block);
816 kbdLinuxKeyState(priv, type, keyCode); /* Update our state bitmap */
817 }
818}
819
820/** Read an event from the \a pDev device. If the event is a motion
821 * event, enqueue it with the \a motion function. Otherwise, check for
822 * special keys with the \a checkspecial function and enqueue the event
823 * with the \a enqueue function. The \a block type is passed to the
824 * functions so that they may block SIGIO handling as appropriate to the
825 * caller of this function. */
826void
827kbdLinuxRead(DevicePtr pDev,
828 MOTIONPROC motion,
829 ENQUEUEPROC enqueue, CHECKPROC checkspecial, BLOCK block)
830{
831 GETPRIV;
832 unsigned char buf[256]; /* RATS: Only used in length-limited call */
833 unsigned char *pt;
834 int n;
835
836 while ((n = read(priv->fd, buf, sizeof(buf))) > 0)
837 for (pt = buf; n; --n, ++pt)
838 kbdLinuxConvert(pDev, *pt, enqueue, checkspecial, block);
839}
840
841/** Turn \a pDev on (i.e., take input from \a pDev). */
842int
843kbdLinuxOn(DevicePtr pDev)
844{
845 GETPRIV;
846 struct termios nTty;
847
848 ioctl(priv->fd, KDSKBMODE, K_RAW);
849
850 nTty = priv->kbdtty;
851 nTty.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP);
852 nTty.c_oflag = 0;
853 nTty.c_cflag = CREAD | CS8;
854 nTty.c_lflag = 0;
855 nTty.c_cc[VTIME] = 0;
856 nTty.c_cc[VMIN] = 1;
857 cfsetispeed(&nTty, B9600);
858 cfsetospeed(&nTty, B9600);
859 if (tcsetattr(priv->fd, TCSANOW, &nTty) < 0)
860 FATAL1("kbdLinuxOn: tcsetattr failed (%s)\n", strerror(errno));
861 return priv->fd;
862}
863
864/** Turn \a pDev off (i.e., stop taking input from \a pDev). */
865void
866kbdLinuxOff(DevicePtr pDev)
867{
868 GETPRIV;
869
870 ioctl(priv->fd, KDSKBMODE, priv->kbdtrans);
871 tcsetattr(priv->fd, TCSANOW, &priv->kbdtty);
872 kbdLinuxCloseConsole(pDev);
873}
874
875static void
876kbdLinuxReadKernelMapping(int fd, KeySymsPtr pKeySyms)
877{
878 KeySym *k;
879 int i;
880 int maxkey;
881
882 static unsigned char tbl[GLYPHS_PER_KEY] = { /* RATS: Use ok */
883 0, /* unshifted */
884 1, /* shifted */
885 0, /* modeswitch unshifted */
886 0 /* modeswitch shifted */
887 };
888
889 /*
890 * Read the mapping from the kernel.
891 * Since we're still using the XFree86 scancode->AT keycode mapping
892 * routines, we need to convert the AT keycodes to Linux keycodes,
893 * then translate the Linux keysyms into X keysyms.
894 *
895 * First, figure out which tables to use for the modeswitch columns
896 * above, from the XF86Config fields.
897 */
898 tbl[2] = 8; /* alt */
899 tbl[3] = tbl[2] | 1;
900
901#if 00 /*BP*/
902 k = map + GLYPHS_PER_KEY;
903#else
904 ErrorF("kbdLinuxReadKernelMapping() is broken/no-op'd\n");
905 return;
906#endif
907 maxkey = NUM_AT2LNX;
908
909 for (i = 0; i < maxkey; ++i) {
910 struct kbentry kbe;
911 int j;
912
913 kbe.kb_index = at2lnx[i];
914
915 for (j = 0; j < GLYPHS_PER_KEY; ++j, ++k) {
916 unsigned short kval;
917
918 *k = NoSymbol;
919
920 kbe.kb_table = tbl[j];
921 if (kbe.kb_index == 0 || ioctl(fd, KDGKBENT, &kbe))
922 continue;
923
924 kval = KVAL(kbe.kb_value);
925 switch (KTYP(kbe.kb_value)) {
926 case KT_LATIN:
927 case KT_LETTER:
928 *k = linux_to_x[kval];
929 break;
930 case KT_FN:
931 if (kval <= 19)
932 *k = XK_F1 + kval;
933 else
934 switch (kbe.kb_value) {
935 case K_FIND:
936 *k = XK_Home; /* or XK_Find */
937 break;
938 case K_INSERT:
939 *k = XK_Insert;
940 break;
941 case K_REMOVE:
942 *k = XK_Delete;
943 break;
944 case K_SELECT:
945 *k = XK_End; /* or XK_Select */
946 break;
947 case K_PGUP:
948 *k = XK_Prior;
949 break;
950 case K_PGDN:
951 *k = XK_Next;
952 break;
953 case K_HELP:
954 *k = XK_Help;
955 break;
956 case K_DO:
957 *k = XK_Execute;
958 break;
959 case K_PAUSE:
960 *k = XK_Pause;
961 break;
962 case K_MACRO:
963 *k = XK_Menu;
964 break;
965 default:
966 break;
967 }
968 break;
969 case KT_SPEC:
970 switch (kbe.kb_value) {
971 case K_ENTER:
972 *k = XK_Return;
973 break;
974 case K_BREAK:
975 *k = XK_Break;
976 break;
977 case K_CAPS:
978 *k = XK_Caps_Lock;
979 break;
980 case K_NUM:
981 *k = XK_Num_Lock;
982 break;
983 case K_HOLD:
984 *k = XK_Scroll_Lock;
985 break;
986 case K_COMPOSE:
987 *k = XK_Multi_key;
988 break;
989 default:
990 break;
991 }
992 break;
993 case KT_PAD:
994 switch (kbe.kb_value) {
995 case K_PPLUS:
996 *k = XK_KP_Add;
997 break;
998 case K_PMINUS:
999 *k = XK_KP_Subtract;
1000 break;
1001 case K_PSTAR:
1002 *k = XK_KP_Multiply;
1003 break;
1004 case K_PSLASH:
1005 *k = XK_KP_Divide;
1006 break;
1007 case K_PENTER:
1008 *k = XK_KP_Enter;
1009 break;
1010 case K_PCOMMA:
1011 *k = XK_KP_Separator;
1012 break;
1013 case K_PDOT:
1014 *k = XK_KP_Decimal;
1015 break;
1016 case K_PPLUSMINUS:
1017 *k = XK_KP_Subtract;
1018 break;
1019 default:
1020 if (kval <= 9)
1021 *k = XK_KP_0 + kval;
1022 break;
1023 }
1024 break;
1025 case KT_DEAD:
1026 /* KT_DEAD keys are for accelerated diacritical creation. */
1027 switch (kbe.kb_value) {
1028 case K_DGRAVE:
1029 *k = XK_dead_grave;
1030 break;
1031 case K_DACUTE:
1032 *k = XK_dead_acute;
1033 break;
1034 case K_DCIRCM:
1035 *k = XK_dead_circumflex;
1036 break;
1037 case K_DTILDE:
1038 *k = XK_dead_tilde;
1039 break;
1040 case K_DDIERE:
1041 *k = XK_dead_diaeresis;
1042 break;
1043 }
1044 break;
1045 case KT_CUR:
1046 switch (kbe.kb_value) {
1047 case K_DOWN:
1048 *k = XK_Down;
1049 break;
1050 case K_LEFT:
1051 *k = XK_Left;
1052 break;
1053 case K_RIGHT:
1054 *k = XK_Right;
1055 break;
1056 case K_UP:
1057 *k = XK_Up;
1058 break;
1059 }
1060 break;
1061 case KT_SHIFT:
1062 switch (kbe.kb_value) {
1063 case K_ALTGR:
1064 *k = XK_Alt_R;
1065 break;
1066 case K_ALT:
1067 *k = (kbe.kb_index == 0x64 ? XK_Alt_R : XK_Alt_L);
1068 break;
1069 case K_CTRL:
1070 *k = (kbe.kb_index == 0x61 ? XK_Control_R : XK_Control_L);
1071 break;
1072 case K_CTRLL:
1073 *k = XK_Control_L;
1074 break;
1075 case K_CTRLR:
1076 *k = XK_Control_R;
1077 break;
1078 case K_SHIFT:
1079 *k = (kbe.kb_index == 0x36 ? XK_Shift_R : XK_Shift_L);
1080 break;
1081 case K_SHIFTL:
1082 *k = XK_Shift_L;
1083 break;
1084 case K_SHIFTR:
1085 *k = XK_Shift_R;
1086 break;
1087 default:
1088 break;
1089 }
1090 break;
1091 case KT_ASCII:
1092 /* KT_ASCII keys accumulate a 3 digit decimal number that
1093 * gets emitted when the shift state changes. We can't
1094 * emulate that.
1095 */
1096 break;
1097 case KT_LOCK:
1098 if (kbe.kb_value == K_SHIFTLOCK)
1099 *k = XK_Shift_Lock;
1100 break;
1101 default:
1102 break;
1103 }
1104 }
1105
1106 if (k[-1] == k[-2])
1107 k[-1] = NoSymbol;
1108 if (k[-2] == k[-3])
1109 k[-2] = NoSymbol;
1110 if (k[-3] == k[-4])
1111 k[-3] = NoSymbol;
1112 if (k[-4] == k[-2] && k[-3] == k[-1])
1113 k[-2] = k[-1] = NoSymbol;
1114 if (k[-1] == k[-4] && k[-2] == k[-3]
1115 && k[-2] == NoSymbol)
1116 k[-1] = NoSymbol;
1117 }
1118}
1119
1120static void
1121kbdLinuxGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap)
1122{
1123 GETPRIV;
1124 KeySym *k, *mapCopy;
1125 char type;
1126 int i;
1127
1128#if 00 /*BP*/
1129 mapCopy = malloc(sizeof(map));
1130 memcpy(mapCopy, map, sizeof(map));
1131#else
1132 ErrorF("kbdLinuxGetMap() is broken/no-op'd\n");
1133 return;
1134#endif
1135
1136 kbdLinuxReadKernelMapping(priv->fd, pKeySyms);
1137
1138 /* compute the modifier map */
1139 for (i = 0; i < MAP_LENGTH; i++)
1140 pModMap[i] = NoSymbol; /* make sure it is restored */
1141
1142 for (k = mapCopy, i = MIN_KEYCODE;
1143 i < NUM_KEYCODES + MIN_KEYCODE; i++, k += 4) {
1144 switch (*k) {
1145 case XK_Shift_L:
1146 case XK_Shift_R:
1147 pModMap[i] = ShiftMask;
1148 break;
1149 case XK_Control_L:
1150 case XK_Control_R:
1151 pModMap[i] = ControlMask;
1152 break;
1153 case XK_Caps_Lock:
1154 pModMap[i] = LockMask;
1155 break;
1156 case XK_Alt_L:
1157 case XK_Alt_R:
1158 pModMap[i] = AltMask;
1159 break;
1160 case XK_Num_Lock:
1161 pModMap[i] = NumLockMask;
1162 break;
1163 case XK_Scroll_Lock:
1164 pModMap[i] = ScrollLockMask;
1165 break;
1166 case XK_Kana_Lock:
1167 case XK_Kana_Shift:
1168 pModMap[i] = KanaMask;
1169 break;
1170 case XK_Mode_switch:
1171 pModMap[i] = AltLangMask;
1172 break;
1173 }
1174 }
1175
1176 priv->kbdType = (ioctl(priv->fd, KDGKBTYPE, &type) < 0) ? KB_101 : type;
1177
1178 pKeySyms->map = mapCopy; /* Must be XFree'able */
1179 pKeySyms->mapWidth = GLYPHS_PER_KEY;
1180 pKeySyms->minKeyCode = MIN_KEYCODE;
1181 pKeySyms->maxKeyCode = MAX_KEYCODE;
1182}
1183
1184/** Fill the \a info structure with information needed to initialize \a
1185 * pDev. */
1186void
1187kbdLinuxGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info)
1188{
1189 info->keyboard = 1;
1190 info->keyClass = 1;
1191 kbdLinuxGetMap(pDev, &info->keySyms, info->modMap);
1192 info->focusClass = 1;
1193 info->kbdFeedbackClass = 1;
1194}