1 /* $NetBSD: kbd.c,v 1.21 2002/10/02 05:04:26 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1995 Leo Weppelman 5 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/device.h> 40 #include <sys/ioctl.h> 41 #include <sys/tty.h> 42 #include <sys/proc.h> 43 #include <sys/conf.h> 44 #include <sys/file.h> 45 #include <sys/kernel.h> 46 #include <sys/signalvar.h> 47 #include <sys/syslog.h> 48 #include <dev/cons.h> 49 #include <machine/cpu.h> 50 #include <machine/iomap.h> 51 #include <machine/mfp.h> 52 #include <machine/acia.h> 53 #include <atari/dev/itevar.h> 54 #include <atari/dev/event_var.h> 55 #include <atari/dev/vuid_event.h> 56 #include <atari/dev/ym2149reg.h> 57 #include <atari/dev/kbdreg.h> 58 #include <atari/dev/kbdvar.h> 59 #include <atari/dev/kbdmap.h> 60 #include <atari/dev/msvar.h> 61 62 #include "mouse.h" 63 64 u_char kbd_modifier; /* Modifier mask */ 65 66 static u_char kbd_ring[KBD_RING_SIZE]; 67 static volatile u_int kbd_rbput = 0; /* 'put' index */ 68 static u_int kbd_rbget = 0; /* 'get' index */ 69 static u_char kbd_soft = 0; /* 1: Softint has been scheduled*/ 70 71 static struct kbd_softc kbd_softc; 72 73 /* {b,c}devsw[] function prototypes */ 74 dev_type_open(kbdopen); 75 dev_type_close(kbdclose); 76 dev_type_read(kbdread); 77 dev_type_ioctl(kbdioctl); 78 dev_type_poll(kbdpoll); 79 80 /* Interrupt handler */ 81 void kbdintr __P((int)); 82 83 static void kbdsoft __P((void *, void *)); 84 static void kbdattach __P((struct device *, struct device *, void *)); 85 static int kbdmatch __P((struct device *, struct cfdata *, void *)); 86 static int kbd_do_modifier __P((u_char)); 87 static int kbd_write_poll __P((u_char *, int)); 88 static void kbd_pkg_start __P((struct kbd_softc *, u_char)); 89 90 CFATTACH_DECL(kbd, sizeof(struct device), 91 kbdmatch, kbdattach, NULL, NULL); 92 93 const struct cdevsw kbd_cdevsw = { 94 kbdopen, kbdclose, kbdread, nowrite, kbdioctl, 95 nostop, notty, kbdpoll, nommap, 96 }; 97 98 /*ARGSUSED*/ 99 static int 100 kbdmatch(pdp, cfp, auxp) 101 struct device *pdp; 102 struct cfdata *cfp; 103 void *auxp; 104 { 105 if (!strcmp((char *)auxp, "kbd")) 106 return (1); 107 return (0); 108 } 109 110 /*ARGSUSED*/ 111 static void 112 kbdattach(pdp, dp, auxp) 113 struct device *pdp, *dp; 114 void *auxp; 115 { 116 int timeout; 117 u_char kbd_rst[] = { 0x80, 0x01 }; 118 u_char kbd_icmd[] = { 0x12, 0x15 }; 119 120 /* 121 * Disable keyboard interrupts from MFP 122 */ 123 MFP->mf_ierb &= ~IB_AINT; 124 125 /* 126 * Reset ACIA and intialize to: 127 * divide by 16, 8 data, 1 stop, no parity, enable RX interrupts 128 */ 129 KBD->ac_cs = A_RESET; 130 delay(100); /* XXX: enough? */ 131 KBD->ac_cs = kbd_softc.k_soft_cs = KBD_INIT | A_RXINT; 132 133 /* 134 * Clear error conditions 135 */ 136 while (KBD->ac_cs & (A_IRQ|A_RXRDY)) 137 timeout = KBD->ac_da; 138 139 /* 140 * Now send the reset string, and read+ignore it's response 141 */ 142 if (!kbd_write_poll(kbd_rst, 2)) 143 printf("kbd: error cannot reset keyboard\n"); 144 for (timeout = 1000; timeout > 0; timeout--) { 145 if (KBD->ac_cs & (A_IRQ|A_RXRDY)) { 146 timeout = KBD->ac_da; 147 timeout = 100; 148 } 149 delay(100); 150 } 151 /* 152 * Send init command: disable mice & joysticks 153 */ 154 kbd_write_poll(kbd_icmd, sizeof(kbd_icmd)); 155 156 printf("\n"); 157 } 158 159 void 160 kbdenable() 161 { 162 int s, code; 163 164 s = spltty(); 165 166 /* 167 * Clear error conditions... 168 */ 169 while (KBD->ac_cs & (A_IRQ|A_RXRDY)) 170 code = KBD->ac_da; 171 /* 172 * Enable interrupts from MFP 173 */ 174 MFP->mf_iprb = (u_int8_t)~IB_AINT; 175 MFP->mf_ierb |= IB_AINT; 176 MFP->mf_imrb |= IB_AINT; 177 178 kbd_softc.k_event_mode = 0; 179 kbd_softc.k_events.ev_io = 0; 180 kbd_softc.k_pkg_size = 0; 181 splx(s); 182 } 183 184 int kbdopen(dev_t dev, int flags, int mode, struct proc *p) 185 { 186 if (kbd_softc.k_events.ev_io) 187 return EBUSY; 188 189 kbd_softc.k_events.ev_io = p; 190 ev_init(&kbd_softc.k_events); 191 return (0); 192 } 193 194 int 195 kbdclose(dev_t dev, int flags, int mode, struct proc *p) 196 { 197 /* Turn off event mode, dump the queue */ 198 kbd_softc.k_event_mode = 0; 199 ev_fini(&kbd_softc.k_events); 200 kbd_softc.k_events.ev_io = NULL; 201 return (0); 202 } 203 204 int 205 kbdread(dev_t dev, struct uio *uio, int flags) 206 { 207 return ev_read(&kbd_softc.k_events, uio, flags); 208 } 209 210 int 211 kbdioctl(dev_t dev,u_long cmd,register caddr_t data,int flag,struct proc *p) 212 { 213 register struct kbd_softc *k = &kbd_softc; 214 struct kbdbell *kb; 215 216 switch (cmd) { 217 case KIOCTRANS: 218 if (*(int *)data == TR_UNTRANS_EVENT) 219 return 0; 220 break; 221 222 case KIOCGTRANS: 223 /* 224 * Get translation mode 225 */ 226 *(int *)data = TR_UNTRANS_EVENT; 227 return 0; 228 229 case KIOCSDIRECT: 230 k->k_event_mode = *(int *)data; 231 return 0; 232 233 case KIOCRINGBELL: 234 kb = (struct kbdbell *)data; 235 if (kb) 236 kbd_bell_sparms(kb->volume, kb->pitch, 237 kb->duration); 238 kbdbell(); 239 return 0; 240 241 case FIONBIO: /* we will remove this someday (soon???) */ 242 return 0; 243 244 case FIOASYNC: 245 k->k_events.ev_async = *(int *)data != 0; 246 return 0; 247 248 case TIOCSPGRP: 249 if (*(int *)data != k->k_events.ev_io->p_pgid) 250 return EPERM; 251 return 0; 252 253 default: 254 return ENOTTY; 255 } 256 257 /* 258 * We identified the ioctl, but we do not handle it. 259 */ 260 return EOPNOTSUPP; /* misuse, but what the heck */ 261 } 262 263 int 264 kbdpoll (dev_t dev, int events, struct proc *p) 265 { 266 return ev_poll (&kbd_softc.k_events, events, p); 267 } 268 269 /* 270 * Keyboard interrupt handler called straight from MFP at spl6. 271 */ 272 void 273 kbdintr(sr) 274 int sr; /* sr at time of interrupt */ 275 { 276 int code; 277 int got_char = 0; 278 279 /* 280 * There may be multiple keys available. Read them all. 281 */ 282 while (KBD->ac_cs & (A_RXRDY|A_OE|A_PE)) { 283 got_char = 1; 284 if (KBD->ac_cs & (A_OE|A_PE)) { 285 code = KBD->ac_da; /* Silently ignore errors */ 286 continue; 287 } 288 kbd_ring[kbd_rbput++ & KBD_RING_MASK] = KBD->ac_da; 289 } 290 291 /* 292 * If characters are waiting for transmit, send them. 293 */ 294 if ((kbd_softc.k_soft_cs & A_TXINT) && (KBD->ac_cs & A_TXRDY)) { 295 if (kbd_softc.k_sendp != NULL) 296 KBD->ac_da = *kbd_softc.k_sendp++; 297 if (--kbd_softc.k_send_cnt <= 0) { 298 /* 299 * The total package has been transmitted, 300 * wakeup anyone waiting for it. 301 */ 302 KBD->ac_cs = (kbd_softc.k_soft_cs &= ~A_TXINT); 303 kbd_softc.k_sendp = NULL; 304 kbd_softc.k_send_cnt = 0; 305 wakeup((caddr_t)&kbd_softc.k_send_cnt); 306 } 307 } 308 309 /* 310 * Activate software-level to handle possible input. 311 */ 312 if (got_char) { 313 if (!BASEPRI(sr)) { 314 if (!kbd_soft++) 315 add_sicallback(kbdsoft, 0, 0); 316 } else { 317 spl1(); 318 kbdsoft(NULL, NULL); 319 } 320 } 321 } 322 323 /* 324 * Keyboard soft interrupt handler 325 */ 326 void 327 kbdsoft(junk1, junk2) 328 void *junk1, *junk2; 329 { 330 int s; 331 u_char code; 332 struct kbd_softc *k = &kbd_softc; 333 struct firm_event *fe; 334 int put; 335 int n, get; 336 337 kbd_soft = 0; 338 get = kbd_rbget; 339 340 for (;;) { 341 n = kbd_rbput; 342 if (get == n) /* We're done */ 343 break; 344 n -= get; 345 if (n > KBD_RING_SIZE) { /* Ring buffer overflow */ 346 get += n - KBD_RING_SIZE; 347 n = KBD_RING_SIZE; 348 } 349 while (--n >= 0) { 350 code = kbd_ring[get++ & KBD_RING_MASK]; 351 352 /* 353 * If collecting a package, stuff it in and 354 * continue. 355 */ 356 if (k->k_pkg_size && (k->k_pkg_idx < k->k_pkg_size)) { 357 k->k_package[k->k_pkg_idx++] = code; 358 if (k->k_pkg_idx == k->k_pkg_size) { 359 /* 360 * Package is complete. 361 */ 362 switch(k->k_pkg_type) { 363 #if NMOUSE > 0 364 case KBD_AMS_PKG: 365 case KBD_RMS_PKG: 366 case KBD_JOY1_PKG: 367 mouse_soft((REL_MOUSE *)k->k_package, 368 k->k_pkg_size, k->k_pkg_type); 369 #endif /* NMOUSE */ 370 } 371 k->k_pkg_size = 0; 372 } 373 continue; 374 } 375 /* 376 * If this is a package header, init pkg. handling. 377 */ 378 if (!KBD_IS_KEY(code)) { 379 kbd_pkg_start(k, code); 380 continue; 381 } 382 if (kbd_do_modifier(code) && !k->k_event_mode) 383 continue; 384 385 /* 386 * if not in event mode, deliver straight to ite to 387 * process key stroke 388 */ 389 if (!k->k_event_mode) { 390 /* Gets to spltty() by itself */ 391 ite_filter(code, ITEFILT_TTY); 392 continue; 393 } 394 395 /* 396 * Keyboard is generating events. Turn this keystroke 397 * into an event and put it in the queue. If the queue 398 * is full, the keystroke is lost (sorry!). 399 */ 400 s = spltty(); 401 put = k->k_events.ev_put; 402 fe = &k->k_events.ev_q[put]; 403 put = (put + 1) % EV_QSIZE; 404 if (put == k->k_events.ev_get) { 405 log(LOG_WARNING, 406 "keyboard event queue overflow\n"); 407 splx(s); 408 continue; 409 } 410 fe->id = KBD_SCANCODE(code); 411 fe->value = KBD_RELEASED(code) ? VKEY_UP : VKEY_DOWN; 412 fe->time = time; 413 k->k_events.ev_put = put; 414 EV_WAKEUP(&k->k_events); 415 splx(s); 416 } 417 kbd_rbget = get; 418 } 419 } 420 421 static u_char sound[] = { 422 0xA8,0x01,0xA9,0x01,0xAA,0x01,0x00, 423 0xF8,0x10,0x10,0x10,0x00,0x20,0x03 424 }; 425 426 void 427 kbdbell() 428 { 429 register int i, sps; 430 431 sps = splhigh(); 432 for (i = 0; i < sizeof(sound); i++) { 433 YM2149->sd_selr = i; 434 YM2149->sd_wdat = sound[i]; 435 } 436 splx(sps); 437 } 438 439 440 /* 441 * Set the parameters of the 'default' beep. 442 */ 443 444 #define KBDBELLCLOCK 125000 /* 2MHz / 16 */ 445 #define KBDBELLDURATION 128 /* 256 / 2MHz */ 446 447 void 448 kbd_bell_gparms(volume, pitch, duration) 449 u_int *volume, *pitch, *duration; 450 { 451 u_int tmp; 452 453 tmp = sound[11] | (sound[12] << 8); 454 *duration = (tmp * KBDBELLDURATION) / 1000; 455 456 tmp = sound[0] | (sound[1] << 8); 457 *pitch = KBDBELLCLOCK / tmp; 458 459 *volume = 0; 460 } 461 462 void 463 kbd_bell_sparms(volume, pitch, duration) 464 u_int volume, pitch, duration; 465 { 466 u_int f, t; 467 468 f = pitch > 10 ? pitch : 10; /* minimum pitch */ 469 if (f > 20000) 470 f = 20000; /* maximum pitch */ 471 472 f = KBDBELLCLOCK / f; 473 474 t = (duration * 1000) / KBDBELLDURATION; 475 476 sound[ 0] = f & 0xff; 477 sound[ 1] = (f >> 8) & 0xf; 478 f -= 1; 479 sound[ 2] = f & 0xff; 480 sound[ 3] = (f >> 8) & 0xf; 481 f += 2; 482 sound[ 4] = f & 0xff; 483 sound[ 5] = (f >> 8) & 0xf; 484 485 sound[11] = t & 0xff; 486 sound[12] = (t >> 8) & 0xff; 487 488 sound[13] = 0x03; 489 } 490 491 int 492 kbdgetcn() 493 { 494 u_char code; 495 int s = spltty(); 496 int ints_active; 497 498 ints_active = 0; 499 if (MFP->mf_imrb & IB_AINT) { 500 ints_active = 1; 501 MFP->mf_imrb &= ~IB_AINT; 502 } 503 for (;;) { 504 while (!((KBD->ac_cs & (A_IRQ|A_RXRDY)) == (A_IRQ|A_RXRDY))) 505 ; /* Wait for key */ 506 if (KBD->ac_cs & (A_OE|A_PE)) { 507 code = KBD->ac_da; /* Silently ignore errors */ 508 continue; 509 } 510 code = KBD->ac_da; 511 if (!kbd_do_modifier(code)) 512 break; 513 } 514 515 if (ints_active) { 516 MFP->mf_iprb = (u_int8_t)~IB_AINT; 517 MFP->mf_imrb |= IB_AINT; 518 } 519 520 splx (s); 521 return code; 522 } 523 524 /* 525 * Write a command to the keyboard in 'polled' mode. 526 */ 527 static int 528 kbd_write_poll(cmd, len) 529 u_char *cmd; 530 int len; 531 { 532 int timeout; 533 534 while (len-- > 0) { 535 KBD->ac_da = *cmd++; 536 for (timeout = 100; !(KBD->ac_cs & A_TXRDY); timeout--) 537 delay(10); 538 if (!(KBD->ac_cs & A_TXRDY)) 539 return (0); 540 } 541 return (1); 542 } 543 544 /* 545 * Write a command to the keyboard. Return when command is send. 546 */ 547 void 548 kbd_write(cmd, len) 549 u_char *cmd; 550 int len; 551 { 552 struct kbd_softc *k = &kbd_softc; 553 int sps; 554 555 /* 556 * Get to splhigh, 'real' interrupts arrive at spl6! 557 */ 558 sps = splhigh(); 559 560 /* 561 * Make sure any privious write has ended... 562 */ 563 while (k->k_sendp != NULL) 564 tsleep((caddr_t)&k->k_sendp, TTOPRI, "kbd_write1", 0); 565 566 /* 567 * If the KBD-acia is not currently busy, send the first 568 * character now. 569 */ 570 KBD->ac_cs = (k->k_soft_cs |= A_TXINT); 571 if (KBD->ac_cs & A_TXRDY) { 572 KBD->ac_da = *cmd++; 573 len--; 574 } 575 576 /* 577 * If we're not yet done, wait until all characters are send. 578 */ 579 if (len > 0) { 580 k->k_sendp = cmd; 581 k->k_send_cnt = len; 582 tsleep((caddr_t)&k->k_send_cnt, TTOPRI, "kbd_write2", 0); 583 } 584 splx(sps); 585 586 /* 587 * Wakeup all procs waiting for us. 588 */ 589 wakeup((caddr_t)&k->k_sendp); 590 } 591 592 /* 593 * Setup softc-fields to assemble a keyboard package. 594 */ 595 static void 596 kbd_pkg_start(kp, msg_start) 597 struct kbd_softc *kp; 598 u_char msg_start; 599 { 600 kp->k_pkg_idx = 1; 601 kp->k_package[0] = msg_start; 602 switch (msg_start) { 603 case 0xf6: 604 kp->k_pkg_type = KBD_MEM_PKG; 605 kp->k_pkg_size = 8; 606 break; 607 case 0xf7: 608 kp->k_pkg_type = KBD_AMS_PKG; 609 kp->k_pkg_size = 6; 610 break; 611 case 0xf8: 612 case 0xf9: 613 case 0xfa: 614 case 0xfb: 615 kp->k_pkg_type = KBD_RMS_PKG; 616 kp->k_pkg_size = 3; 617 break; 618 case 0xfc: 619 kp->k_pkg_type = KBD_CLK_PKG; 620 kp->k_pkg_size = 7; 621 break; 622 case 0xfe: 623 kp->k_pkg_type = KBD_JOY0_PKG; 624 kp->k_pkg_size = 2; 625 break; 626 case 0xff: 627 kp->k_pkg_type = KBD_JOY1_PKG; 628 kp->k_pkg_size = 2; 629 break; 630 default: 631 printf("kbd: Unknown packet 0x%x\n", msg_start); 632 break; 633 } 634 } 635 636 /* 637 * Modifier processing 638 */ 639 static int 640 kbd_do_modifier(code) 641 u_char code; 642 { 643 u_char up, mask; 644 645 up = KBD_RELEASED(code); 646 mask = 0; 647 648 switch(KBD_SCANCODE(code)) { 649 case KBD_LEFT_SHIFT: 650 mask = KBD_MOD_LSHIFT; 651 break; 652 case KBD_RIGHT_SHIFT: 653 mask = KBD_MOD_RSHIFT; 654 break; 655 case KBD_CTRL: 656 mask = KBD_MOD_CTRL; 657 break; 658 case KBD_ALT: 659 mask = KBD_MOD_ALT; 660 break; 661 case KBD_CAPS_LOCK: 662 /* CAPSLOCK is a toggle */ 663 if(!up) 664 kbd_modifier ^= KBD_MOD_CAPS; 665 return 1; 666 } 667 if(mask) { 668 if(up) 669 kbd_modifier &= ~mask; 670 else 671 kbd_modifier |= mask; 672 return 1; 673 } 674 return 0; 675 } 676