sun_kbd.c revision ee3138f1
1/* 2 * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany 3 * Copyright 1993 by David Dawes <dawes@XFree86.org> 4 * Copyright 1999 by David Holland <davidh@iquest.net) 5 * 6 * Permission to use, copy, modify, distribute, and sell this software and its 7 * documentation for any purpose is hereby granted without fee, provided that 8 * the above copyright notice appear in all copies and that both that copyright 9 * notice and this permission notice appear in supporting documentation, and 10 * that the names of Thomas Roell, David Dawes, and David Holland not be used 11 * in advertising or publicity pertaining to distribution of the software 12 * without specific, written prior permission. Thomas Roell, David Dawes, and 13 * David Holland make no representations about the suitability of this software 14 * for any purpose. It is provided "as is" without express or implied 15 * warranty. 16 * 17 * THOMAS ROELL, DAVID DAWES, AND DAVID HOLLAND DISCLAIM ALL WARRANTIES WITH 18 * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 19 * AND FITNESS. IN NO EVENT SHALL THOMAS ROELL, DAVID DAWES, OR DAVID HOLLAND 20 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 21 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 22 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 23 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 24 */ 25/* Copyright 2004-2007 Sun Microsystems, Inc. All rights reserved. 26 * 27 * Permission is hereby granted, free of charge, to any person obtaining a 28 * copy of this software and associated documentation files (the 29 * "Software"), to deal in the Software without restriction, including 30 * without limitation the rights to use, copy, modify, merge, publish, 31 * distribute, and/or sell copies of the Software, and to permit persons 32 * to whom the Software is furnished to do so, provided that the above 33 * copyright notice(s) and this permission notice appear in all copies of 34 * the Software and that both the above copyright notice(s) and this 35 * permission notice appear in supporting documentation. 36 * 37 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 38 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 39 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 40 * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 41 * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL 42 * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING 43 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 44 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 45 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 46 * 47 * Except as contained in this notice, the name of a copyright holder 48 * shall not be used in advertising or otherwise to promote the sale, use 49 * or other dealings in this Software without prior written authorization 50 * of the copyright holder. 51 */ 52 53#ifdef HAVE_CONFIG_H 54#include "config.h" 55#endif 56 57#include "xf86.h" 58#include "xf86Priv.h" 59#include "xf86_OSlib.h" 60#include "xf86OSKbd.h" 61#include "sun_kbd.h" 62 63#include <sys/stropts.h> 64#include <sys/vuid_event.h> 65#include <sys/kbd.h> 66 67static void 68sunKbdSetLeds(InputInfoPtr pInfo, int leds) 69{ 70 int i; 71 72 SYSCALL(i = ioctl(pInfo->fd, KIOCSLED, &leds)); 73 if (i < 0) { 74 xf86Msg(X_ERROR, "%s: Failed to set keyboard LED's: %s\n", 75 pInfo->name, strerror(errno)); 76 } 77} 78 79 80static int 81sunKbdGetLeds(InputInfoPtr pInfo) 82{ 83 int i, leds = 0; 84 85 SYSCALL(i = ioctl(pInfo->fd, KIOCGLED, &leds)); 86 if (i < 0) { 87 xf86Msg(X_ERROR, "%s: Failed to get keyboard LED's: %s\n", 88 pInfo->name, strerror(errno)); 89 } 90 return leds; 91} 92 93 94/* 95 * Save initial keyboard state. This is called at the start of each server 96 * generation. 97 */ 98static int 99KbdInit(InputInfoPtr pInfo, int what) 100{ 101 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 102 sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private; 103 pointer options = pInfo->options; 104 105 int ktype, klayout, i; 106 const char *ktype_name; 107 108 priv->otranslation = -1; 109 priv->odirect = -1; 110 111 if (options != NULL) { 112 priv->strmod = xf86SetStrOption(options, "StreamsModule", NULL); 113 } else { 114 priv->strmod = NULL; 115 } 116 117 if (priv->strmod) { 118 SYSCALL(i = ioctl(pInfo->fd, I_PUSH, priv->strmod)); 119 if (i < 0) { 120 xf86Msg(X_ERROR, 121 "%s: cannot push module '%s' onto keyboard device: %s\n", 122 pInfo->name, priv->strmod, strerror(errno)); 123 } 124 } 125 126 SYSCALL(i = ioctl(pInfo->fd, KIOCTYPE, &ktype)); 127 if (i < 0) { 128 xf86Msg(X_ERROR, "%s: Unable to determine keyboard type: %s\n", 129 pInfo->name, strerror(errno)); 130 return BadImplementation; 131 } 132 133 SYSCALL(i = ioctl(pInfo->fd, KIOCLAYOUT, &klayout)); 134 if (i < 0) { 135 xf86Msg(X_ERROR, "%s: Unable to determine keyboard layout: %s\n", 136 pInfo->name, strerror(errno)); 137 return BadImplementation; 138 } 139 140 switch (ktype) { 141 case KB_SUN3: 142 ktype_name = "Sun Type 3"; break; 143 case KB_SUN4: 144 ktype_name = "Sun Type 4/5/6"; break; 145 case KB_USB: 146 ktype_name = "USB"; break; 147 case KB_PC: 148 ktype_name = "PC"; break; 149 default: 150 ktype_name = "Unknown"; break; 151 } 152 153 xf86Msg(X_PROBED, "%s: Keyboard type: %s (%d)\n", 154 pInfo->name, ktype_name, ktype); 155 xf86Msg(X_PROBED, "%s: Keyboard layout: %d\n", pInfo->name, klayout); 156 157 priv->ktype = ktype; 158 priv->oleds = sunKbdGetLeds(pInfo); 159 160 return Success; 161} 162 163 164static int 165KbdOn(InputInfoPtr pInfo, int what) 166{ 167 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 168 sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private; 169 170 int ktrans, kdirect, i; 171 172 SYSCALL(i = ioctl(pInfo->fd, KIOCGDIRECT, &kdirect)); 173 if (i < 0) { 174 xf86Msg(X_ERROR, 175 "%s: Unable to determine keyboard direct setting: %s\n", 176 pInfo->name, strerror(errno)); 177 return BadImplementation; 178 } 179 180 priv->odirect = kdirect; 181 kdirect = 1; 182 183 SYSCALL(i = ioctl(pInfo->fd, KIOCSDIRECT, &kdirect)); 184 if (i < 0) { 185 xf86Msg(X_ERROR, "%s: Failed turning keyboard direct mode on: %s\n", 186 pInfo->name, strerror(errno)); 187 return BadImplementation; 188 } 189 190 /* Setup translation */ 191 192 SYSCALL(i = ioctl(pInfo->fd, KIOCGTRANS, &ktrans)); 193 if (i < 0) { 194 xf86Msg(X_ERROR, 195 "%s: Unable to determine keyboard translation mode: %s\n", 196 pInfo->name, strerror(errno)); 197 return BadImplementation; 198 } 199 200 priv->otranslation = ktrans; 201 ktrans = TR_UNTRANS_EVENT; 202 203 SYSCALL(i = ioctl(pInfo->fd, KIOCTRANS, &ktrans)); 204 if (i < 0) { 205 xf86Msg(X_ERROR, "%s: Failed setting keyboard translation mode: %s\n", 206 pInfo->name, strerror(errno)); 207 return BadImplementation; 208 } 209 210 return Success; 211} 212 213static int 214KbdOff(InputInfoPtr pInfo, int what) 215{ 216 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 217 sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private; 218 219 int i; 220 221 /* restore original state */ 222 223 sunKbdSetLeds(pInfo, priv->oleds); 224 225 if (priv->otranslation != -1) { 226 SYSCALL(i = ioctl(pInfo->fd, KIOCTRANS, &priv->otranslation)); 227 if (i < 0) { 228 xf86Msg(X_ERROR, 229 "%s: Unable to restore keyboard translation mode: %s\n", 230 pInfo->name, strerror(errno)); 231 return BadImplementation; 232 } 233 priv->otranslation = -1; 234 } 235 236 if (priv->odirect != -1) { 237 SYSCALL(i = ioctl(pInfo->fd, KIOCSDIRECT, &priv->odirect)); 238 if (i < 0) { 239 xf86Msg(X_ERROR, 240 "%s: Unable to restore keyboard direct setting: %s\n", 241 pInfo->name, strerror(errno)); 242 return BadImplementation; 243 } 244 priv->odirect = -1; 245 } 246 247 if (priv->strmod) { 248 SYSCALL(i = ioctl(pInfo->fd, I_POP, priv->strmod)); 249 if (i < 0) { 250 xf86Msg(X_WARNING, 251 "%s: cannot pop module '%s' off keyboard device: %s\n", 252 pInfo->name, priv->strmod, strerror(errno)); 253 } 254 } 255 256 return Success; 257} 258 259 260static void 261SoundKbdBell(InputInfoPtr pInfo, int loudness, int pitch, int duration) 262{ 263 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 264 sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private; 265 266 int kbdCmd, i; 267#ifdef KIOCMKTONE 268 int cycles; 269 int mktonevalue; 270#endif 271 272 if (loudness && pitch) 273 { 274#ifdef KIOCMKTONE 275 if (pitch == 0) 276 cycles = UINT16_MAX; 277 else if (pitch >= UINT16_MAX) 278 cycles = 0; 279 else { 280 cycles = (PIT_HZ + pitch / 2) / pitch; 281 if (cycles > UINT16_MAX) 282 cycles = UINT16_MAX; 283 } 284 285 mktonevalue = cycles | (((duration * loudness * 20) / 1000) << 16); 286 287 errno = 0; 288 SYSCALL(i = ioctl (pInfo->fd, KIOCMKTONE, mktonevalue)); 289 if (i == 0) 290 return; 291 292 if (errno != EINVAL) { 293 if (errno != EAGAIN) 294 xf86Msg(X_ERROR, "%s: Failed to activate bell: %s\n", 295 pInfo->name, strerror(errno)); 296 return; 297 } 298#endif 299 300 kbdCmd = KBD_CMD_BELL; 301 302 SYSCALL(i = ioctl (pInfo->fd, KIOCCMD, &kbdCmd)); 303 if (i < 0) { 304 xf86Msg(X_ERROR, "%s: Failed to activate bell: %s\n", 305 pInfo->name, strerror(errno)); 306 } 307 308 usleep(duration * loudness * 20); 309 310 kbdCmd = KBD_CMD_NOBELL; 311 SYSCALL(i = ioctl (pInfo->fd, KIOCCMD, &kbdCmd)); 312 if (i < 0) { 313 xf86Msg(X_ERROR, "%s: Failed to deactivate bell: %s\n", 314 pInfo->name, strerror(errno)); 315 } 316 } 317} 318 319static void 320SetKbdLeds(InputInfoPtr pInfo, int leds) 321{ 322 int real_leds = sunKbdGetLeds(pInfo); 323 324 real_leds &= ~(LED_CAPS_LOCK | LED_NUM_LOCK | LED_SCROLL_LOCK | LED_COMPOSE); 325 326 if (leds & XLED1) real_leds |= LED_CAPS_LOCK; 327 if (leds & XLED2) real_leds |= LED_NUM_LOCK; 328 if (leds & XLED3) real_leds |= LED_SCROLL_LOCK; 329 if (leds & XLED4) real_leds |= LED_COMPOSE; 330 331 sunKbdSetLeds(pInfo, real_leds); 332} 333 334static int 335GetKbdLeds(InputInfoPtr pInfo) 336{ 337 int leds = 0; 338 int real_leds = sunKbdGetLeds(pInfo); 339 340 if (real_leds & LED_CAPS_LOCK) leds |= XLED1; 341 if (real_leds & LED_NUM_LOCK) leds |= XLED2; 342 if (real_leds & LED_SCROLL_LOCK) leds |= XLED3; 343 if (real_leds & LED_COMPOSE) leds |= XLED4; 344 345 return leds; 346} 347 348/* ARGSUSED0 */ 349static void 350SetKbdRepeat(InputInfoPtr pInfo, char rad) 351{ 352 /* Nothing to do */ 353} 354 355static void 356ReadInput(InputInfoPtr pInfo) 357{ 358 KbdDevPtr pKbd = (KbdDevPtr) pInfo->private; 359 Firm_event event[64]; 360 int nBytes, i; 361 362 /* I certainly hope its not possible to read partial events */ 363 364 if ((nBytes = read(pInfo->fd, (char *)event, sizeof(event))) > 0) 365 { 366 for (i = 0; i < (nBytes / sizeof(Firm_event)); i++) { 367 pKbd->PostEvent(pInfo, event[i].id & 0xFF, 368 event[i].value == VKEY_DOWN ? TRUE : FALSE); 369 } 370 } 371} 372 373static Bool 374OpenKeyboard(InputInfoPtr pInfo) 375{ 376 const char *kbdPath = NULL; 377 const char *defaultKbd = "/dev/kbd"; 378 379 if (pInfo->options != NULL) { 380 kbdPath = xf86SetStrOption(pInfo->options, "Device", NULL); 381 } 382 if (kbdPath == NULL) { 383 kbdPath = defaultKbd; 384 } 385 386 pInfo->fd = open(kbdPath, O_RDONLY | O_NONBLOCK); 387 388 if (pInfo->fd == -1) { 389 xf86Msg(X_ERROR, "%s: cannot open \"%s\"\n", pInfo->name, kbdPath); 390 } else { 391 xf86MsgVerb(X_INFO, 3, "%s: Opened device \"%s\"\n", pInfo->name, 392 kbdPath); 393 } 394 395 if ((kbdPath != NULL) && (kbdPath != defaultKbd)) { 396 xfree(kbdPath); 397 } 398 399 if (pInfo->fd == -1) { 400 return FALSE; 401 } else { 402 pInfo->read_input = ReadInput; 403 return TRUE; 404 } 405} 406 407_X_EXPORT Bool 408xf86OSKbdPreInit(InputInfoPtr pInfo) 409{ 410 KbdDevPtr pKbd = pInfo->private; 411 412 pKbd->KbdInit = KbdInit; 413 pKbd->KbdOn = KbdOn; 414 pKbd->KbdOff = KbdOff; 415 pKbd->Bell = SoundKbdBell; 416 pKbd->SetLeds = SetKbdLeds; 417 pKbd->GetLeds = GetKbdLeds; 418 pKbd->SetKbdRepeat = SetKbdRepeat; 419 pKbd->KbdGetMapping = KbdGetMapping; 420 421 pKbd->RemapScanCode = NULL; 422 pKbd->GetSpecialKey = NULL; 423 pKbd->SpecialKey = NULL; 424 425 pKbd->OpenKeyboard = OpenKeyboard; 426 427 pKbd->vtSwitchSupported = FALSE; 428 pKbd->CustomKeycodes = FALSE; 429 430 pKbd->private = xcalloc(sizeof(sunKbdPrivRec), 1); 431 if (pKbd->private == NULL) { 432 xf86Msg(X_ERROR,"can't allocate keyboard OS private data\n"); 433 return FALSE; 434 } else { 435 sunKbdPrivPtr priv = (sunKbdPrivPtr) pKbd->private; 436 priv->otranslation = -1; 437 priv->odirect = -1; 438 } 439 440 return TRUE; 441} 442