1 /* $NetBSD: kbd.c,v 1.22 2002/10/23 09:10:52 jdolecek 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 dev_type_kqfilter(kbdkqfilter); 80 81 /* Interrupt handler */ 82 void kbdintr __P((int)); 83 84 static void kbdsoft __P((void *, void *)); 85 static void kbdattach __P((struct device *, struct device *, void *)); 86 static int kbdmatch __P((struct device *, struct cfdata *, void *)); 87 static int kbd_do_modifier __P((u_char)); 88 static int kbd_write_poll __P((u_char *, int)); 89 static void kbd_pkg_start __P((struct kbd_softc *, u_char)); 90 91 CFATTACH_DECL(kbd, sizeof(struct device), 92 kbdmatch, kbdattach, NULL, NULL); 93 94 const struct cdevsw kbd_cdevsw = { 95 kbdopen, kbdclose, kbdread, nowrite, kbdioctl, 96 nostop, notty, kbdpoll, nommap, kbdkqfilter, 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 = (u_int8_t)~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 int 271 kbdkqfilter(dev_t dev, struct knote *kn) 272 { 273 274 return (ev_kqfilter(&kbd_softc.k_events, kn)); 275 } 276 277 /* 278 * Keyboard interrupt handler called straight from MFP at spl6. 279 */ 280 void 281 kbdintr(sr) 282 int sr; /* sr at time of interrupt */ 283 { 284 int code; 285 int got_char = 0; 286 287 /* 288 * There may be multiple keys available. Read them all. 289 */ 290 while (KBD->ac_cs & (A_RXRDY|A_OE|A_PE)) { 291 got_char = 1; 292 if (KBD->ac_cs & (A_OE|A_PE)) { 293 code = KBD->ac_da; /* Silently ignore errors */ 294 continue; 295 } 296 kbd_ring[kbd_rbput++ & KBD_RING_MASK] = KBD->ac_da; 297 } 298 299 /* 300 * If characters are waiting for transmit, send them. 301 */ 302 if ((kbd_softc.k_soft_cs & A_TXINT) && (KBD->ac_cs & A_TXRDY)) { 303 if (kbd_softc.k_sendp != NULL) 304 KBD->ac_da = *kbd_softc.k_sendp++; 305 if (--kbd_softc.k_send_cnt <= 0) { 306 /* 307 * The total package has been transmitted, 308 * wakeup anyone waiting for it. 309 */ 310 KBD->ac_cs = (kbd_softc.k_soft_cs &= ~A_TXINT); 311 kbd_softc.k_sendp = NULL; 312 kbd_softc.k_send_cnt = 0; 313 wakeup((caddr_t)&kbd_softc.k_send_cnt); 314 } 315 } 316 317 /* 318 * Activate software-level to handle possible input. 319 */ 320 if (got_char) { 321 if (!BASEPRI(sr)) { 322 if (!kbd_soft++) 323 add_sicallback(kbdsoft, 0, 0); 324 } else { 325 spl1(); 326 kbdsoft(NULL, NULL); 327 } 328 } 329 } 330 331 /* 332 * Keyboard soft interrupt handler 333 */ 334 void 335 kbdsoft(junk1, junk2) 336 void *junk1, *junk2; 337 { 338 int s; 339 u_char code; 340 struct kbd_softc *k = &kbd_softc; 341 struct firm_event *fe; 342 int put; 343 int n, get; 344 345 kbd_soft = 0; 346 get = kbd_rbget; 347 348 for (;;) { 349 n = kbd_rbput; 350 if (get == n) /* We're done */ 351 break; 352 n -= get; 353 if (n > KBD_RING_SIZE) { /* Ring buffer overflow */ 354 get += n - KBD_RING_SIZE; 355 n = KBD_RING_SIZE; 356 } 357 while (--n >= 0) { 358 code = kbd_ring[get++ & KBD_RING_MASK]; 359 360 /* 361 * If collecting a package, stuff it in and 362 * continue. 363 */ 364 if (k->k_pkg_size && (k->k_pkg_idx < k->k_pkg_size)) { 365 k->k_package[k->k_pkg_idx++] = code; 366 if (k->k_pkg_idx == k->k_pkg_size) { 367 /* 368 * Package is complete. 369 */ 370 switch(k->k_pkg_type) { 371 #if NMOUSE > 0 372 case KBD_AMS_PKG: 373 case KBD_RMS_PKG: 374 case KBD_JOY1_PKG: 375 mouse_soft((REL_MOUSE *)k->k_package, 376 k->k_pkg_size, k->k_pkg_type); 377 #endif /* NMOUSE */ 378 } 379 k->k_pkg_size = 0; 380 } 381 continue; 382 } 383 /* 384 * If this is a package header, init pkg. handling. 385 */ 386 if (!KBD_IS_KEY(code)) { 387 kbd_pkg_start(k, code); 388 continue; 389 } 390 if (kbd_do_modifier(code) && !k->k_event_mode) 391 continue; 392 393 /* 394 * if not in event mode, deliver straight to ite to 395 * process key stroke 396 */ 397 if (!k->k_event_mode) { 398 /* Gets to spltty() by itself */ 399 ite_filter(code, ITEFILT_TTY); 400 continue; 401 } 402 403 /* 404 * Keyboard is generating events. Turn this keystroke 405 * into an event and put it in the queue. If the queue 406 * is full, the keystroke is lost (sorry!). 407 */ 408 s = spltty(); 409 put = k->k_events.ev_put; 410 fe = &k->k_events.ev_q[put]; 411 put = (put + 1) % EV_QSIZE; 412 if (put == k->k_events.ev_get) { 413 log(LOG_WARNING, 414 "keyboard event queue overflow\n"); 415 splx(s); 416 continue; 417 } 418 fe->id = KBD_SCANCODE(code); 419 fe->value = KBD_RELEASED(code) ? VKEY_UP : VKEY_DOWN; 420 fe->time = time; 421 k->k_events.ev_put = put; 422 EV_WAKEUP(&k->k_events); 423 splx(s); 424 } 425 kbd_rbget = get; 426 } 427 } 428 429 static u_char sound[] = { 430 0xA8,0x01,0xA9,0x01,0xAA,0x01,0x00, 431 0xF8,0x10,0x10,0x10,0x00,0x20,0x03 432 }; 433 434 void 435 kbdbell() 436 { 437 register int i, sps; 438 439 sps = splhigh(); 440 for (i = 0; i < sizeof(sound); i++) { 441 YM2149->sd_selr = i; 442 YM2149->sd_wdat = sound[i]; 443 } 444 splx(sps); 445 } 446 447 448 /* 449 * Set the parameters of the 'default' beep. 450 */ 451 452 #define KBDBELLCLOCK 125000 /* 2MHz / 16 */ 453 #define KBDBELLDURATION 128 /* 256 / 2MHz */ 454 455 void 456 kbd_bell_gparms(volume, pitch, duration) 457 u_int *volume, *pitch, *duration; 458 { 459 u_int tmp; 460 461 tmp = sound[11] | (sound[12] << 8); 462 *duration = (tmp * KBDBELLDURATION) / 1000; 463 464 tmp = sound[0] | (sound[1] << 8); 465 *pitch = KBDBELLCLOCK / tmp; 466 467 *volume = 0; 468 } 469 470 void 471 kbd_bell_sparms(volume, pitch, duration) 472 u_int volume, pitch, duration; 473 { 474 u_int f, t; 475 476 f = pitch > 10 ? pitch : 10; /* minimum pitch */ 477 if (f > 20000) 478 f = 20000; /* maximum pitch */ 479 480 f = KBDBELLCLOCK / f; 481 482 t = (duration * 1000) / KBDBELLDURATION; 483 484 sound[ 0] = f & 0xff; 485 sound[ 1] = (f >> 8) & 0xf; 486 f -= 1; 487 sound[ 2] = f & 0xff; 488 sound[ 3] = (f >> 8) & 0xf; 489 f += 2; 490 sound[ 4] = f & 0xff; 491 sound[ 5] = (f >> 8) & 0xf; 492 493 sound[11] = t & 0xff; 494 sound[12] = (t >> 8) & 0xff; 495 496 sound[13] = 0x03; 497 } 498 499 int 500 kbdgetcn() 501 { 502 u_char code; 503 int s = spltty(); 504 int ints_active; 505 506 ints_active = 0; 507 if (MFP->mf_imrb & IB_AINT) { 508 ints_active = 1; 509 MFP->mf_imrb &= ~IB_AINT; 510 } 511 for (;;) { 512 while (!((KBD->ac_cs & (A_IRQ|A_RXRDY)) == (A_IRQ|A_RXRDY))) 513 ; /* Wait for key */ 514 if (KBD->ac_cs & (A_OE|A_PE)) { 515 code = KBD->ac_da; /* Silently ignore errors */ 516 continue; 517 } 518 code = KBD->ac_da; 519 if (!kbd_do_modifier(code)) 520 break; 521 } 522 523 if (ints_active) { 524 MFP->mf_iprb = (u_int8_t)~IB_AINT; 525 MFP->mf_imrb |= IB_AINT; 526 } 527 528 splx (s); 529 return code; 530 } 531 532 /* 533 * Write a command to the keyboard in 'polled' mode. 534 */ 535 static int 536 kbd_write_poll(cmd, len) 537 u_char *cmd; 538 int len; 539 { 540 int timeout; 541 542 while (len-- > 0) { 543 KBD->ac_da = *cmd++; 544 for (timeout = 100; !(KBD->ac_cs & A_TXRDY); timeout--) 545 delay(10); 546 if (!(KBD->ac_cs & A_TXRDY)) 547 return (0); 548 } 549 return (1); 550 } 551 552 /* 553 * Write a command to the keyboard. Return when command is send. 554 */ 555 void 556 kbd_write(cmd, len) 557 u_char *cmd; 558 int len; 559 { 560 struct kbd_softc *k = &kbd_softc; 561 int sps; 562 563 /* 564 * Get to splhigh, 'real' interrupts arrive at spl6! 565 */ 566 sps = splhigh(); 567 568 /* 569 * Make sure any privious write has ended... 570 */ 571 while (k->k_sendp != NULL) 572 tsleep((caddr_t)&k->k_sendp, TTOPRI, "kbd_write1", 0); 573 574 /* 575 * If the KBD-acia is not currently busy, send the first 576 * character now. 577 */ 578 KBD->ac_cs = (k->k_soft_cs |= A_TXINT); 579 if (KBD->ac_cs & A_TXRDY) { 580 KBD->ac_da = *cmd++; 581 len--; 582 } 583 584 /* 585 * If we're not yet done, wait until all characters are send. 586 */ 587 if (len > 0) { 588 k->k_sendp = cmd; 589 k->k_send_cnt = len; 590 tsleep((caddr_t)&k->k_send_cnt, TTOPRI, "kbd_write2", 0); 591 } 592 splx(sps); 593 594 /* 595 * Wakeup all procs waiting for us. 596 */ 597 wakeup((caddr_t)&k->k_sendp); 598 } 599 600 /* 601 * Setup softc-fields to assemble a keyboard package. 602 */ 603 static void 604 kbd_pkg_start(kp, msg_start) 605 struct kbd_softc *kp; 606 u_char msg_start; 607 { 608 kp->k_pkg_idx = 1; 609 kp->k_package[0] = msg_start; 610 switch (msg_start) { 611 case 0xf6: 612 kp->k_pkg_type = KBD_MEM_PKG; 613 kp->k_pkg_size = 8; 614 break; 615 case 0xf7: 616 kp->k_pkg_type = KBD_AMS_PKG; 617 kp->k_pkg_size = 6; 618 break; 619 case 0xf8: 620 case 0xf9: 621 case 0xfa: 622 case 0xfb: 623 kp->k_pkg_type = KBD_RMS_PKG; 624 kp->k_pkg_size = 3; 625 break; 626 case 0xfc: 627 kp->k_pkg_type = KBD_CLK_PKG; 628 kp->k_pkg_size = 7; 629 break; 630 case 0xfe: 631 kp->k_pkg_type = KBD_JOY0_PKG; 632 kp->k_pkg_size = 2; 633 break; 634 case 0xff: 635 kp->k_pkg_type = KBD_JOY1_PKG; 636 kp->k_pkg_size = 2; 637 break; 638 default: 639 printf("kbd: Unknown packet 0x%x\n", msg_start); 640 break; 641 } 642 } 643 644 /* 645 * Modifier processing 646 */ 647 static int 648 kbd_do_modifier(code) 649 u_char code; 650 { 651 u_char up, mask; 652 653 up = KBD_RELEASED(code); 654 mask = 0; 655 656 switch(KBD_SCANCODE(code)) { 657 case KBD_LEFT_SHIFT: 658 mask = KBD_MOD_LSHIFT; 659 break; 660 case KBD_RIGHT_SHIFT: 661 mask = KBD_MOD_RSHIFT; 662 break; 663 case KBD_CTRL: 664 mask = KBD_MOD_CTRL; 665 break; 666 case KBD_ALT: 667 mask = KBD_MOD_ALT; 668 break; 669 case KBD_CAPS_LOCK: 670 /* CAPSLOCK is a toggle */ 671 if(!up) 672 kbd_modifier ^= KBD_MOD_CAPS; 673 return 1; 674 } 675 if(mask) { 676 if(up) 677 kbd_modifier &= ~mask; 678 else 679 kbd_modifier |= mask; 680 return 1; 681 } 682 return 0; 683 } 684