1/*
2 * Copyright (c) 2002 by The XFree86 Project, Inc.
3 * Author: Ivan Pascal.
4 *
5 * Based on the code from
6 * xf86Config.c which is
7 * Copyright 1991-2002 by The XFree86 Project, Inc.
8 * Copyright 1997 by Metro Link, Inc.
9 * xf86Events.c and xf86Io.c which are
10 * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
11 */
12
13#ifdef HAVE_CONFIG_H
14#include "config.h"
15#endif
16
17#include <stdio.h>
18#include <string.h>
19#include <stdlib.h>
20#include <unistd.h>
21#include <xorg-server.h>
22
23#include <X11/X.h>
24#include <X11/Xproto.h>
25
26#include "xf86.h"
27#include "atKeynames.h"
28#include "xf86Privstr.h"
29
30#include <X11/extensions/XI.h>
31#include <X11/extensions/XIproto.h>
32#include "extnsionst.h"
33#include "extinit.h"
34#include "inputstr.h"
35
36#include "xf86Xinput.h"
37#include "xf86_OSproc.h"
38#include "xf86OSKbd.h"
39#include "compiler.h"
40
41#include "exevents.h"
42#include <X11/Xatom.h>
43#include "xserver-properties.h"
44
45#include "xkbstr.h"
46#include "xkbsrv.h"
47
48#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 23
49#define HAVE_THREADED_INPUT	1
50#endif
51
52#define CAPSFLAG	1
53#define NUMFLAG		2
54#define SCROLLFLAG	4
55#define MODEFLAG	8
56#define COMPOSEFLAG	16
57/* Used to know when the first DEVICE_ON after a DEVICE_INIT is called */
58#define INITFLAG	(1U << 31)
59
60static int KbdPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags);
61static int KbdProc(DeviceIntPtr device, int what);
62static void KbdCtrl(DeviceIntPtr device, KeybdCtrl *ctrl);
63static void KbdBell(int percent, DeviceIntPtr dev, pointer ctrl, int unused);
64static void PostKbdEvent(InputInfoPtr pInfo, unsigned int key, Bool down);
65
66static void InitKBD(InputInfoPtr pInfo, Bool init);
67static void UpdateLeds(InputInfoPtr pInfo);
68
69static const char *kbdDefaults[] = {
70#ifdef __NetBSD__
71#ifdef DEFAULT_TO_WSKBD
72    "Protocol",		"wskbd",
73#else
74    "Protocol",		"standard",
75#endif
76#else /* NetBSD */
77    "Protocol",		"standard",
78#endif /* NetBSD */
79    "XkbRules",		"base",
80    "XkbModel",		"pc105",
81    "XkbLayout",	"us",
82    NULL
83};
84
85static char *xkb_rules;
86static char *xkb_model;
87static char *xkb_layout;
88static char *xkb_variant;
89static char *xkb_options;
90
91_X_EXPORT InputDriverRec KBD = {
92    1,
93    "kbd",
94    NULL,
95    KbdPreInit,
96    NULL,
97    NULL
98};
99
100_X_EXPORT InputDriverRec KEYBOARD = {
101    1,
102    "keyboard",
103    NULL,
104    KbdPreInit,
105    NULL,
106    NULL
107};
108
109static XF86ModuleVersionInfo xf86KbdVersionRec = {
110    "kbd",
111    MODULEVENDORSTRING,
112    MODINFOSTRING1,
113    MODINFOSTRING2,
114    XORG_VERSION_CURRENT,
115    PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, PACKAGE_VERSION_PATCHLEVEL,
116    ABI_CLASS_XINPUT,
117    ABI_XINPUT_VERSION,
118    MOD_CLASS_XINPUT,
119    {0, 0, 0, 0}
120};
121
122static pointer
123xf86KbdPlug(pointer module, pointer options, int *errmaj, int *errmin)
124{
125    xf86AddInputDriver(&KBD, module, 0);
126    return module;
127}
128
129_X_EXPORT XF86ModuleData kbdModuleData = {
130    &xf86KbdVersionRec,
131    xf86KbdPlug,
132    NULL
133};
134
135static int
136KbdPreInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
137{
138    KbdDevPtr pKbd;
139    char *s;
140    const char **defaults;
141    int rc = Success;
142
143    /* Initialise the InputInfoRec. */
144    pInfo->type_name = XI_KEYBOARD;
145    pInfo->device_control = KbdProc;
146    /*
147     * We don't specify our own read_input function. We expect
148     * an OS specific readInput() function to handle this.
149     */
150    pInfo->read_input = NULL;
151    pInfo->control_proc = NULL;
152    pInfo->switch_mode = NULL;
153    pInfo->fd = -1;
154    pInfo->dev = NULL;
155
156    defaults = kbdDefaults;
157    xf86CollectInputOptions(pInfo, defaults);
158    xf86ProcessCommonOptions(pInfo, pInfo->options);
159
160    if (!(pKbd = calloc(sizeof(KbdDevRec), 1))) {
161        rc = BadAlloc;
162        goto out;
163    }
164
165    pInfo->private = pKbd;
166    pKbd->PostEvent = PostKbdEvent;
167
168    if (!xf86OSKbdPreInit(pInfo)) {
169        rc = BadAlloc;
170        goto out;
171    }
172
173    if (!pKbd->OpenKeyboard(pInfo)) {
174        rc = BadMatch;
175        goto out;
176    }
177
178    if ((s = xf86SetStrOption(pInfo->options, "XLeds", NULL))) {
179        char *l, *end;
180        unsigned int i;
181        l = strtok(s, " \t\n");
182        while (l) {
183    	    i = strtoul(l, &end, 0);
184    	    if (*end == '\0')
185    	        pKbd->xledsMask |= 1L << (i - 1);
186    	    else {
187    	        xf86Msg(X_ERROR, "\"%s\" is not a valid XLeds value", l);
188    	    }
189    	    l = strtok(NULL, " \t\n");
190        }
191        free(s);
192    }
193
194    xkb_rules = xf86SetStrOption(pInfo->options, "XkbRules", NULL);
195    xkb_model = xf86SetStrOption(pInfo->options, "XkbModel", NULL);
196    xkb_layout = xf86SetStrOption(pInfo->options, "XkbLayout", NULL);
197    xkb_variant = xf86SetStrOption(pInfo->options, "XkbVariant", NULL);
198    xkb_options = xf86SetStrOption(pInfo->options, "XkbOptions", NULL);
199
200    pKbd->CustomKeycodes = xf86SetBoolOption(pInfo->options, "CustomKeycodes",
201                                             FALSE);
202
203out:
204  return rc;
205}
206
207static void
208KbdBell(int percent, DeviceIntPtr dev, pointer ctrl, int unused)
209{
210   InputInfoPtr pInfo = (InputInfoPtr) dev->public.devicePrivate;
211   KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
212   pKbd->Bell(pInfo, percent, ((KeybdCtrl*) ctrl)->bell_pitch,
213                              ((KeybdCtrl*) ctrl)->bell_duration);
214}
215
216static void
217UpdateLeds(InputInfoPtr pInfo)
218{
219    KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
220    unsigned long leds = 0;
221
222    if (pKbd->keyLeds & CAPSFLAG)    leds |= XLED1;
223    if (pKbd->keyLeds & NUMFLAG)     leds |= XLED2;
224    if (pKbd->keyLeds & SCROLLFLAG ||
225        pKbd->keyLeds & MODEFLAG)    leds |= XLED3;
226    if (pKbd->keyLeds & COMPOSEFLAG) leds |= XLED4;
227
228    pKbd->leds = (pKbd->leds & pKbd->xledsMask) | (leds & ~pKbd->xledsMask);
229    pKbd->SetLeds(pInfo, pKbd->leds);
230}
231
232static void
233KbdCtrl( DeviceIntPtr device, KeybdCtrl *ctrl)
234{
235   unsigned long leds;
236   InputInfoPtr pInfo = (InputInfoPtr) device->public.devicePrivate;
237   KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
238
239   if ( ctrl->leds & XLED1) {
240       pKbd->keyLeds |= CAPSFLAG;
241   } else {
242       pKbd->keyLeds &= ~CAPSFLAG;
243   }
244   if ( ctrl->leds & XLED2) {
245       pKbd->keyLeds |= NUMFLAG;
246   } else {
247       pKbd->keyLeds &= ~NUMFLAG;
248   }
249   if ( ctrl->leds & XLED3) {
250       pKbd->keyLeds |= SCROLLFLAG;
251   } else {
252       pKbd->keyLeds &= ~SCROLLFLAG;
253   }
254   if ( ctrl->leds & (XCOMP|XLED4) ) {
255       pKbd->keyLeds |= COMPOSEFLAG;
256   } else {
257       pKbd->keyLeds &= ~COMPOSEFLAG;
258   }
259   leds = ctrl->leds & ~(XCAPS | XNUM | XSCR); /* ??? */
260   pKbd->leds = leds;
261  pKbd->SetLeds(pInfo, pKbd->leds);
262}
263
264static void
265InitKBD(InputInfoPtr pInfo, Bool init)
266{
267  KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
268
269  pKbd->scanPrefix      = 0;
270
271  if (init) {
272      pKbd->keyLeds = pKbd->GetLeds(pInfo);
273      UpdateLeds(pInfo);
274      pKbd->keyLeds |= INITFLAG;
275  } else {
276      unsigned long leds = pKbd->keyLeds;
277
278      pKbd->keyLeds = pKbd->GetLeds(pInfo);
279      UpdateLeds(pInfo);
280      if ((pKbd->keyLeds & CAPSFLAG) !=
281	  ((leds & INITFLAG) ? 0 : (leds & CAPSFLAG))) {
282	  pKbd->PostEvent(pInfo, KEY_CapsLock, TRUE);
283	  pKbd->PostEvent(pInfo, KEY_CapsLock, FALSE);
284      }
285      if ((pKbd->keyLeds & NUMFLAG) !=
286	  (leds & INITFLAG ? 0 : leds & NUMFLAG)) {
287	  pKbd->PostEvent(pInfo, KEY_NumLock, TRUE);
288	  pKbd->PostEvent(pInfo, KEY_NumLock, FALSE);
289      }
290  }
291}
292
293static int
294KbdProc(DeviceIntPtr device, int what)
295{
296
297  InputInfoPtr pInfo = device->public.devicePrivate;
298  KbdDevPtr pKbd = (KbdDevPtr) pInfo->private;
299  XkbRMLVOSet rmlvo;
300  KeySymsRec           keySyms;
301  CARD8                modMap[MAP_LENGTH];
302  int                  ret;
303
304  switch (what) {
305     case DEVICE_INIT:
306         ret = pKbd->KbdInit(pInfo, what);
307         if (ret != Success)
308             return ret;
309
310         pKbd->KbdGetMapping(pInfo, &keySyms, modMap);
311
312         device->public.on = FALSE;
313#ifdef USE_WSKBD_GETMAP
314         /* Use keySyms from device dependent ioctl rather than complex XKB */
315         rmlvo.rules = "base";
316         rmlvo.model = "empty";
317         rmlvo.layout = xkb_layout;
318         rmlvo.variant = xkb_variant;
319         rmlvo.options = xkb_options;
320
321         XkbSetRulesDflts(&rmlvo);
322         if (!InitKeyboardDeviceStruct(device, NULL, KbdBell, KbdCtrl))
323         {
324             xf86Msg(X_ERROR, "%s: Keyboard initialization failed. This "
325                     "could be a missing or incorrect setup of "
326                     "xkeyboard-config.\n", device->name);
327
328             return BadValue;
329         }
330         /* Apply device dependent keySyms over "empty" XKB settings */
331         XkbApplyMappingChange(device, &keySyms,
332           keySyms.minKeyCode,
333           keySyms.maxKeyCode - keySyms.minKeyCode + 1,
334           modMap, serverClient);
335#else
336         rmlvo.rules = xkb_rules;
337         rmlvo.model = xkb_model;
338         rmlvo.layout = xkb_layout;
339         rmlvo.variant = xkb_variant;
340         rmlvo.options = xkb_options;
341
342         if (!InitKeyboardDeviceStruct(device, &rmlvo, KbdBell, KbdCtrl))
343         {
344             xf86Msg(X_ERROR, "%s: Keyboard initialization failed. This "
345                     "could be a missing or incorrect setup of "
346                     "xkeyboard-config.\n", device->name);
347
348             return BadValue;
349         }
350#endif /* USE_WSKBD_GETMAP */
351# ifdef XI_PROP_DEVICE_NODE
352         {
353             const char *device_node =
354                 xf86CheckStrOption(pInfo->options, "Device", NULL);
355
356             if (device_node)
357             {
358                 Atom prop_device = MakeAtom(XI_PROP_DEVICE_NODE,
359                                             strlen(XI_PROP_DEVICE_NODE), TRUE);
360                 XIChangeDeviceProperty(device, prop_device, XA_STRING, 8,
361                                        PropModeReplace, strlen(device_node),
362                                        device_node, FALSE);
363             }
364         }
365# endif /* XI_PROP_DEVICE_NODE */
366         InitKBD(pInfo, TRUE);
367         break;
368  case DEVICE_ON:
369    if (device->public.on)
370	break;
371    /*
372     * Set the keyboard into "direct" mode and turn on
373     * event translation.
374     */
375    if ((ret = pKbd->KbdOn(pInfo, what)) != Success)
376	return ret;
377    /*
378     * Discard any pending input after a VT switch to prevent the server
379     * passing on parts of the VT switch sequence.
380     */
381    if (pInfo->fd >= 0) {
382	xf86FlushInput(pInfo->fd);
383#if HAVE_THREADED_INPUT
384	xf86AddEnabledDevice(pInfo);
385#else
386	AddEnabledDevice(pInfo->fd);
387#endif
388    }
389
390    device->public.on = TRUE;
391    InitKBD(pInfo, FALSE);
392    break;
393
394  case DEVICE_CLOSE:
395  case DEVICE_OFF:
396
397    /*
398     * Restore original keyboard directness and translation.
399     */
400    if (pInfo->fd != -1) {
401#if HAVE_THREADED_INPUT
402      xf86RemoveEnabledDevice(pInfo);
403#else
404      RemoveEnabledDevice(pInfo->fd);
405#endif
406    }
407    pKbd->KbdOff(pInfo, what);
408    device->public.on = FALSE;
409    break;
410
411#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) * 100 + GET_ABI_MINOR(ABI_XINPUT_VERSION) >= 1901
412  case DEVICE_ABORT:
413    /*
414     * Restore original keyboard state even on crash.
415     */
416    pKbd->KbdOff(pInfo, what);
417    break;
418#endif
419
420  default:
421    return BadValue;
422  }
423  return (Success);
424}
425
426static void
427PostKbdEvent(InputInfoPtr pInfo, unsigned int scanCode, Bool down)
428{
429
430#ifndef USE_WSKBD_GETMAP
431  KbdDevPtr    pKbd = (KbdDevPtr) pInfo->private;
432#endif
433  DeviceIntPtr device = pInfo->dev;
434#ifndef USE_WSKBD_GETMAP
435  KeyClassRec  *keyc = device->key;
436  int state;
437#endif
438
439#ifdef DEBUG
440  LogMessageVerbSigSafe(X_INFO, -1, "kbd driver rec scancode: 0x%x %s\n", scanCode, down ? "down" : "up");
441#endif
442
443#ifndef USE_WSKBD_GETMAP /* this convertion is necessary only for pc105 XKB */
444  /*
445   * First do some special scancode remapping ...
446   */
447  if (pKbd->RemapScanCode != NULL) {
448     if (pKbd->RemapScanCode(pInfo, (int*) &scanCode))
449         return;
450  } else {
451     if (pKbd->scancodeMap != NULL) {
452         TransMapPtr map = pKbd->scancodeMap;
453         if (scanCode >= map->begin && scanCode < map->end)
454             scanCode = map->map[scanCode - map->begin];
455     }
456  }
457
458  /*
459   * PC keyboards generate separate key codes for
460   * Alt+Print and Control+Pause but in the X keyboard model
461   * they need to get the same key code as the base key on the same
462   * physical keyboard key.
463   */
464
465  state = XkbStateFieldFromRec(&keyc->xkbInfo->state);
466
467  if (((state & AltMask) == AltMask) && (scanCode == KEY_SysReqest))
468    scanCode = KEY_Print;
469  else if (scanCode == KEY_Break)
470    scanCode = KEY_Pause;
471#endif
472
473  xf86PostKeyboardEvent(device, scanCode + MIN_KEYCODE, down);
474}
475