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