1 /* $NetBSD: kbd.c,v 1.23 1996/09/14 14:55:08 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 <amiga/amiga/drcustom.h> 53 #endif 54 #include <amiga/amiga/cia.h> 55 #include <amiga/dev/itevar.h> 56 #include <amiga/dev/kbdreg.h> 57 #include <amiga/dev/kbdmap.h> 58 #include <amiga/dev/event_var.h> 59 #include <amiga/dev/vuid_event.h> 60 #include "kbd.h" 61 62 #include <sys/conf.h> 63 #include <machine/conf.h> 64 65 struct kbd_softc { 66 int k_event_mode; /* if true, collect events, else pass to ite */ 67 struct evvar k_events; /* event queue state */ 68 #ifdef DRACO 69 u_char k_rlprfx; /* MF-II rel. prefix has been seen */ 70 #endif 71 }; 72 struct kbd_softc kbd_softc; 73 74 int kbdmatch __P((struct device *, void *, void *)); 75 void kbdattach __P((struct device *, struct device *, void *)); 76 void kbdintr __P((int)); 77 void kbdstuffchar __P((u_char)); 78 79 struct cfattach kbd_ca = { 80 sizeof(struct device), kbdmatch, kbdattach 81 }; 82 83 struct cfdriver kbd_cd = { 84 NULL, "kbd", DV_DULL, NULL, 0 85 }; 86 87 /*ARGSUSED*/ 88 int 89 kbdmatch(pdp, match, auxp) 90 struct device *pdp; 91 void *match, *auxp; 92 { 93 94 if (matchname((char *)auxp, "kbd")) 95 return(1); 96 return(0); 97 } 98 99 /*ARGSUSED*/ 100 void 101 kbdattach(pdp, dp, auxp) 102 struct device *pdp, *dp; 103 void *auxp; 104 { 105 #ifdef DRACO 106 /* 107 * XXX Must be kept in sync with kbdenable() switch. 108 * XXX This should be probed, but this way we dont need to initialize 109 * the keyboards. 110 */ 111 switch (is_draco()) { 112 case 0: 113 case 1: 114 case 2: 115 printf(": CIA A type Amiga\n"); 116 break; 117 case 3: 118 case 4: 119 default: 120 printf(": QuickLogic type MF-II\n"); 121 break; 122 } 123 #else 124 printf(": CIA A type Amiga\n"); 125 #endif 126 127 } 128 129 /* definitions for amiga keyboard encoding. */ 130 #define KEY_CODE(c) ((c) & 0x7f) 131 #define KEY_UP(c) ((c) & 0x80) 132 133 void 134 kbdenable() 135 { 136 int s; 137 138 #ifdef DRACO 139 u_char c; 140 #endif 141 /* 142 * collides with external ints from SCSI, watch out for this when 143 * enabling/disabling interrupts there !! 144 */ 145 s = spltty(); 146 #ifdef DRACO 147 switch (is_draco()) { 148 case 0: 149 custom.intena = INTF_SETCLR | INTF_PORTS; 150 151 ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_SP; 152 /* SP interrupt enable */ 153 ciaa.cra &= ~(1<<6); /* serial line == input */ 154 break; 155 case 1: 156 case 2: 157 /* XXX: tobedone: conditionally enable that one */ 158 /* XXX: for now, just enable DraCo ports and CIA */ 159 *draco_intena |= DRIRQ_INT2; 160 ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_SP; 161 /* SP interrupt enable */ 162 ciaa.cra &= ~(1<<6); /* serial line == input */ 163 break; 164 165 case 3: 166 ciaa.icr = CIA_ICR_SP; /* CIA SP interrupt disable */ 167 ciaa.cra &= ~(1<<6); /* serial line == input */ 168 /* FALLTHROUGH */ 169 case 4: 170 default: 171 /* XXX: for now: always enable own keyboard */ 172 173 while (draco_ioct->io_status & DRSTAT_KBDRECV) { 174 c = draco_ioct->io_kbddata; 175 draco_ioct->io_kbdrst = 0; 176 DELAY(2000); 177 } 178 179 draco_ioct->io_control &= ~DRCNTRL_KBDINTENA; 180 break; 181 } 182 #else 183 custom.intena = INTF_SETCLR | INTF_PORTS; 184 ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_SP; /* SP interrupt enable */ 185 ciaa.cra &= ~(1<<6); /* serial line == input */ 186 #endif 187 kbd_softc.k_event_mode = 0; 188 kbd_softc.k_events.ev_io = 0; 189 splx(s); 190 } 191 192 193 int 194 kbdopen(dev, flags, mode, p) 195 dev_t dev; 196 int flags, mode; 197 struct proc *p; 198 { 199 200 if (kbd_softc.k_events.ev_io) 201 return EBUSY; 202 203 kbd_softc.k_events.ev_io = p; 204 ev_init(&kbd_softc.k_events); 205 return (0); 206 } 207 208 int 209 kbdclose(dev, flags, mode, p) 210 dev_t dev; 211 int flags, mode; 212 struct proc *p; 213 { 214 215 /* Turn off event mode, dump the queue */ 216 kbd_softc.k_event_mode = 0; 217 ev_fini(&kbd_softc.k_events); 218 kbd_softc.k_events.ev_io = NULL; 219 return (0); 220 } 221 222 int 223 kbdread(dev, uio, flags) 224 dev_t dev; 225 struct uio *uio; 226 int flags; 227 { 228 return ev_read (&kbd_softc.k_events, uio, flags); 229 } 230 231 int 232 kbdioctl(dev, cmd, data, flag, p) 233 dev_t dev; 234 u_long cmd; 235 register caddr_t data; 236 int flag; 237 struct proc *p; 238 { 239 register struct kbd_softc *k = &kbd_softc; 240 241 switch (cmd) { 242 case KIOCTRANS: 243 if (*(int *)data == TR_UNTRANS_EVENT) 244 return 0; 245 break; 246 247 case KIOCGTRANS: 248 /* Get translation mode */ 249 *(int *)data = TR_UNTRANS_EVENT; 250 return 0; 251 252 case KIOCSDIRECT: 253 k->k_event_mode = *(int *)data; 254 return 0; 255 256 case FIONBIO: /* we will remove this someday (soon???) */ 257 return 0; 258 259 case FIOASYNC: 260 k->k_events.ev_async = *(int *)data != 0; 261 return 0; 262 263 case TIOCSPGRP: 264 if (*(int *)data != k->k_events.ev_io->p_pgid) 265 return EPERM; 266 return 0; 267 268 default: 269 return ENOTTY; 270 } 271 272 /* We identified the ioctl, but we do not handle it. */ 273 return EOPNOTSUPP; /* misuse, but what the heck */ 274 } 275 276 int 277 kbdselect(dev, rw, p) 278 dev_t dev; 279 int rw; 280 struct proc *p; 281 { 282 return ev_select (&kbd_softc.k_events, rw, p); 283 } 284 285 286 void 287 kbdintr(mask) 288 int mask; 289 { 290 u_char c; 291 #ifdef KBDRESET 292 static int reset_warn; 293 #endif 294 295 /* 296 * now only invoked from generic CIA interrupt handler if there *is* 297 * a keyboard interrupt pending 298 */ 299 300 c = ~ciaa.sdr; /* keyboard data is inverted */ 301 /* ack */ 302 ciaa.cra |= (1 << 6); /* serial line output */ 303 #ifdef KBDRESET 304 if (reset_warn && c == 0xf0) { 305 #ifdef DEBUG 306 printf ("kbdintr: !!!! Reset Warning !!!!\n"); 307 #endif 308 bootsync(); 309 reset_warn = 0; 310 DELAY(30000000); 311 } 312 #endif 313 /* wait 200 microseconds (for bloody Cherry keyboards..) */ 314 DELAY(2000); /* fudge delay a bit for some keyboards */ 315 ciaa.cra &= ~(1 << 6); 316 317 /* process the character */ 318 c = (c >> 1) | (c << 7); /* rotate right once */ 319 320 #ifdef KBDRESET 321 if (c == 0x78) { 322 #ifdef DEBUG 323 printf ("kbdintr: Reset Warning started\n"); 324 #endif 325 ++reset_warn; 326 return; 327 } 328 #endif 329 kbdstuffchar(c); 330 } 331 332 #ifdef DRACO 333 /* maps MF-II keycodes to Amiga keycodes */ 334 335 u_char drkbdtab[] = { 336 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x50, 337 0x45, 0xff, 0xff, 0xff, 0xff, 0x42, 0x00, 0x51, 338 339 0xff, 0x64, 0x60, 0x30, 0x63, 0x10, 0x01, 0x52, 340 0xff, 0x66, 0x31, 0x21, 0x20, 0x11, 0x02, 0x53, 341 342 0xff, 0x33, 0x32, 0x22, 0x12, 0x04, 0x03, 0x54, 343 0xff, 0x40, 0x34, 0x23, 0x14, 0x13, 0x05, 0x55, 344 345 0xff, 0x36, 0x35, 0x25, 0x24, 0x15, 0x06, 0x56, 346 0xff, 0x67, 0x37, 0x26, 0x16, 0x07, 0x08, 0x57, 347 /* --- */ 348 0xff, 0x38, 0x27, 0x17, 0x18, 0x0a, 0x09, 0x58, 349 0xff, 0x39, 0x3a, 0x28, 0x29, 0x19, 0x0b, 0x59, 350 351 0xff, 0xff, 0x2a, 0x2b, 0x1a, 0x0c, 0x4b, 0xff, 352 0x65, 0x61, 0x44, 0x1b, 0xff, 0xff, 0x6f, 0xff, 353 354 0x4d, 0x4f, 0xff, 0x4c, 0x0d, 0xff, 0x41, 0x46, 355 0xff, 0x1d, 0x4e, 0x2d, 0x3d, 0x4a, 0x5f, 0x62, 356 357 0x0f, 0x3c, 0x1e, 0x2e, 0x2f, 0x3e, 0x5a, 0x5b, 358 0xff, 0x43, 0x1f, 0xff, 0x5e, 0x3f, 0x5c, 0xff, 359 /* --- */ 360 0xff, 0xff, 0xff, 0xff, 0x5d 361 }; 362 #endif 363 364 365 int 366 kbdgetcn () 367 { 368 int s; 369 u_char ints, mask, c, in; 370 371 #ifdef DRACO 372 /* 373 * XXX todo: if CIA DraCo, get from cia if cia kbd 374 * installed. 375 */ 376 if (is_draco()) { 377 c = 0; 378 s = spltty (); 379 while ((draco_ioct->io_status & DRSTAT_KBDRECV) == 0); 380 in = draco_ioct->io_kbddata; 381 draco_ioct->io_kbdrst = 0; 382 if (in == 0xF0) { /* release prefix */ 383 c = 0x80; 384 while ((draco_ioct->io_status & DRSTAT_KBDRECV) == 0); 385 in = draco_ioct->io_kbddata; 386 draco_ioct->io_kbdrst = 0; 387 } 388 splx(s); 389 #ifdef DRACORAWKEYDEBUG 390 printf("<%02x>", in); 391 #endif 392 return (in>=sizeof(drkbdtab) ? 0xff : drkbdtab[in]|c); 393 } 394 #endif 395 s = spltty(); 396 for (ints = 0; ! ((mask = ciaa.icr) & CIA_ICR_SP); 397 ints |= mask) ; 398 399 in = ciaa.sdr; 400 c = ~in; 401 402 /* ack */ 403 ciaa.cra |= (1 << 6); /* serial line output */ 404 ciaa.sdr = 0xff; /* ack */ 405 /* wait 200 microseconds */ 406 DELAY(2000); /* XXXX only works as long as DELAY doesn't 407 * use a timer and waits.. */ 408 ciaa.cra &= ~(1 << 6); 409 ciaa.sdr = in; 410 411 splx (s); 412 c = (c >> 1) | (c << 7); 413 414 /* take care that no CIA-interrupts are lost */ 415 if (ints) 416 dispatch_cia_ints (0, ints); 417 418 return c; 419 } 420 421 void 422 kbdstuffchar(c) 423 u_char c; 424 { 425 struct firm_event *fe; 426 struct kbd_softc *k = &kbd_softc; 427 int put; 428 429 /* 430 * If not in event mode, deliver straight to ite to process 431 * key stroke 432 */ 433 434 if (! k->k_event_mode) { 435 ite_filter (c, ITEFILT_TTY); 436 return; 437 } 438 439 /* 440 * Keyboard is generating events. Turn this keystroke into an 441 * event and put it in the queue. If the queue is full, the 442 * keystroke is lost (sorry!). 443 */ 444 445 put = k->k_events.ev_put; 446 fe = &k->k_events.ev_q[put]; 447 put = (put + 1) % EV_QSIZE; 448 if (put == k->k_events.ev_get) { 449 log(LOG_WARNING, "keyboard event queue overflow\n"); 450 /* ??? */ 451 return; 452 } 453 fe->id = KEY_CODE(c); 454 fe->value = KEY_UP(c) ? VKEY_UP : VKEY_DOWN; 455 fe->time = time; 456 k->k_events.ev_put = put; 457 EV_WAKEUP(&k->k_events); 458 } 459 460 461 #ifdef DRACO 462 void 463 drkbdintr() 464 { 465 u_char in; 466 struct kbd_softc *k = &kbd_softc; 467 468 in = draco_ioct->io_kbddata; 469 draco_ioct->io_kbdrst = 0; 470 471 if (in == 0xF0) 472 k->k_rlprfx = 0x80; 473 else { 474 kbdstuffchar(in>=sizeof(drkbdtab) ? 0xff : 475 drkbdtab[in] | k->k_rlprfx); 476 k->k_rlprfx = 0; 477 } 478 } 479 480 #endif 481