Home | History | Annotate | Line # | Download | only in dev
kbd.c revision 1.21
      1 /*	$NetBSD: kbd.c,v 1.21 1996/05/16 17:50:25 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 #ifdef DRACO
    138 	u_char c;
    139 #endif
    140 	/*
    141 	 * collides with external ints from SCSI, watch out for this when
    142 	 * enabling/disabling interrupts there !!
    143 	 */
    144 	s = spltty();
    145 #ifdef DRACO
    146 	switch (is_draco()) {
    147 		case 0:
    148 			custom.intena = INTF_SETCLR | INTF_PORTS;
    149 
    150 			ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_SP;
    151 						/* SP interrupt enable */
    152 			ciaa.cra &= ~(1<<6);	/* serial line == input */
    153 			printf("ok.\n");
    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 				printf(".");
    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 kbdselect(dev, rw, p)
    279 	dev_t dev;
    280 	int rw;
    281 	struct proc *p;
    282 {
    283 	return ev_select (&kbd_softc.k_events, rw, 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 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