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