Home | History | Annotate | Line # | Download | only in dev
kbd.c revision 1.26
      1 /*	$NetBSD: kbd.c,v 1.26 1996/10/13 03:07:22 christos 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 kbdpoll(dev, events, p)
    278 	dev_t dev;
    279 	int events;
    280 	struct proc *p;
    281 {
    282 	return ev_poll (&kbd_softc.k_events, events, 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