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