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