bsd_kbd.c revision 023e83d8
1 2/* 3 * Copyright (c) 2002 by The XFree86 Project, Inc. 4 * Author: Ivan Pascal. 5 * 6 * Based on the code from bsd_io.c which is 7 * Copyright 1992 by Rich Murphey <Rich@Rice.edu> 8 * Copyright 1993 by David Dawes <dawes@xfree86.org> 9 */ 10 11#ifdef HAVE_CONFIG_H 12#include "config.h" 13#endif 14 15#include <xorg-server.h> 16#include <X11/X.h> 17#include <termios.h> 18 19#include "compiler.h" 20 21#include "xf86.h" 22#include "xf86Priv.h" 23#include "xf86_OSlib.h" 24 25#include "xf86Xinput.h" 26#include "xf86OSKbd.h" 27#include "atKeynames.h" 28#include "bsd_kbd.h" 29 30static KbdProtocolRec protocols[] = { 31 {"standard", PROT_STD }, 32#ifdef WSCONS_SUPPORT 33 {"wskbd", PROT_WSCONS }, 34#endif 35 { NULL, PROT_UNKNOWN_KBD } 36}; 37 38typedef struct { 39 struct termios kbdtty; 40} BsdKbdPrivRec, *BsdKbdPrivPtr; 41 42static 43int KbdInit(InputInfoPtr pInfo, int what) 44{ 45 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 46 BsdKbdPrivPtr priv = (BsdKbdPrivPtr) pKbd->private; 47 48 if (pKbd->isConsole) { 49 switch (pKbd->consType) { 50#if defined(PCCONS_SUPPORT) || defined(SYSCONS_SUPPORT) || defined (PCVT_SUPPORT) || defined (WSCONS_SUPPORT) 51 case PCCONS: 52 case SYSCONS: 53 case PCVT: 54#if defined WSCONS_SUPPORT 55 case WSCONS: 56#endif 57 tcgetattr(pInfo->fd, &(priv->kbdtty)); 58#endif 59 break; 60 } 61 } 62 63 return Success; 64} 65 66static void 67SetKbdLeds(InputInfoPtr pInfo, int leds) 68{ 69 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 70 int real_leds = 0; 71 72#ifdef LED_CAP 73 if (leds & XLED1) real_leds |= LED_CAP; 74#endif 75#ifdef LED_NUM 76 if (leds & XLED2) real_leds |= LED_NUM; 77#endif 78#ifdef LED_SCR 79 if (leds & XLED3) real_leds |= LED_SCR; 80 if (leds & XLED4) real_leds |= LED_SCR; 81#endif 82 83 switch (pKbd->consType) { 84 85#ifdef PCCONS_SUPPORT 86 case PCCONS: 87 break; 88#endif 89#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT) 90 case SYSCONS: 91 case PCVT: 92 ioctl(pInfo->fd, KDSETLED, real_leds); 93 break; 94#endif 95#if defined(WSCONS_SUPPORT) 96 case WSCONS: 97 ioctl(pInfo->fd, WSKBDIO_SETLEDS, &real_leds); 98 break; 99#endif 100 } 101} 102 103static int 104GetKbdLeds(InputInfoPtr pInfo) 105{ 106 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 107 int leds = 0, real_leds = 0; 108 109 switch (pKbd->consType) { 110 111#ifdef PCCONS_SUPPORT 112 case PCCONS: 113 break; 114#endif 115#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT) 116 case SYSCONS: 117 case PCVT: 118 ioctl(pInfo->fd, KDGETLED, &real_leds); 119 break; 120#endif 121#if defined(WSCONS_SUPPORT) 122 case WSCONS: 123 ioctl(pInfo->fd, WSKBDIO_GETLEDS, &real_leds); 124 break; 125#endif 126 } 127 128#ifdef LED_CAP 129 if (real_leds & LED_CAP) leds |= XLED1; 130#endif 131#ifdef LED_NUM 132 if (real_leds & LED_NUM) leds |= XLED2; 133#endif 134#ifdef LED_SCR 135 if (real_leds & LED_SCR) leds |= XLED3; 136#endif 137 138 return(leds); 139} 140 141static int 142KbdOn(InputInfoPtr pInfo, int what) 143{ 144 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 145#if defined(SYSCONS_SUPPORT) || defined(PCCONS_SUPPORT) || defined(PCVT_SUPPORT) || defined(WSCONS_SUPPORT) 146 BsdKbdPrivPtr priv = (BsdKbdPrivPtr) pKbd->private; 147 struct termios nTty; 148#endif 149#ifdef WSCONS_SUPPORT 150 int option; 151#endif 152 153 if (pKbd->isConsole) { 154 switch (pKbd->consType) { 155 156#if defined(SYSCONS_SUPPORT) || defined(PCCONS_SUPPORT) || defined(PCVT_SUPPORT) || defined(WSCONS_SUPPORT) 157 case SYSCONS: 158 case PCCONS: 159 case PCVT: 160#ifdef WSCONS_SUPPORT 161 case WSCONS: 162#endif 163 nTty = priv->kbdtty; 164 nTty.c_iflag = IGNPAR | IGNBRK; 165 nTty.c_oflag = 0; 166 nTty.c_cflag = CREAD | CS8; 167 nTty.c_lflag = 0; 168 nTty.c_cc[VTIME] = 0; 169 nTty.c_cc[VMIN] = 1; 170 cfsetispeed(&nTty, 9600); 171 cfsetospeed(&nTty, 9600); 172 if (tcsetattr(pInfo->fd, TCSANOW, &nTty) < 0) { 173 xf86Msg(X_ERROR, "KbdOn: tcsetattr: %s\n", 174 strerror(errno)); 175 } 176 break; 177#endif 178 } 179#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT) || defined (WSCONS_SUPPORT) 180 switch (pKbd->consType) { 181 case SYSCONS: 182 case PCVT: 183#ifdef K_CODE 184 if (pKbd->CustomKeycodes) 185 ioctl(pInfo->fd, KDSKBMODE, K_CODE); 186 else 187 ioctl(pInfo->fd, KDSKBMODE, K_RAW); 188#else 189 ioctl(pInfo->fd, KDSKBMODE, K_RAW); 190#endif 191 break; 192#ifdef WSCONS_SUPPORT 193 case WSCONS: 194 option = WSKBD_RAW; 195 if (ioctl(pInfo->fd, WSKBDIO_SETMODE, &option) == -1) { 196 FatalError("can't switch keyboard to raw mode. " 197 "Enable support for it in the kernel\n" 198 "or use for example:\n\n" 199 "Option \"Protocol\" \"wskbd\"\n" 200 "Option \"Device\" \"/dev/wskbd0\"\n" 201 "\nin your xorg.conf(5) file\n"); 202 } 203 break; 204#endif 205 } 206#endif 207 } else { 208 switch (pKbd->consType) { 209#ifdef WSCONS_SUPPORT 210 case WSCONS: 211 if ((pKbd->wsKbdDev[0] != 0) && (pInfo->fd == -1)) { 212 xf86Msg(X_INFO, "opening %s\n", pKbd->wsKbdDev); 213 pInfo->fd = open(pKbd->wsKbdDev, O_RDONLY | O_NONBLOCK | O_EXCL); 214#ifdef WSKBDIO_SETVERSION 215 int version = WSKBDIO_EVENT_VERSION; 216 if (ioctl(pInfo->fd, WSKBDIO_SETVERSION, &version) == -1) { 217 xf86Msg(X_WARNING, "%s: cannot set version\n", pInfo->name); 218 return FALSE; 219 } 220#endif 221 } 222 break; 223#endif 224 } 225 } 226 return Success; 227} 228 229static int 230KbdOff(InputInfoPtr pInfo, int what) 231{ 232 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 233 BsdKbdPrivPtr priv = (BsdKbdPrivPtr) pKbd->private; 234#ifdef WSCONS_SUPPORT 235 int option; 236#endif 237 238 if (pKbd->isConsole) { 239 switch (pKbd->consType) { 240#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT) 241 case SYSCONS: 242 case PCVT: 243 ioctl(pInfo->fd, KDSKBMODE, K_XLATE); 244 /* FALL THROUGH */ 245#endif 246#if defined(SYSCONS_SUPPORT) || defined(PCCONS_SUPPORT) || defined(PCVT_SUPPORT) 247 case PCCONS: 248 tcsetattr(pInfo->fd, TCSANOW, &(priv->kbdtty)); 249 break; 250#endif 251#ifdef WSCONS_SUPPORT 252 case WSCONS: 253 option = WSKBD_TRANSLATED; 254 ioctl(xf86Info.consoleFd, WSKBDIO_SETMODE, &option); 255 tcsetattr(pInfo->fd, TCSANOW, &(priv->kbdtty)); 256 break; 257#endif 258 } 259 } else { 260 switch (pKbd->consType) { 261#ifdef WSCONS_SUPPORT 262 case WSCONS: 263 if ((pKbd->wsKbdDev[0] != 0) && (pInfo->fd != -1)) { 264 xf86Msg(X_INFO, "closing %s\n", pKbd->wsKbdDev); 265 /* need to close the fd while we're gone */ 266 close(pInfo->fd); 267 pInfo->fd = -1; 268 } 269 break; 270#endif 271 } 272 } 273 return Success; 274} 275 276static void 277SoundBell(InputInfoPtr pInfo, int loudness, int pitch, int duration) 278{ 279 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 280#ifdef WSCONS_SUPPORT 281 struct wskbd_bell_data wsb; 282#endif 283 284 if (loudness && pitch) { 285 switch (pKbd->consType) { 286#ifdef PCCONS_SUPPORT 287 case PCCONS: 288 { int data[2]; 289 data[0] = pitch; 290 data[1] = (duration * loudness) / 50; 291 ioctl(pInfo->fd, CONSOLE_X_BELL, data); 292 break; 293 } 294#endif 295#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT) 296 case SYSCONS: 297 case PCVT: 298 ioctl(pInfo->fd, KDMKTONE, 299 ((1193190 / pitch) & 0xffff) | 300 (((unsigned long)duration*loudness/50)<<16)); 301 break; 302#endif 303#if defined (WSCONS_SUPPORT) 304 case WSCONS: 305 wsb.which = WSKBD_BELL_DOALL; 306 wsb.pitch = pitch; 307 wsb.period = duration; 308 wsb.volume = loudness; 309 ioctl(pInfo->fd, WSKBDIO_COMPLEXBELL, &wsb); 310 break; 311#endif 312 } 313 } 314} 315 316static void 317stdReadInput(InputInfoPtr pInfo) 318{ 319 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 320 unsigned char rBuf[64]; 321 int nBytes, i; 322 if ((nBytes = read( pInfo->fd, (char *)rBuf, sizeof(rBuf))) > 0) { 323 for (i = 0; i < nBytes; i++) 324 pKbd->PostEvent(pInfo, rBuf[i] & 0x7f, 325 rBuf[i] & 0x80 ? FALSE : TRUE); 326 } 327} 328 329#ifdef WSCONS_SUPPORT 330 331static void 332WSReadInput(InputInfoPtr pInfo) 333{ 334 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 335 struct wscons_event events[64]; 336 int type; 337 int blocked, n, i; 338 339 if ((n = read( pInfo->fd, events, sizeof(events))) > 0) { 340 n /= sizeof(struct wscons_event); 341 for (i = 0; i < n; i++) { 342 type = events[i].type; 343 if (type == WSCONS_EVENT_KEY_UP || type == WSCONS_EVENT_KEY_DOWN) { 344 /* It seems better to block SIGIO there */ 345 blocked = xf86BlockSIGIO(); 346 pKbd->PostEvent(pInfo, (unsigned int)(events[i].value), 347 type == WSCONS_EVENT_KEY_DOWN ? TRUE : FALSE); 348 xf86UnblockSIGIO(blocked); 349 } 350 } /* for */ 351 } 352} 353 354static void 355printWsType(const char *type, char *name) 356{ 357 xf86Msg(X_PROBED, "%s: Keyboard type: %s\n", name, type); 358} 359#endif 360 361static Bool 362OpenKeyboard(InputInfoPtr pInfo) 363{ 364 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 365 int i; 366 KbdProtocolId prot = PROT_UNKNOWN_KBD; 367 char *s; 368 369 s = xf86SetStrOption(pInfo->options, "Protocol", NULL); 370 for (i = 0; protocols[i].name; i++) { 371 if (xf86NameCmp(s, protocols[i].name) == 0) { 372 prot = protocols[i].id; 373 break; 374 } 375 } 376 377 switch (prot) { 378 case PROT_STD: 379 pInfo->read_input = stdReadInput; 380 break; 381#ifdef WSCONS_SUPPORT 382 case PROT_WSCONS: 383 pInfo->read_input = WSReadInput; 384 break; 385#endif 386 default: 387 xf86Msg(X_ERROR,"\"%s\" is not a valid keyboard protocol name\n", s); 388 free(s); 389 return FALSE; 390 } 391 free(s); 392 393 if (prot == PROT_WSCONS) { 394 s = xf86SetStrOption(pInfo->options, "Device", "/dev/wskbd"); 395 } else 396 s = xf86SetStrOption(pInfo->options, "Device", NULL); 397 398 if (s == NULL) { 399 pInfo->fd = xf86Info.consoleFd; 400 pKbd->isConsole = TRUE; 401 pKbd->consType = xf86Info.consType; 402 pKbd->wsKbdDev[0] = 0; 403 } else { 404 pInfo->fd = open(s, O_RDONLY | O_NONBLOCK | O_EXCL); 405 if (pInfo->fd == -1) { 406 xf86Msg(X_ERROR, "%s: cannot open \"%s\"\n", pInfo->name, s); 407 free(s); 408 return FALSE; 409 } 410 pKbd->isConsole = FALSE; 411 strncpy(pKbd->wsKbdDev, s, 256); 412 pKbd->consType = xf86Info.consType; 413 free(s); 414 } 415 416#ifdef WSCONS_SUPPORT 417 if( prot == PROT_WSCONS) { 418 pKbd->consType = WSCONS; 419#ifdef WSKBDIO_SETVERSION 420 int version = WSKBDIO_EVENT_VERSION; 421 if (ioctl(pInfo->fd, WSKBDIO_SETVERSION, &version) == -1) { 422 xf86Msg(X_WARNING, "%s: cannot set version\n", pInfo->name); 423 return FALSE; 424 } 425#endif 426 /* Find out keyboard type */ 427 if (ioctl(pInfo->fd, WSKBDIO_GTYPE, &(pKbd->wsKbdType)) == -1) { 428 xf86Msg(X_ERROR, "%s: cannot get keyboard type", pInfo->name); 429 close(pInfo->fd); 430 return FALSE; 431 } 432 /* If wsKbdType==0, no keyboard attached to the mux. Assume USB. */ 433 if (pKbd->wsKbdType == 0) { 434 xf86Msg(X_WARNING, "%s: No keyboard attached, assuming USB\n", 435 pInfo->name); 436 pKbd->wsKbdType = WSKBD_TYPE_USB; 437 } 438 switch (pKbd->wsKbdType) { 439 case WSKBD_TYPE_PC_XT: 440 printWsType("XT", pInfo->name); 441 break; 442 case WSKBD_TYPE_PC_AT: 443 printWsType("AT", pInfo->name); 444 break; 445 case WSKBD_TYPE_USB: 446 printWsType("USB", pInfo->name); 447 break; 448#ifdef WSKBD_TYPE_ADB 449 case WSKBD_TYPE_ADB: 450 printWsType("ADB", pInfo->name); 451 break; 452#endif 453#ifdef WSKBD_TYPE_LK201 454 case WSKBD_TYPE_LK201: 455 printWsType("LK201", pInfo->name); 456 break; 457#endif 458#ifdef WSKBD_TYPE_MAPLE 459 case WSKBD_TYPE_MAPLE: 460 printWsType("Maple", pInfo->name); 461 break; 462#endif 463#ifdef WSKBD_TYPE_SUN 464 case WSKBD_TYPE_SUN: 465 printWsType("Sun", pInfo->name); 466 break; 467#endif 468#ifdef WSKBD_TYPE_SUN5 469 case WSKBD_TYPE_SUN5: 470 printWsType("Sun5", pInfo->name); 471 break; 472#endif 473 default: 474 xf86Msg(X_WARNING, "%s: Unsupported wskbd type \"%d\"\n", 475 pInfo->name, pKbd->wsKbdType); 476 printWsType("Unknown wskbd", pInfo->name); 477 break; 478 } 479 } 480#endif 481 482#if 0 /* no more vtSwitchSupported in xf86-input-keyboard-1.6.0 */ 483#if defined (SYSCONS_SUPPORT) || defined (PCVT_SUPPORT) || defined (WSCONS_SUPPORT) 484 if ((pKbd->isConsole && 485 ((pKbd->consType == SYSCONS) || (pKbd->consType == PCVT))) || 486 (pKbd->consType == WSCONS)) 487 pKbd->vtSwitchSupported = TRUE; 488#endif 489#endif 490 491 return TRUE; 492} 493 494_X_EXPORT Bool 495xf86OSKbdPreInit(InputInfoPtr pInfo) 496{ 497 KbdDevPtr pKbd = pInfo->private; 498 499 pKbd->KbdInit = KbdInit; 500 pKbd->KbdOn = KbdOn; 501 pKbd->KbdOff = KbdOff; 502 pKbd->Bell = SoundBell; 503 pKbd->SetLeds = SetKbdLeds; 504 pKbd->GetLeds = GetKbdLeds; 505 pKbd->KbdGetMapping = KbdGetMapping; 506 507 pKbd->RemapScanCode = NULL; 508 509 pKbd->OpenKeyboard = OpenKeyboard; 510 511 pKbd->private = calloc(sizeof(BsdKbdPrivRec), 1); 512 if (pKbd->private == NULL) { 513 xf86Msg(X_ERROR,"can't allocate keyboard OS private data\n"); 514 return FALSE; 515 } 516 return TRUE; 517} 518