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