1 /* $NetBSD: kbdsun.c,v 1.1 2002/10/03 16:13:26 uwe Exp $ */ 2 /* NetBSD: kbd.c,v 1.29 2001/11/13 06:54:32 lukem Exp */ 3 4 /* 5 * Copyright (c) 1992, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This software was developed by the Computer Systems Engineering group 9 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 10 * contributed to Berkeley. 11 * 12 * All advertising materials mentioning features or use of this software 13 * must display the following acknowledgement: 14 * This product includes software developed by the University of 15 * California, Lawrence Berkeley Laboratory. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions 19 * are met: 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 2. Redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution. 25 * 3. All advertising materials mentioning features or use of this software 26 * must display the following acknowledgement: 27 * This product includes software developed by the University of 28 * California, Berkeley and its contributors. 29 * 4. Neither the name of the University nor the names of its contributors 30 * may be used to endorse or promote products derived from this software 31 * without specific prior written permission. 32 * 33 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 36 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 37 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 41 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 43 * SUCH DAMAGE. 44 * 45 * @(#)kbd.c 8.2 (Berkeley) 10/30/93 46 */ 47 48 /* 49 * /dev/kbd middle layer for sun keyboard off a serial line 50 * This code is used by kbd_zs and sunkbd drivers (lower layer). 51 */ 52 53 #include <sys/cdefs.h> 54 __KERNEL_RCSID(0, "$NetBSD: kbdsun.c,v 1.1 2002/10/03 16:13:26 uwe Exp $"); 55 56 #include <sys/param.h> 57 #include <sys/systm.h> 58 #include <sys/conf.h> 59 #include <sys/device.h> 60 #include <sys/ioctl.h> 61 #include <sys/kernel.h> 62 #include <sys/proc.h> 63 #include <sys/signal.h> 64 #include <sys/signalvar.h> 65 #include <sys/time.h> 66 #include <sys/syslog.h> 67 #include <sys/select.h> 68 #include <sys/poll.h> 69 #include <sys/file.h> 70 71 #include <machine/vuid_event.h> 72 #include <machine/kbd.h> 73 #include <machine/kbio.h> 74 #include <dev/sun/event_var.h> 75 #include <dev/sun/kbd_xlate.h> 76 77 #include <dev/sun/kbdvar.h> 78 #include <dev/sun/kbdsunvar.h> 79 80 81 /* callbacks for the upper /dev/kbd layer */ 82 static int kbd_sun_open(struct kbd_softc *); 83 static int kbd_sun_close(struct kbd_softc *); 84 static int kbd_sun_do_cmd(struct kbd_softc *, int, int); 85 static int kbd_sun_set_leds(struct kbd_softc *, int, int); 86 87 static void kbd_sun_set_leds1(struct kbd_softc *, int); /* aux */ 88 89 struct kbd_ops kbd_ops_sun = { 90 kbd_sun_open, 91 kbd_sun_close, 92 kbd_sun_do_cmd, 93 kbd_sun_set_leds 94 }; 95 96 /* in user context, wait for keyboard output to finish */ 97 static int kbd_sun_drain_tx(struct kbd_sun_softc *); 98 99 /* helper functions for kbd_sun_input */ 100 static void kbd_sun_was_reset(struct kbd_sun_softc *); 101 static void kbd_sun_new_layout(struct kbd_sun_softc *); 102 static void kbd_sun_repeat(void *); 103 104 105 /*********************************************************************** 106 * Callbacks for upper layer. 107 */ 108 109 /* 110 * Initialization to be done at first open. 111 * This is called from kbdopen() or kd_cc_open() 112 * Called with user context. 113 */ 114 static int 115 kbd_sun_open(kbd) 116 struct kbd_softc *kbd; 117 { 118 struct kbd_sun_softc *k = (struct kbd_sun_softc *)kbd; 119 struct kbd_state *ks; 120 int error, s; 121 122 if (kbd == NULL) 123 return (ENXIO); 124 125 ks = &kbd->k_state; 126 127 /* tolerate extra calls. */ 128 if (k->k_isopen) 129 return (0); 130 131 /* stop pending autorepeat */ 132 if (k->k_repeating) { 133 k->k_repeating = 0; 134 callout_stop(&k->k_repeat_ch); 135 } 136 137 /* open internal device */ 138 if (k->k_deviopen) 139 (*k->k_deviopen)((struct device *)k, FREAD|FWRITE); 140 141 s = spltty(); 142 143 /* reset the keyboard and find out its type */ 144 kbd_sun_output(k, KBD_CMD_RESET); 145 kbd_sun_start_tx(k); 146 kbd_sun_drain_tx(k); 147 148 /* the wakeup for this is in kbd_was_reset(). */ 149 error = tsleep((caddr_t)&ks->kbd_id, PZERO | PCATCH, devopn, hz); 150 if (error == EWOULDBLOCK) { /* no response */ 151 log(LOG_ERR, "%s: reset failed\n", kbd->k_dev.dv_xname); 152 153 /* 154 * Allow the open anyway (to keep getty happy) 155 * but assume the "least common denominator". 156 */ 157 error = 0; 158 ks->kbd_id = KB_SUN2; 159 } 160 161 /* initialize the table pointers for this type */ 162 kbd_xlate_init(ks); 163 164 /* earlier than type 4 does not know "layout" */ 165 if (ks->kbd_id < KB_SUN4) 166 goto done; 167 168 /* ask for the layout */ 169 kbd_sun_output(k, KBD_CMD_GETLAYOUT); 170 kbd_sun_start_tx(k); 171 kbd_sun_drain_tx(k); 172 173 /* the wakeup for this is in kbd_new_layout() */ 174 error = tsleep((caddr_t)&ks->kbd_layout, PZERO | PCATCH, devopn, hz); 175 if (error == EWOULDBLOCK) { /* no response */ 176 log(LOG_ERR, "%s: no response to get_layout\n", 177 kbd->k_dev.dv_xname); 178 error = 0; 179 ks->kbd_layout = 0; /* US layout */ 180 } 181 done: 182 splx(s); 183 184 if (error == 0) 185 k->k_isopen = 1; 186 187 return (error); 188 } 189 190 191 static int 192 kbd_sun_close(kbd) 193 struct kbd_softc *kbd; 194 { 195 196 return (0); /* nothing to do so far */ 197 } 198 199 200 /* 201 * keyboard command ioctl 202 * ``unimplemented commands are ignored'' (blech) 203 * XXX: This is also exported to the fb driver (for bell). 204 */ 205 static int 206 kbd_sun_do_cmd(kbd, cmd, isioctl) 207 struct kbd_softc *kbd; 208 int cmd; 209 int isioctl; 210 { 211 struct kbd_sun_softc *k = (struct kbd_sun_softc *)kbd; 212 struct kbd_state *ks; 213 int error, s; 214 215 error = 0; 216 ks = &kbd->k_state; 217 218 switch (cmd) { 219 220 case KBD_CMD_BELL: 221 case KBD_CMD_NOBELL: 222 /* Supported by type 2, 3, and 4 keyboards */ 223 break; 224 225 case KBD_CMD_CLICK: 226 case KBD_CMD_NOCLICK: 227 /* Unsupported by type 2 keyboards */ 228 if (ks->kbd_id <= KB_SUN2) 229 return (0); 230 ks->kbd_click = (cmd == KBD_CMD_CLICK); 231 break; 232 233 default: 234 return (0); 235 } 236 237 s = spltty(); 238 239 if (isioctl) 240 error = kbd_sun_drain_tx(k); 241 242 if (error == 0) { 243 kbd_sun_output(k, cmd); 244 kbd_sun_start_tx(k); 245 } 246 247 splx(s); 248 249 return (error); 250 } 251 252 253 /* 254 * KIOCSLED. Has user context. 255 * Take care about spl and call kbd_sun_set_leds. 256 */ 257 static int 258 kbd_sun_set_leds(kbd, leds, isioctl) 259 struct kbd_softc *kbd; 260 int leds; 261 int isioctl; 262 { 263 struct kbd_sun_softc *k = (struct kbd_sun_softc *)kbd; 264 265 if (isioctl) { 266 int error, s; 267 s = spltty(); 268 error = kbd_sun_drain_tx(k); 269 if (error == 0) { 270 kbd_sun_set_leds1(kbd, leds); 271 } 272 splx(s); 273 return (error); 274 } 275 else { 276 kbd_sun_set_leds1(kbd, leds); 277 return (0); 278 } 279 } 280 281 282 /* 283 * Safe to call from intterupt handler. Called at spltty() 284 * by kbd_sun_iocsled and kbd_sun_input (via kbd_update_leds). 285 */ 286 static void 287 kbd_sun_set_leds1(kbd, new_leds) 288 struct kbd_softc *kbd; 289 int new_leds; 290 { 291 struct kbd_sun_softc *k = (struct kbd_sun_softc *)kbd; 292 struct kbd_state *ks = &kbd->k_state; 293 294 /* Don't send unless state changes. */ 295 if (ks->kbd_leds == new_leds) 296 return; 297 298 ks->kbd_leds = new_leds; 299 300 /* Only type 4 and later has LEDs anyway. */ 301 if (ks->kbd_id < KB_SUN4) 302 return; 303 304 kbd_sun_output(k, KBD_CMD_SETLED); 305 kbd_sun_output(k, new_leds); 306 kbd_sun_start_tx(k); 307 } 308 309 310 311 /*********************************************************************** 312 * Methods for lower layer to call and related functions. 313 */ 314 315 /* 316 * Enqueue some output for the keyboard 317 * Called at spltty(). 318 */ 319 void 320 kbd_sun_output(k, c) 321 struct kbd_sun_softc *k; 322 int c; /* the data */ 323 { 324 int put; 325 326 put = k->k_tbput; 327 k->k_tbuf[put] = (u_char)c; 328 put = (put + 1) & KBD_TX_RING_MASK; 329 330 /* Would overrun if increment makes (put == get) */ 331 if (put == k->k_tbget) { 332 log(LOG_WARNING, "%s: output overrun\n", 333 k->k_kbd.k_dev.dv_xname); 334 } else { 335 /* OK, really increment. */ 336 k->k_tbput = put; 337 } 338 } 339 340 341 /* 342 * In user context. Called at spltty(). 343 * Wait for output to keyboard to finish. 344 */ 345 static int 346 kbd_sun_drain_tx(k) 347 struct kbd_sun_softc *k; 348 { 349 int error = 0; 350 351 while (k->k_txflags & K_TXBUSY && !error) { 352 k->k_txflags |= K_TXWANT; 353 error = tsleep((caddr_t)&k->k_txflags, 354 PZERO | PCATCH, "kbdout", 0); 355 } 356 357 return (error); 358 } 359 360 /* 361 * Start the sending data from the output queue 362 * Called at spltty(). 363 */ 364 void 365 kbd_sun_start_tx(k) 366 struct kbd_sun_softc *k; 367 { 368 int get; 369 u_char c; 370 371 if (k->k_txflags & K_TXBUSY) 372 return; 373 374 /* Is there anything to send? */ 375 get = k->k_tbget; 376 if (get == k->k_tbput) { 377 /* Nothing to send. Wake drain waiters. */ 378 if (k->k_txflags & K_TXWANT) { 379 k->k_txflags &= ~K_TXWANT; 380 wakeup((caddr_t)&k->k_txflags); 381 } 382 return; 383 } 384 385 /* Have something to send. */ 386 c = k->k_tbuf[get]; 387 get = (get + 1) & KBD_TX_RING_MASK; 388 k->k_tbget = get; 389 k->k_txflags |= K_TXBUSY; 390 391 /* Pass data down to the underlying device. */ 392 (*k->k_write_data)(k, c); 393 } 394 395 396 /* 397 * Called by underlying driver's softint() routine on input, 398 * which passes us the raw hardware scan codes. 399 * Called at spltty() 400 */ 401 void 402 kbd_sun_input(k, c) 403 struct kbd_sun_softc *k; 404 int c; 405 { 406 struct kbd_softc *kbd = (struct kbd_softc *)k; 407 struct kbd_state *ks = &kbd->k_state; 408 int keysym; 409 410 /* XXX - Input errors already handled. */ 411 412 /* Are we expecting special input? */ 413 if (k->k_expect) { 414 if (k->k_expect & KBD_EXPECT_IDCODE) { 415 /* We read a KBD_RESET last time. */ 416 ks->kbd_id = c; 417 kbd_sun_was_reset(k); 418 } 419 if (k->k_expect & KBD_EXPECT_LAYOUT) { 420 /* We read a KBD_LAYOUT last time. */ 421 ks->kbd_layout = c; 422 kbd_sun_new_layout(k); 423 } 424 k->k_expect = 0; 425 return; 426 } 427 428 /* Is this one of the "special" input codes? */ 429 if (KBD_SPECIAL(c)) { 430 switch (c) { 431 case KBD_RESET: 432 k->k_expect |= KBD_EXPECT_IDCODE; 433 /* Fake an "all-up" to resync. translation. */ 434 c = KBD_IDLE; 435 break; 436 437 case KBD_LAYOUT: 438 k->k_expect |= KBD_EXPECT_LAYOUT; 439 return; 440 441 case KBD_ERROR: 442 log(LOG_WARNING, "%s: received error indicator\n", 443 kbd->k_dev.dv_xname); 444 return; 445 446 case KBD_IDLE: 447 /* Let this go to the translator. */ 448 break; 449 } 450 } 451 452 /* 453 * If /dev/kbd is not connected in event mode, 454 * translate and send upstream (to console). 455 */ 456 if (!kbd->k_evmode) { 457 458 /* Any input stops auto-repeat (i.e. key release). */ 459 if (k->k_repeating) { 460 k->k_repeating = 0; 461 callout_stop(&k->k_repeat_ch); 462 } 463 464 /* Translate this code to a keysym */ 465 keysym = kbd_code_to_keysym(ks, c); 466 467 /* Pass up to the next layer. */ 468 if (kbd_input_keysym(kbd, keysym)) { 469 log(LOG_WARNING, "%s: code=0x%x with mod=0x%x" 470 " produced unexpected keysym 0x%x\n", 471 kbd->k_dev.dv_xname, 472 c, ks->kbd_modbits, keysym); 473 /* No point in auto-repeat here. */ 474 return; 475 } 476 477 /* Does this symbol get auto-repeat? */ 478 if (KEYSYM_NOREPEAT(keysym)) 479 return; 480 481 /* Setup for auto-repeat after initial delay. */ 482 k->k_repeating = 1; 483 k->k_repeatsym = keysym; 484 callout_reset(&k->k_repeat_ch, k->k_repeat_start, 485 kbd_sun_repeat, k); 486 return; 487 } 488 489 /* 490 * IDLEs confuse the MIT X11R4 server badly, so we must drop them. 491 * This is bad as it means the server will not automatically resync 492 * on all-up IDLEs, but I did not drop them before, and the server 493 * goes crazy when it comes time to blank the screen.... 494 */ 495 if (c == KBD_IDLE) 496 return; 497 498 /* 499 * Keyboard is generating events. Turn this keystroke into an 500 * event and put it in the queue. 501 */ 502 kbd_input_event(kbd, c); 503 } 504 505 506 /* 507 * Called by kbd_sun_input to handle keyboard's response to reset. 508 * Called at spltty(). 509 */ 510 static void 511 kbd_sun_was_reset(k) 512 struct kbd_sun_softc *k; 513 { 514 struct kbd_state *ks = &k->k_kbd.k_state; 515 516 /* 517 * On first identification, wake up anyone waiting for type 518 * and set up the table pointers. 519 */ 520 wakeup((caddr_t)&ks->kbd_id); 521 522 /* Restore keyclick, if necessary */ 523 switch (ks->kbd_id) { 524 525 case KB_SUN2: 526 /* Type 2 keyboards don't support keyclick */ 527 break; 528 529 case KB_SUN3: 530 /* Type 3 keyboards come up with keyclick on */ 531 if (!ks->kbd_click) { 532 /* turn off the click */ 533 kbd_sun_output(k, KBD_CMD_NOCLICK); 534 kbd_sun_start_tx(k); 535 } 536 break; 537 538 case KB_SUN4: 539 /* Type 4 keyboards come up with keyclick off */ 540 if (ks->kbd_click) { 541 /* turn on the click */ 542 kbd_sun_output(k, KBD_CMD_CLICK); 543 kbd_sun_start_tx(k); 544 } 545 break; 546 } 547 548 /* LEDs are off after reset. */ 549 ks->kbd_leds = 0; 550 } 551 552 /* 553 * Called by kbd_sun_input to handle response to layout request. 554 * Called at spltty(). 555 */ 556 static void 557 kbd_sun_new_layout(k) 558 struct kbd_sun_softc *k; 559 { 560 struct kbd_state *ks = &k->k_kbd.k_state; 561 562 /* 563 * On first identification, wake up anyone waiting for type 564 * and set up the table pointers. 565 */ 566 wakeup((caddr_t)&ks->kbd_layout); 567 568 /* XXX: switch decoding tables? */ 569 } 570 571 572 /* 573 * This is the autorepeat callout function. 574 * Autorepeat is scheduled by kbd_sun_input. 575 * Called at splsoftclock(). 576 */ 577 static void 578 kbd_sun_repeat(arg) 579 void *arg; 580 { 581 struct kbd_sun_softc *k = (struct kbd_sun_softc *)arg; 582 int s; 583 584 s = spltty(); 585 if (k->k_repeating && k->k_repeatsym >= 0) { 586 587 /* feed typematic keysym to the upper layer */ 588 (void)kbd_input_keysym(&k->k_kbd, k->k_repeatsym); 589 590 /* reschedule next repeat */ 591 callout_reset(&k->k_repeat_ch, k->k_repeat_step, 592 kbd_sun_repeat, k); 593 } 594 splx(s); 595 } 596