1 /* $NetBSD: kbd.c,v 1.15 1997/01/10 21:24:26 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 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 FIONBIO: /* we will remove this someday (soon???) */ 234 return 0; 235 236 case FIOASYNC: 237 k->k_events.ev_async = *(int *)data != 0; 238 return 0; 239 240 case TIOCSPGRP: 241 if (*(int *)data != k->k_events.ev_io->p_pgid) 242 return EPERM; 243 return 0; 244 245 default: 246 return ENOTTY; 247 } 248 249 /* 250 * We identified the ioctl, but we do not handle it. 251 */ 252 return EOPNOTSUPP; /* misuse, but what the heck */ 253 } 254 255 int 256 kbdpoll (dev_t dev, int events, struct proc *p) 257 { 258 return ev_poll (&kbd_softc.k_events, events, p); 259 } 260 261 /* 262 * Keyboard interrupt handler called straight from MFP at spl6. 263 */ 264 void 265 kbdintr(sr) 266 int sr; /* sr at time of interrupt */ 267 { 268 int code; 269 int got_char = 0; 270 271 /* 272 * There may be multiple keys available. Read them all. 273 */ 274 while (KBD->ac_cs & (A_RXRDY|A_OE|A_PE)) { 275 got_char = 1; 276 if (KBD->ac_cs & (A_OE|A_PE)) { 277 code = KBD->ac_da; /* Silently ignore errors */ 278 continue; 279 } 280 kbd_ring[kbd_rbput++ & KBD_RING_MASK] = KBD->ac_da; 281 } 282 283 /* 284 * If characters are waiting for transmit, send them. 285 */ 286 if ((kbd_softc.k_soft_cs & A_TXINT) && (KBD->ac_cs & A_TXRDY)) { 287 if (kbd_softc.k_sendp != NULL) 288 KBD->ac_da = *kbd_softc.k_sendp++; 289 if (--kbd_softc.k_send_cnt <= 0) { 290 /* 291 * The total package has been transmitted, 292 * wakeup anyone waiting for it. 293 */ 294 KBD->ac_cs = (kbd_softc.k_soft_cs &= ~A_TXINT); 295 kbd_softc.k_sendp = NULL; 296 kbd_softc.k_send_cnt = 0; 297 wakeup((caddr_t)&kbd_softc.k_send_cnt); 298 } 299 } 300 301 /* 302 * Activate software-level to handle possible input. 303 */ 304 if (got_char) { 305 if (!BASEPRI(sr)) { 306 if (!kbd_soft++) 307 add_sicallback(kbdsoft, 0, 0); 308 } else { 309 spl1(); 310 kbdsoft(NULL, NULL); 311 } 312 } 313 } 314 315 /* 316 * Keyboard soft interrupt handler 317 */ 318 void 319 kbdsoft(junk1, junk2) 320 void *junk1, *junk2; 321 { 322 int s; 323 u_char code; 324 struct kbd_softc *k = &kbd_softc; 325 struct firm_event *fe; 326 int put; 327 int n, get; 328 329 kbd_soft = 0; 330 get = kbd_rbget; 331 332 for (;;) { 333 n = kbd_rbput; 334 if (get == n) /* We're done */ 335 break; 336 n -= get; 337 if (n > KBD_RING_SIZE) { /* Ring buffer overflow */ 338 get += n - KBD_RING_SIZE; 339 n = KBD_RING_SIZE; 340 } 341 while (--n >= 0) { 342 code = kbd_ring[get++ & KBD_RING_MASK]; 343 344 /* 345 * If collecting a package, stuff it in and 346 * continue. 347 */ 348 if (k->k_pkg_size && (k->k_pkg_idx < k->k_pkg_size)) { 349 k->k_package[k->k_pkg_idx++] = code; 350 if (k->k_pkg_idx == k->k_pkg_size) { 351 /* 352 * Package is complete. 353 */ 354 switch(k->k_pkg_type) { 355 #if NMOUSE > 0 356 case KBD_AMS_PKG: 357 case KBD_RMS_PKG: 358 case KBD_JOY1_PKG: 359 mouse_soft((REL_MOUSE *)k->k_package, 360 k->k_pkg_size, k->k_pkg_type); 361 #endif /* NMOUSE */ 362 } 363 k->k_pkg_size = 0; 364 } 365 continue; 366 } 367 /* 368 * If this is a package header, init pkg. handling. 369 */ 370 if (!KBD_IS_KEY(code)) { 371 kbd_pkg_start(k, code); 372 continue; 373 } 374 if (kbd_do_modifier(code) && !k->k_event_mode) 375 continue; 376 377 /* 378 * if not in event mode, deliver straight to ite to 379 * process key stroke 380 */ 381 if (!k->k_event_mode) { 382 /* Gets to spltty() by itself */ 383 ite_filter(code, ITEFILT_TTY); 384 continue; 385 } 386 387 /* 388 * Keyboard is generating events. Turn this keystroke 389 * into an event and put it in the queue. If the queue 390 * is full, the keystroke is lost (sorry!). 391 */ 392 s = spltty(); 393 put = k->k_events.ev_put; 394 fe = &k->k_events.ev_q[put]; 395 put = (put + 1) % EV_QSIZE; 396 if (put == k->k_events.ev_get) { 397 log(LOG_WARNING, 398 "keyboard event queue overflow\n"); 399 splx(s); 400 continue; 401 } 402 fe->id = KBD_SCANCODE(code); 403 fe->value = KBD_RELEASED(code) ? VKEY_UP : VKEY_DOWN; 404 fe->time = time; 405 k->k_events.ev_put = put; 406 EV_WAKEUP(&k->k_events); 407 splx(s); 408 } 409 kbd_rbget = get; 410 } 411 } 412 413 static char sound[] = { 414 0xA8,0x01,0xA9,0x01,0xAA,0x01,0x00, 415 0xF8,0x10,0x10,0x10,0x00,0x20,0x03 416 }; 417 418 void 419 kbdbell() 420 { 421 register int i, sps; 422 423 sps = splhigh(); 424 for (i = 0; i < sizeof(sound); i++) { 425 YM2149->sd_selr = i; 426 YM2149->sd_wdat = sound[i]; 427 } 428 splx(sps); 429 } 430 431 int 432 kbdgetcn() 433 { 434 u_char code; 435 int s = spltty(); 436 int ints_active; 437 438 ints_active = 0; 439 if (MFP->mf_imrb & IB_AINT) { 440 ints_active = 1; 441 MFP->mf_imrb &= ~IB_AINT; 442 } 443 for (;;) { 444 while (!((KBD->ac_cs & (A_IRQ|A_RXRDY)) == (A_IRQ|A_RXRDY))) 445 ; /* Wait for key */ 446 if (KBD->ac_cs & (A_OE|A_PE)) { 447 code = KBD->ac_da; /* Silently ignore errors */ 448 continue; 449 } 450 code = KBD->ac_da; 451 if (!kbd_do_modifier(code)) 452 break; 453 } 454 455 if (ints_active) { 456 MFP->mf_iprb &= ~IB_AINT; 457 MFP->mf_imrb |= IB_AINT; 458 } 459 460 splx (s); 461 return code; 462 } 463 464 /* 465 * Write a command to the keyboard in 'polled' mode. 466 */ 467 static int 468 kbd_write_poll(cmd, len) 469 u_char *cmd; 470 int len; 471 { 472 int timeout; 473 474 while (len-- > 0) { 475 KBD->ac_da = *cmd++; 476 for (timeout = 100; !(KBD->ac_cs & A_TXRDY); timeout--) 477 delay(10); 478 if (!(KBD->ac_cs & A_TXRDY)) 479 return (0); 480 } 481 return (1); 482 } 483 484 /* 485 * Write a command to the keyboard. Return when command is send. 486 */ 487 void 488 kbd_write(cmd, len) 489 u_char *cmd; 490 int len; 491 { 492 struct kbd_softc *k = &kbd_softc; 493 int sps; 494 495 /* 496 * Get to splhigh, 'real' interrupts arrive at spl6! 497 */ 498 sps = splhigh(); 499 500 /* 501 * Make sure any privious write has ended... 502 */ 503 while (k->k_sendp != NULL) 504 tsleep((caddr_t)&k->k_sendp, TTOPRI, "kbd_write1", 0); 505 506 /* 507 * If the KBD-acia is not currently busy, send the first 508 * character now. 509 */ 510 KBD->ac_cs = (k->k_soft_cs |= A_TXINT); 511 if (KBD->ac_cs & A_TXRDY) { 512 KBD->ac_da = *cmd++; 513 len--; 514 } 515 516 /* 517 * If we're not yet done, wait until all characters are send. 518 */ 519 if (len > 0) { 520 k->k_sendp = cmd; 521 k->k_send_cnt = len; 522 tsleep((caddr_t)&k->k_send_cnt, TTOPRI, "kbd_write2", 0); 523 } 524 splx(sps); 525 526 /* 527 * Wakeup all procs waiting for us. 528 */ 529 wakeup((caddr_t)&k->k_sendp); 530 } 531 532 /* 533 * Setup softc-fields to assemble a keyboard package. 534 */ 535 static void 536 kbd_pkg_start(kp, msg_start) 537 struct kbd_softc *kp; 538 u_char msg_start; 539 { 540 kp->k_pkg_idx = 1; 541 kp->k_package[0] = msg_start; 542 switch (msg_start) { 543 case 0xf6: 544 kp->k_pkg_type = KBD_MEM_PKG; 545 kp->k_pkg_size = 8; 546 break; 547 case 0xf7: 548 kp->k_pkg_type = KBD_AMS_PKG; 549 kp->k_pkg_size = 6; 550 break; 551 case 0xf8: 552 case 0xf9: 553 case 0xfa: 554 case 0xfb: 555 kp->k_pkg_type = KBD_RMS_PKG; 556 kp->k_pkg_size = 3; 557 break; 558 case 0xfc: 559 kp->k_pkg_type = KBD_CLK_PKG; 560 kp->k_pkg_size = 7; 561 break; 562 case 0xfe: 563 kp->k_pkg_type = KBD_JOY0_PKG; 564 kp->k_pkg_size = 2; 565 break; 566 case 0xff: 567 kp->k_pkg_type = KBD_JOY1_PKG; 568 kp->k_pkg_size = 2; 569 break; 570 default: 571 printf("kbd: Unknown packet 0x%x\n", msg_start); 572 break; 573 } 574 } 575 576 /* 577 * Modifier processing 578 */ 579 static int 580 kbd_do_modifier(code) 581 u_char code; 582 { 583 u_char up, mask; 584 585 up = KBD_RELEASED(code); 586 mask = 0; 587 588 switch(KBD_SCANCODE(code)) { 589 case KBD_LEFT_SHIFT: 590 mask = KBD_MOD_LSHIFT; 591 break; 592 case KBD_RIGHT_SHIFT: 593 mask = KBD_MOD_RSHIFT; 594 break; 595 case KBD_CTRL: 596 mask = KBD_MOD_CTRL; 597 break; 598 case KBD_ALT: 599 mask = KBD_MOD_ALT; 600 break; 601 case KBD_CAPS_LOCK: 602 /* CAPSLOCK is a toggle */ 603 if(!up) 604 kbd_modifier ^= KBD_MOD_CAPS; 605 return 1; 606 } 607 if(mask) { 608 if(up) 609 kbd_modifier &= ~mask; 610 else 611 kbd_modifier |= mask; 612 return 1; 613 } 614 return 0; 615 } 616