1 /* $NetBSD: kbd.c,v 1.34 2000/05/25 18:39:09 is Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * kbd.c 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/file.h> 44 #include <sys/kernel.h> 45 #include <sys/syslog.h> 46 #include <sys/signalvar.h> 47 #include <dev/cons.h> 48 #include <machine/cpu.h> 49 #include <amiga/amiga/device.h> 50 #include <amiga/amiga/custom.h> 51 #ifdef DRACO 52 #include <m68k/asm_single.h> 53 #include <amiga/amiga/drcustom.h> 54 #endif 55 #include <amiga/amiga/cia.h> 56 #include <amiga/dev/itevar.h> 57 #include <amiga/dev/kbdreg.h> 58 #include <amiga/dev/kbdmap.h> 59 #include <amiga/dev/event_var.h> 60 #include <amiga/dev/vuid_event.h> 61 #include "kbd.h" 62 63 #include <sys/conf.h> 64 #include <machine/conf.h> 65 66 struct kbd_softc { 67 int k_event_mode; /* if true, collect events, else pass to ite */ 68 struct evvar k_events; /* event queue state */ 69 #ifdef DRACO 70 u_char k_rlprfx; /* MF-II rel. prefix has been seen */ 71 u_char k_mf2; 72 #endif 73 }; 74 struct kbd_softc kbd_softc; 75 76 int kbdmatch __P((struct device *, struct cfdata *, void *)); 77 void kbdattach __P((struct device *, struct device *, void *)); 78 void kbdintr __P((int)); 79 void kbdstuffchar __P((u_char)); 80 81 int drkbdgetc __P((void)); 82 int drkbdrputc __P((int)); 83 int drkbdputc __P((int)); 84 int drkbdputc2 __P((int, int)); 85 int drkbdwaitfor __P((int)); 86 87 struct cfattach kbd_ca = { 88 sizeof(struct device), kbdmatch, kbdattach 89 }; 90 91 /*ARGSUSED*/ 92 int 93 kbdmatch(pdp, cfp, auxp) 94 struct device *pdp; 95 struct cfdata *cfp; 96 void *auxp; 97 { 98 99 if (matchname((char *)auxp, "kbd")) 100 return(1); 101 return(0); 102 } 103 104 /*ARGSUSED*/ 105 void 106 kbdattach(pdp, dp, auxp) 107 struct device *pdp, *dp; 108 void *auxp; 109 { 110 #ifdef DRACO 111 kbdenable(); 112 if (kbd_softc.k_mf2) 113 printf(": QuickLogic type MF-II\n"); 114 else 115 printf(": CIA A type Amiga\n"); 116 #else 117 printf(": CIA A type Amiga\n"); 118 #endif 119 120 } 121 122 /* definitions for amiga keyboard encoding. */ 123 #define KEY_CODE(c) ((c) & 0x7f) 124 #define KEY_UP(c) ((c) & 0x80) 125 126 #define DATLO single_inst_bclr_b(draco_ioct->io_control, DRCNTRL_KBDDATOUT) 127 #define DATHI single_inst_bset_b(draco_ioct->io_control, DRCNTRL_KBDDATOUT) 128 129 #define CLKLO single_inst_bclr_b(draco_ioct->io_control, DRCNTRL_KBDCLKOUT) 130 #define CLKHI single_inst_bset_b(draco_ioct->io_control, DRCNTRL_KBDCLKOUT) 131 132 void 133 kbdenable() 134 { 135 static int kbd_inited = 0; 136 137 int s; 138 139 #ifdef DRACO 140 int id; 141 #endif 142 /* 143 * collides with external ints from SCSI, watch out for this when 144 * enabling/disabling interrupts there !! 145 */ 146 s = splhigh(); /* don't lower; might be called from early ddb */ 147 if (kbd_inited) { 148 splx(s); 149 return; 150 } 151 kbd_inited = 1; 152 #ifdef DRACO 153 if (is_draco()) { 154 155 CLKLO; 156 delay(5000); 157 draco_ioct->io_kbdrst = 0; 158 159 if (drkbdputc(0xf2)) 160 goto LnoMFII; 161 162 id = drkbdgetc() << 8; 163 id |= drkbdgetc(); 164 165 if (id != 0xab83) 166 goto LnoMFII; 167 168 if (drkbdputc2(0xf0, 3)) /* mode 3 */ 169 goto LnoMFII; 170 171 if (drkbdputc(0xf8)) /* make/break, no typematic */ 172 goto LnoMFII; 173 174 if (drkbdputc(0xf4)) /* enable */ 175 goto LnoMFII; 176 kbd_softc.k_mf2 = 1; 177 single_inst_bclr_b(draco_ioct->io_control, DRCNTRL_KBDINTENA); 178 179 ciaa.icr = CIA_ICR_SP; /* CIA SP interrupt disable */ 180 ciaa.cra &= ~(1<<6); /* serial line == input */ 181 splx(s); 182 return; 183 184 LnoMFII: 185 kbd_softc.k_mf2 = 0; 186 single_inst_bset_b(*draco_intena, DRIRQ_INT2); 187 ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_SP; 188 /* SP interrupt enable */ 189 ciaa.cra &= ~(1<<6); /* serial line == input */ 190 splx(s); 191 return; 192 193 } else { 194 #endif 195 custom.intena = INTF_SETCLR | INTF_PORTS; 196 ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_SP; /* SP interrupt enable */ 197 ciaa.cra &= ~(1<<6); /* serial line == input */ 198 #ifdef DRACO 199 } 200 #endif 201 kbd_softc.k_event_mode = 0; 202 kbd_softc.k_events.ev_io = 0; 203 splx(s); 204 } 205 206 #ifdef DRACO 207 /* 208 * call this with kbd interupt blocked 209 */ 210 211 int 212 drkbdgetc() 213 { 214 u_int8_t in; 215 216 while ((draco_ioct->io_status & DRSTAT_KBDRECV) == 0); 217 in = draco_ioct->io_kbddata; 218 draco_ioct->io_kbdrst = 0; 219 220 return in; 221 } 222 223 #define WAIT0 if (drkbdwaitfor(0)) goto Ltimeout 224 #define WAIT1 if (drkbdwaitfor(DRSTAT_KBDCLKIN)) goto Ltimeout 225 226 int 227 drkbdwaitfor(bit) 228 int bit; 229 { 230 int i; 231 232 233 234 i = 60000; /* about 50 ms max */ 235 236 do { 237 if ((draco_ioct->io_status & DRSTAT_KBDCLKIN) == bit) 238 return 0; 239 240 } while (--i >= 0); 241 242 return 1; 243 } 244 245 /* 246 * Output a raw byte to the keyboard (+ parity and stop bit). 247 * return 0 on success, 1 on timeout. 248 */ 249 int 250 drkbdrputc(c) 251 u_int8_t c; 252 { 253 u_int8_t parity; 254 int bitcnt; 255 256 DATLO; CLKHI; WAIT1; 257 parity = 0; 258 259 for (bitcnt=7; bitcnt >= 0; bitcnt--) { 260 WAIT0; 261 if (c & 1) { 262 DATHI; 263 } else { 264 ++parity; 265 DATLO; 266 } 267 c >>= 1; 268 WAIT1; 269 } 270 WAIT0; 271 /* parity bit */ 272 if (parity & 1) { 273 DATLO; 274 } else { 275 DATHI; 276 } 277 WAIT1; 278 /* stop bit */ 279 WAIT0; DATHI; WAIT1; 280 281 WAIT0; /* XXX should check the ack bit here... */ 282 WAIT1; 283 draco_ioct->io_kbdrst = 0; 284 return 0; 285 286 Ltimeout: 287 DATHI; 288 draco_ioct->io_kbdrst = 0; 289 return 1; 290 } 291 292 /* 293 * Output one cooked byte to the keyboard, with wait for ACK or RESEND, 294 * and retry if necessary. 0 == success, 1 == timeout 295 */ 296 int 297 drkbdputc(c) 298 u_int8_t c; 299 { 300 int rc; 301 302 do { 303 if (drkbdrputc(c)) 304 return(-1); 305 306 rc = drkbdgetc(); 307 } while (rc == 0xfe); 308 return (!(rc == 0xfa)); 309 } 310 311 /* 312 * same for twobyte sequence 313 */ 314 315 int 316 drkbdputc2(c1, c2) 317 u_int8_t c1, c2; 318 { 319 int rc; 320 321 do { 322 do { 323 if (drkbdrputc(c1)) 324 return(-1); 325 326 rc = drkbdgetc(); 327 } while (rc == 0xfe); 328 if (rc != 0xfa) 329 return (-1); 330 331 if (drkbdrputc(c2)) 332 return(-1); 333 334 rc = drkbdgetc(); 335 } while (rc == 0xfe); 336 return (!(rc == 0xfa)); 337 } 338 #endif 339 340 int 341 kbdopen(dev, flags, mode, p) 342 dev_t dev; 343 int flags, mode; 344 struct proc *p; 345 { 346 347 kbdenable(); 348 if (kbd_softc.k_events.ev_io) 349 return EBUSY; 350 351 kbd_softc.k_events.ev_io = p; 352 ev_init(&kbd_softc.k_events); 353 return (0); 354 } 355 356 int 357 kbdclose(dev, flags, mode, p) 358 dev_t dev; 359 int flags, mode; 360 struct proc *p; 361 { 362 363 /* Turn off event mode, dump the queue */ 364 kbd_softc.k_event_mode = 0; 365 ev_fini(&kbd_softc.k_events); 366 kbd_softc.k_events.ev_io = NULL; 367 return (0); 368 } 369 370 int 371 kbdread(dev, uio, flags) 372 dev_t dev; 373 struct uio *uio; 374 int flags; 375 { 376 return ev_read (&kbd_softc.k_events, uio, flags); 377 } 378 379 int 380 kbdioctl(dev, cmd, data, flag, p) 381 dev_t dev; 382 u_long cmd; 383 register caddr_t data; 384 int flag; 385 struct proc *p; 386 { 387 register struct kbd_softc *k = &kbd_softc; 388 389 switch (cmd) { 390 case KIOCTRANS: 391 if (*(int *)data == TR_UNTRANS_EVENT) 392 return 0; 393 break; 394 395 case KIOCGTRANS: 396 /* Get translation mode */ 397 *(int *)data = TR_UNTRANS_EVENT; 398 return 0; 399 400 case KIOCSDIRECT: 401 k->k_event_mode = *(int *)data; 402 return 0; 403 404 case FIONBIO: /* we will remove this someday (soon???) */ 405 return 0; 406 407 case FIOASYNC: 408 k->k_events.ev_async = *(int *)data != 0; 409 return 0; 410 411 case TIOCSPGRP: 412 if (*(int *)data != k->k_events.ev_io->p_pgid) 413 return EPERM; 414 return 0; 415 416 default: 417 return ENOTTY; 418 } 419 420 /* We identified the ioctl, but we do not handle it. */ 421 return EOPNOTSUPP; /* misuse, but what the heck */ 422 } 423 424 int 425 kbdpoll(dev, events, p) 426 dev_t dev; 427 int events; 428 struct proc *p; 429 { 430 return ev_poll (&kbd_softc.k_events, events, p); 431 } 432 433 434 void 435 kbdintr(mask) 436 int mask; 437 { 438 u_char c; 439 #ifdef KBDRESET 440 static int reset_warn; 441 #endif 442 443 /* 444 * now only invoked from generic CIA interrupt handler if there *is* 445 * a keyboard interrupt pending 446 */ 447 448 c = ~ciaa.sdr; /* keyboard data is inverted */ 449 /* ack */ 450 ciaa.cra |= (1 << 6); /* serial line output */ 451 #ifdef KBDRESET 452 if (reset_warn && c == 0xf0) { 453 #ifdef DEBUG 454 printf ("kbdintr: !!!! Reset Warning !!!!\n"); 455 #endif 456 bootsync(); 457 reset_warn = 0; 458 DELAY(30000000); 459 } 460 #endif 461 /* wait 200 microseconds (for bloody Cherry keyboards..) */ 462 DELAY(2000); /* fudge delay a bit for some keyboards */ 463 ciaa.cra &= ~(1 << 6); 464 465 /* process the character */ 466 c = (c >> 1) | (c << 7); /* rotate right once */ 467 468 #ifdef KBDRESET 469 if (c == 0x78) { 470 #ifdef DEBUG 471 printf ("kbdintr: Reset Warning started\n"); 472 #endif 473 ++reset_warn; 474 return; 475 } 476 #endif 477 kbdstuffchar(c); 478 } 479 480 #ifdef DRACO 481 /* maps MF-II keycodes to Amiga keycodes */ 482 483 const u_char drkbdtab[] = { 484 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x50, 485 0x45, 0xff, 0xff, 0xff, 0xff, 0x42, 0x00, 0x51, 486 487 0xff, 0x64, 0x60, 0x30, 0x63, 0x10, 0x01, 0x52, 488 0xff, 0x66, 0x31, 0x21, 0x20, 0x11, 0x02, 0x53, 489 490 0xff, 0x33, 0x32, 0x22, 0x12, 0x04, 0x03, 0x54, 491 0xff, 0x40, 0x34, 0x23, 0x14, 0x13, 0x05, 0x55, 492 493 0xff, 0x36, 0x35, 0x25, 0x24, 0x15, 0x06, 0x56, 494 0xff, 0x67, 0x37, 0x26, 0x16, 0x07, 0x08, 0x57, 495 /* --- */ 496 0xff, 0x38, 0x27, 0x17, 0x18, 0x0a, 0x09, 0x58, 497 0xff, 0x39, 0x3a, 0x28, 0x29, 0x19, 0x0b, 0x59, 498 499 0xff, 0xff, 0x2a, 0x2b, 0x1a, 0x0c, 0x4b, 0xff, 500 0x65, 0x61, 0x44, 0x1b, 0xff, 0xff, 0x6f, 0xff, 501 502 0x4d, 0x4f, 0xff, 0x4c, 0x0d, 0xff, 0x41, 0x46, 503 0xff, 0x1d, 0x4e, 0x2d, 0x3d, 0x4a, 0x5f, 0x62, 504 505 0x0f, 0x3c, 0x1e, 0x2e, 0x2f, 0x3e, 0x5a, 0x5b, 506 0xff, 0x43, 0x1f, 0xff, 0x5e, 0x3f, 0x5c, 0xff, 507 /* --- */ 508 0xff, 0xff, 0xff, 0xff, 0x5d 509 }; 510 #endif 511 512 513 int 514 kbdgetcn () 515 { 516 int s; 517 u_char ints, mask, c, in; 518 519 #ifdef DRACO 520 if (is_draco() && kbd_softc.k_mf2) { 521 do { 522 c = 0; 523 s = spltty (); 524 while ((draco_ioct->io_status & DRSTAT_KBDRECV) == 0); 525 in = draco_ioct->io_kbddata; 526 draco_ioct->io_kbdrst = 0; 527 if (in == 0xF0) { /* release prefix */ 528 c = 0x80; 529 while ((draco_ioct->io_status & 530 DRSTAT_KBDRECV) == 0); 531 in = draco_ioct->io_kbddata; 532 draco_ioct->io_kbdrst = 0; 533 } 534 splx(s); 535 #ifdef DRACORAWKEYDEBUG 536 printf("<%02x>", in); 537 #endif 538 c |= in>=sizeof(drkbdtab) ? 0xff : drkbdtab[in]; 539 } while (c == 0xff); 540 return (c); 541 } 542 #endif 543 s = spltty(); 544 for (ints = 0; ! ((mask = ciaa.icr) & CIA_ICR_SP); 545 ints |= mask) ; 546 547 in = ciaa.sdr; 548 c = ~in; 549 550 /* ack */ 551 ciaa.cra |= (1 << 6); /* serial line output */ 552 ciaa.sdr = 0xff; /* ack */ 553 /* wait 200 microseconds */ 554 DELAY(2000); /* XXXX only works as long as DELAY doesn't 555 * use a timer and waits.. */ 556 ciaa.cra &= ~(1 << 6); 557 ciaa.sdr = in; 558 559 splx (s); 560 c = (c >> 1) | (c << 7); 561 562 /* take care that no CIA-interrupts are lost */ 563 if (ints) 564 dispatch_cia_ints (0, ints); 565 566 return c; 567 } 568 569 void 570 kbdstuffchar(c) 571 u_char c; 572 { 573 struct firm_event *fe; 574 struct kbd_softc *k = &kbd_softc; 575 int put; 576 577 /* 578 * If not in event mode, deliver straight to ite to process 579 * key stroke 580 */ 581 582 if (! k->k_event_mode) { 583 ite_filter (c, ITEFILT_TTY); 584 return; 585 } 586 587 /* 588 * Keyboard is generating events. Turn this keystroke into an 589 * event and put it in the queue. If the queue is full, the 590 * keystroke is lost (sorry!). 591 */ 592 593 put = k->k_events.ev_put; 594 fe = &k->k_events.ev_q[put]; 595 put = (put + 1) % EV_QSIZE; 596 if (put == k->k_events.ev_get) { 597 log(LOG_WARNING, "keyboard event queue overflow\n"); 598 /* ??? */ 599 return; 600 } 601 fe->id = KEY_CODE(c); 602 fe->value = KEY_UP(c) ? VKEY_UP : VKEY_DOWN; 603 fe->time = time; 604 k->k_events.ev_put = put; 605 EV_WAKEUP(&k->k_events); 606 } 607 608 609 #ifdef DRACO 610 void 611 drkbdintr() 612 { 613 u_char in; 614 struct kbd_softc *k = &kbd_softc; 615 616 in = draco_ioct->io_kbddata; 617 draco_ioct->io_kbdrst = 0; 618 619 if (in == 0xF0) 620 k->k_rlprfx = 0x80; 621 else { 622 kbdstuffchar(in>=sizeof(drkbdtab) ? 0xff : 623 drkbdtab[in] | k->k_rlprfx); 624 k->k_rlprfx = 0; 625 } 626 } 627 628 #endif 629