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