1 /* $NetBSD: kbd.c,v 1.16 1997/06/29 20:30:50 leo 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 struct cfattach kbd_ca = { 91 sizeof(struct device), kbdmatch, kbdattach 92 }; 93 94 struct cfdriver kbd_cd = { 95 NULL, "kbd", DV_DULL, NULL, 0 96 }; 97 98 99 /*ARGSUSED*/ 100 static int 101 kbdmatch(pdp, cfp, auxp) 102 struct device *pdp; 103 struct cfdata *cfp; 104 void *auxp; 105 { 106 if (!strcmp((char *)auxp, "kbd")) 107 return (1); 108 return (0); 109 } 110 111 /*ARGSUSED*/ 112 static void 113 kbdattach(pdp, dp, auxp) 114 struct device *pdp, *dp; 115 void *auxp; 116 { 117 int timeout; 118 u_char kbd_rst[] = { 0x80, 0x01 }; 119 u_char kbd_icmd[] = { 0x12, 0x15 }; 120 121 /* 122 * Disable keyboard interrupts from MFP 123 */ 124 MFP->mf_ierb &= ~IB_AINT; 125 126 /* 127 * Reset ACIA and intialize to: 128 * divide by 16, 8 data, 1 stop, no parity, enable RX interrupts 129 */ 130 KBD->ac_cs = A_RESET; 131 delay(100); /* XXX: enough? */ 132 KBD->ac_cs = kbd_softc.k_soft_cs = KBD_INIT | A_RXINT; 133 134 /* 135 * Clear error conditions 136 */ 137 while (KBD->ac_cs & (A_IRQ|A_RXRDY)) 138 timeout = KBD->ac_da; 139 140 /* 141 * Now send the reset string, and read+ignore it's response 142 */ 143 if (!kbd_write_poll(kbd_rst, 2)) 144 printf("kbd: error cannot reset keyboard\n"); 145 for (timeout = 1000; timeout > 0; timeout--) { 146 if (KBD->ac_cs & (A_IRQ|A_RXRDY)) { 147 timeout = KBD->ac_da; 148 timeout = 100; 149 } 150 delay(100); 151 } 152 /* 153 * Send init command: disable mice & joysticks 154 */ 155 kbd_write_poll(kbd_icmd, sizeof(kbd_icmd)); 156 157 printf("\n"); 158 } 159 160 void 161 kbdenable() 162 { 163 int s, code; 164 165 s = spltty(); 166 167 /* 168 * Clear error conditions... 169 */ 170 while (KBD->ac_cs & (A_IRQ|A_RXRDY)) 171 code = KBD->ac_da; 172 /* 173 * Enable interrupts from MFP 174 */ 175 MFP->mf_iprb &= ~IB_AINT; 176 MFP->mf_ierb |= IB_AINT; 177 MFP->mf_imrb |= IB_AINT; 178 179 kbd_softc.k_event_mode = 0; 180 kbd_softc.k_events.ev_io = 0; 181 kbd_softc.k_pkg_size = 0; 182 splx(s); 183 } 184 185 int kbdopen(dev_t dev, int flags, int mode, struct proc *p) 186 { 187 if (kbd_softc.k_events.ev_io) 188 return EBUSY; 189 190 kbd_softc.k_events.ev_io = p; 191 ev_init(&kbd_softc.k_events); 192 return (0); 193 } 194 195 int 196 kbdclose(dev_t dev, int flags, int mode, struct proc *p) 197 { 198 /* Turn off event mode, dump the queue */ 199 kbd_softc.k_event_mode = 0; 200 ev_fini(&kbd_softc.k_events); 201 kbd_softc.k_events.ev_io = NULL; 202 return (0); 203 } 204 205 int 206 kbdread(dev_t dev, struct uio *uio, int flags) 207 { 208 return ev_read(&kbd_softc.k_events, uio, flags); 209 } 210 211 int 212 kbdioctl(dev_t dev,u_long cmd,register caddr_t data,int flag,struct proc *p) 213 { 214 register struct kbd_softc *k = &kbd_softc; 215 struct kbdbell *kb; 216 217 switch (cmd) { 218 case KIOCTRANS: 219 if (*(int *)data == TR_UNTRANS_EVENT) 220 return 0; 221 break; 222 223 case KIOCGTRANS: 224 /* 225 * Get translation mode 226 */ 227 *(int *)data = TR_UNTRANS_EVENT; 228 return 0; 229 230 case KIOCSDIRECT: 231 k->k_event_mode = *(int *)data; 232 return 0; 233 234 case KIOCRINGBELL: 235 kb = (struct kbdbell *)data; 236 if (kb) 237 kbd_bell_sparms(kb->volume, kb->pitch, 238 kb->duration); 239 kbdbell(); 240 return 0; 241 242 case FIONBIO: /* we will remove this someday (soon???) */ 243 return 0; 244 245 case FIOASYNC: 246 k->k_events.ev_async = *(int *)data != 0; 247 return 0; 248 249 case TIOCSPGRP: 250 if (*(int *)data != k->k_events.ev_io->p_pgid) 251 return EPERM; 252 return 0; 253 254 default: 255 return ENOTTY; 256 } 257 258 /* 259 * We identified the ioctl, but we do not handle it. 260 */ 261 return EOPNOTSUPP; /* misuse, but what the heck */ 262 } 263 264 int 265 kbdpoll (dev_t dev, int events, struct proc *p) 266 { 267 return ev_poll (&kbd_softc.k_events, events, p); 268 } 269 270 /* 271 * Keyboard interrupt handler called straight from MFP at spl6. 272 */ 273 void 274 kbdintr(sr) 275 int sr; /* sr at time of interrupt */ 276 { 277 int code; 278 int got_char = 0; 279 280 /* 281 * There may be multiple keys available. Read them all. 282 */ 283 while (KBD->ac_cs & (A_RXRDY|A_OE|A_PE)) { 284 got_char = 1; 285 if (KBD->ac_cs & (A_OE|A_PE)) { 286 code = KBD->ac_da; /* Silently ignore errors */ 287 continue; 288 } 289 kbd_ring[kbd_rbput++ & KBD_RING_MASK] = KBD->ac_da; 290 } 291 292 /* 293 * If characters are waiting for transmit, send them. 294 */ 295 if ((kbd_softc.k_soft_cs & A_TXINT) && (KBD->ac_cs & A_TXRDY)) { 296 if (kbd_softc.k_sendp != NULL) 297 KBD->ac_da = *kbd_softc.k_sendp++; 298 if (--kbd_softc.k_send_cnt <= 0) { 299 /* 300 * The total package has been transmitted, 301 * wakeup anyone waiting for it. 302 */ 303 KBD->ac_cs = (kbd_softc.k_soft_cs &= ~A_TXINT); 304 kbd_softc.k_sendp = NULL; 305 kbd_softc.k_send_cnt = 0; 306 wakeup((caddr_t)&kbd_softc.k_send_cnt); 307 } 308 } 309 310 /* 311 * Activate software-level to handle possible input. 312 */ 313 if (got_char) { 314 if (!BASEPRI(sr)) { 315 if (!kbd_soft++) 316 add_sicallback(kbdsoft, 0, 0); 317 } else { 318 spl1(); 319 kbdsoft(NULL, NULL); 320 } 321 } 322 } 323 324 /* 325 * Keyboard soft interrupt handler 326 */ 327 void 328 kbdsoft(junk1, junk2) 329 void *junk1, *junk2; 330 { 331 int s; 332 u_char code; 333 struct kbd_softc *k = &kbd_softc; 334 struct firm_event *fe; 335 int put; 336 int n, get; 337 338 kbd_soft = 0; 339 get = kbd_rbget; 340 341 for (;;) { 342 n = kbd_rbput; 343 if (get == n) /* We're done */ 344 break; 345 n -= get; 346 if (n > KBD_RING_SIZE) { /* Ring buffer overflow */ 347 get += n - KBD_RING_SIZE; 348 n = KBD_RING_SIZE; 349 } 350 while (--n >= 0) { 351 code = kbd_ring[get++ & KBD_RING_MASK]; 352 353 /* 354 * If collecting a package, stuff it in and 355 * continue. 356 */ 357 if (k->k_pkg_size && (k->k_pkg_idx < k->k_pkg_size)) { 358 k->k_package[k->k_pkg_idx++] = code; 359 if (k->k_pkg_idx == k->k_pkg_size) { 360 /* 361 * Package is complete. 362 */ 363 switch(k->k_pkg_type) { 364 #if NMOUSE > 0 365 case KBD_AMS_PKG: 366 case KBD_RMS_PKG: 367 case KBD_JOY1_PKG: 368 mouse_soft((REL_MOUSE *)k->k_package, 369 k->k_pkg_size, k->k_pkg_type); 370 #endif /* NMOUSE */ 371 } 372 k->k_pkg_size = 0; 373 } 374 continue; 375 } 376 /* 377 * If this is a package header, init pkg. handling. 378 */ 379 if (!KBD_IS_KEY(code)) { 380 kbd_pkg_start(k, code); 381 continue; 382 } 383 if (kbd_do_modifier(code) && !k->k_event_mode) 384 continue; 385 386 /* 387 * if not in event mode, deliver straight to ite to 388 * process key stroke 389 */ 390 if (!k->k_event_mode) { 391 /* Gets to spltty() by itself */ 392 ite_filter(code, ITEFILT_TTY); 393 continue; 394 } 395 396 /* 397 * Keyboard is generating events. Turn this keystroke 398 * into an event and put it in the queue. If the queue 399 * is full, the keystroke is lost (sorry!). 400 */ 401 s = spltty(); 402 put = k->k_events.ev_put; 403 fe = &k->k_events.ev_q[put]; 404 put = (put + 1) % EV_QSIZE; 405 if (put == k->k_events.ev_get) { 406 log(LOG_WARNING, 407 "keyboard event queue overflow\n"); 408 splx(s); 409 continue; 410 } 411 fe->id = KBD_SCANCODE(code); 412 fe->value = KBD_RELEASED(code) ? VKEY_UP : VKEY_DOWN; 413 fe->time = time; 414 k->k_events.ev_put = put; 415 EV_WAKEUP(&k->k_events); 416 splx(s); 417 } 418 kbd_rbget = get; 419 } 420 } 421 422 static u_char sound[] = { 423 0xA8,0x01,0xA9,0x01,0xAA,0x01,0x00, 424 0xF8,0x10,0x10,0x10,0x00,0x20,0x03 425 }; 426 427 void 428 kbdbell() 429 { 430 register int i, sps; 431 432 sps = splhigh(); 433 for (i = 0; i < sizeof(sound); i++) { 434 YM2149->sd_selr = i; 435 YM2149->sd_wdat = sound[i]; 436 } 437 splx(sps); 438 } 439 440 441 /* 442 * Set the parameters of the 'default' beep. 443 */ 444 445 #define KBDBELLCLOCK 125000 /* 2MHz / 16 */ 446 #define KBDBELLDURATION 128 /* 256 / 2MHz */ 447 448 void 449 kbd_bell_gparms(volume, pitch, duration) 450 u_int *volume, *pitch, *duration; 451 { 452 u_int tmp; 453 454 tmp = sound[11] | (sound[12] << 8); 455 *duration = (tmp * KBDBELLDURATION) / 1000; 456 457 tmp = sound[0] | (sound[1] << 8); 458 *pitch = KBDBELLCLOCK / tmp; 459 460 *volume = 0; 461 } 462 463 void 464 kbd_bell_sparms(volume, pitch, duration) 465 u_int volume, pitch, duration; 466 { 467 u_int f, t; 468 469 f = pitch > 10 ? pitch : 10; /* minimum pitch */ 470 if (f > 20000) 471 f = 20000; /* maximum pitch */ 472 473 f = KBDBELLCLOCK / f; 474 475 t = (duration * 1000) / KBDBELLDURATION; 476 477 sound[ 0] = f & 0xff; 478 sound[ 1] = (f >> 8) & 0xf; 479 f -= 1; 480 sound[ 2] = f & 0xff; 481 sound[ 3] = (f >> 8) & 0xf; 482 f += 2; 483 sound[ 4] = f & 0xff; 484 sound[ 5] = (f >> 8) & 0xf; 485 486 sound[11] = t & 0xff; 487 sound[12] = (t >> 8) & 0xff; 488 489 sound[13] = 0x03; 490 } 491 492 int 493 kbdgetcn() 494 { 495 u_char code; 496 int s = spltty(); 497 int ints_active; 498 499 ints_active = 0; 500 if (MFP->mf_imrb & IB_AINT) { 501 ints_active = 1; 502 MFP->mf_imrb &= ~IB_AINT; 503 } 504 for (;;) { 505 while (!((KBD->ac_cs & (A_IRQ|A_RXRDY)) == (A_IRQ|A_RXRDY))) 506 ; /* Wait for key */ 507 if (KBD->ac_cs & (A_OE|A_PE)) { 508 code = KBD->ac_da; /* Silently ignore errors */ 509 continue; 510 } 511 code = KBD->ac_da; 512 if (!kbd_do_modifier(code)) 513 break; 514 } 515 516 if (ints_active) { 517 MFP->mf_iprb &= ~IB_AINT; 518 MFP->mf_imrb |= IB_AINT; 519 } 520 521 splx (s); 522 return code; 523 } 524 525 /* 526 * Write a command to the keyboard in 'polled' mode. 527 */ 528 static int 529 kbd_write_poll(cmd, len) 530 u_char *cmd; 531 int len; 532 { 533 int timeout; 534 535 while (len-- > 0) { 536 KBD->ac_da = *cmd++; 537 for (timeout = 100; !(KBD->ac_cs & A_TXRDY); timeout--) 538 delay(10); 539 if (!(KBD->ac_cs & A_TXRDY)) 540 return (0); 541 } 542 return (1); 543 } 544 545 /* 546 * Write a command to the keyboard. Return when command is send. 547 */ 548 void 549 kbd_write(cmd, len) 550 u_char *cmd; 551 int len; 552 { 553 struct kbd_softc *k = &kbd_softc; 554 int sps; 555 556 /* 557 * Get to splhigh, 'real' interrupts arrive at spl6! 558 */ 559 sps = splhigh(); 560 561 /* 562 * Make sure any privious write has ended... 563 */ 564 while (k->k_sendp != NULL) 565 tsleep((caddr_t)&k->k_sendp, TTOPRI, "kbd_write1", 0); 566 567 /* 568 * If the KBD-acia is not currently busy, send the first 569 * character now. 570 */ 571 KBD->ac_cs = (k->k_soft_cs |= A_TXINT); 572 if (KBD->ac_cs & A_TXRDY) { 573 KBD->ac_da = *cmd++; 574 len--; 575 } 576 577 /* 578 * If we're not yet done, wait until all characters are send. 579 */ 580 if (len > 0) { 581 k->k_sendp = cmd; 582 k->k_send_cnt = len; 583 tsleep((caddr_t)&k->k_send_cnt, TTOPRI, "kbd_write2", 0); 584 } 585 splx(sps); 586 587 /* 588 * Wakeup all procs waiting for us. 589 */ 590 wakeup((caddr_t)&k->k_sendp); 591 } 592 593 /* 594 * Setup softc-fields to assemble a keyboard package. 595 */ 596 static void 597 kbd_pkg_start(kp, msg_start) 598 struct kbd_softc *kp; 599 u_char msg_start; 600 { 601 kp->k_pkg_idx = 1; 602 kp->k_package[0] = msg_start; 603 switch (msg_start) { 604 case 0xf6: 605 kp->k_pkg_type = KBD_MEM_PKG; 606 kp->k_pkg_size = 8; 607 break; 608 case 0xf7: 609 kp->k_pkg_type = KBD_AMS_PKG; 610 kp->k_pkg_size = 6; 611 break; 612 case 0xf8: 613 case 0xf9: 614 case 0xfa: 615 case 0xfb: 616 kp->k_pkg_type = KBD_RMS_PKG; 617 kp->k_pkg_size = 3; 618 break; 619 case 0xfc: 620 kp->k_pkg_type = KBD_CLK_PKG; 621 kp->k_pkg_size = 7; 622 break; 623 case 0xfe: 624 kp->k_pkg_type = KBD_JOY0_PKG; 625 kp->k_pkg_size = 2; 626 break; 627 case 0xff: 628 kp->k_pkg_type = KBD_JOY1_PKG; 629 kp->k_pkg_size = 2; 630 break; 631 default: 632 printf("kbd: Unknown packet 0x%x\n", msg_start); 633 break; 634 } 635 } 636 637 /* 638 * Modifier processing 639 */ 640 static int 641 kbd_do_modifier(code) 642 u_char code; 643 { 644 u_char up, mask; 645 646 up = KBD_RELEASED(code); 647 mask = 0; 648 649 switch(KBD_SCANCODE(code)) { 650 case KBD_LEFT_SHIFT: 651 mask = KBD_MOD_LSHIFT; 652 break; 653 case KBD_RIGHT_SHIFT: 654 mask = KBD_MOD_RSHIFT; 655 break; 656 case KBD_CTRL: 657 mask = KBD_MOD_CTRL; 658 break; 659 case KBD_ALT: 660 mask = KBD_MOD_ALT; 661 break; 662 case KBD_CAPS_LOCK: 663 /* CAPSLOCK is a toggle */ 664 if(!up) 665 kbd_modifier ^= KBD_MOD_CAPS; 666 return 1; 667 } 668 if(mask) { 669 if(up) 670 kbd_modifier &= ~mask; 671 else 672 kbd_modifier |= mask; 673 return 1; 674 } 675 return 0; 676 } 677