xref: /netbsd-src/sys/arch/amiga/dev/kbd.c (revision 481fca6e59249d8ffcf24fef7cfbe7b131bfb080)
1 /*	$NetBSD: kbd.c,v 1.34 2000/05/25 18:39:09 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 <m68k/asm_single.h>
53 #include <amiga/amiga/drcustom.h>
54 #endif
55 #include <amiga/amiga/cia.h>
56 #include <amiga/dev/itevar.h>
57 #include <amiga/dev/kbdreg.h>
58 #include <amiga/dev/kbdmap.h>
59 #include <amiga/dev/event_var.h>
60 #include <amiga/dev/vuid_event.h>
61 #include "kbd.h"
62 
63 #include <sys/conf.h>
64 #include <machine/conf.h>
65 
66 struct kbd_softc {
67 	int k_event_mode;	/* if true, collect events, else pass to ite */
68 	struct evvar k_events;	/* event queue state */
69 #ifdef DRACO
70 	u_char k_rlprfx;	/* MF-II rel. prefix has been seen */
71 	u_char k_mf2;
72 #endif
73 };
74 struct kbd_softc kbd_softc;
75 
76 int kbdmatch __P((struct device *, struct cfdata *, void *));
77 void kbdattach __P((struct device *, struct device *, void *));
78 void kbdintr __P((int));
79 void kbdstuffchar __P((u_char));
80 
81 int drkbdgetc __P((void));
82 int drkbdrputc __P((int));
83 int drkbdputc __P((int));
84 int drkbdputc2 __P((int, int));
85 int drkbdwaitfor __P((int));
86 
87 struct cfattach kbd_ca = {
88 	sizeof(struct device), kbdmatch, kbdattach
89 };
90 
91 /*ARGSUSED*/
92 int
93 kbdmatch(pdp, cfp, auxp)
94 	struct device *pdp;
95 	struct cfdata *cfp;
96 	void *auxp;
97 {
98 
99 	if (matchname((char *)auxp, "kbd"))
100 		return(1);
101 	return(0);
102 }
103 
104 /*ARGSUSED*/
105 void
106 kbdattach(pdp, dp, auxp)
107 	struct device *pdp, *dp;
108 	void *auxp;
109 {
110 #ifdef DRACO
111 	kbdenable();
112 	if (kbd_softc.k_mf2)
113 		printf(": QuickLogic type MF-II\n");
114 	else
115 		printf(": CIA A type Amiga\n");
116 #else
117 	printf(": CIA A type Amiga\n");
118 #endif
119 
120 }
121 
122 /* definitions for amiga keyboard encoding. */
123 #define KEY_CODE(c)  ((c) & 0x7f)
124 #define KEY_UP(c)    ((c) & 0x80)
125 
126 #define DATLO single_inst_bclr_b(draco_ioct->io_control, DRCNTRL_KBDDATOUT)
127 #define DATHI single_inst_bset_b(draco_ioct->io_control, DRCNTRL_KBDDATOUT)
128 
129 #define CLKLO single_inst_bclr_b(draco_ioct->io_control, DRCNTRL_KBDCLKOUT)
130 #define CLKHI single_inst_bset_b(draco_ioct->io_control, DRCNTRL_KBDCLKOUT)
131 
132 void
133 kbdenable()
134 {
135 	static int kbd_inited = 0;
136 
137 	int s;
138 
139 #ifdef DRACO
140 	int id;
141 #endif
142 	/*
143 	 * collides with external ints from SCSI, watch out for this when
144 	 * enabling/disabling interrupts there !!
145 	 */
146 	s = splhigh();	/* don't lower; might be called from early ddb */
147 	if (kbd_inited) {
148 		splx(s);
149 		return;
150 	}
151 	kbd_inited = 1;
152 #ifdef DRACO
153 	if (is_draco()) {
154 
155 		CLKLO;
156 		delay(5000);
157 		draco_ioct->io_kbdrst = 0;
158 
159 		if (drkbdputc(0xf2))
160 			goto LnoMFII;
161 
162 		id = drkbdgetc() << 8;
163 		id |= drkbdgetc();
164 
165 		if (id != 0xab83)
166 			goto LnoMFII;
167 
168 		if (drkbdputc2(0xf0, 3))	/* mode 3 */
169 			goto LnoMFII;
170 
171 		if (drkbdputc(0xf8))		/* make/break, no typematic */
172 			goto LnoMFII;
173 
174 		if (drkbdputc(0xf4))		/* enable */
175 			goto LnoMFII;
176 		kbd_softc.k_mf2 = 1;
177 		single_inst_bclr_b(draco_ioct->io_control, DRCNTRL_KBDINTENA);
178 
179 		ciaa.icr = CIA_ICR_SP;  /* CIA SP interrupt disable */
180 		ciaa.cra &= ~(1<<6);	/* serial line == input */
181 		splx(s);
182 		return;
183 
184 	LnoMFII:
185 		kbd_softc.k_mf2 = 0;
186 		single_inst_bset_b(*draco_intena, DRIRQ_INT2);
187 		ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_SP;
188 					/* SP interrupt enable */
189 		ciaa.cra &= ~(1<<6);	/* serial line == input */
190 		splx(s);
191 		return;
192 
193 	} else {
194 #endif
195 	custom.intena = INTF_SETCLR | INTF_PORTS;
196 	ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_SP;  /* SP interrupt enable */
197 	ciaa.cra &= ~(1<<6);		/* serial line == input */
198 #ifdef DRACO
199 	}
200 #endif
201 	kbd_softc.k_event_mode = 0;
202 	kbd_softc.k_events.ev_io = 0;
203 	splx(s);
204 }
205 
206 #ifdef DRACO
207 /*
208  * call this with kbd interupt blocked
209  */
210 
211 int
212 drkbdgetc()
213 {
214 	u_int8_t in;
215 
216 	while ((draco_ioct->io_status & DRSTAT_KBDRECV) == 0);
217 	in = draco_ioct->io_kbddata;
218 	draco_ioct->io_kbdrst = 0;
219 
220 	return in;
221 }
222 
223 #define WAIT0 if (drkbdwaitfor(0)) goto Ltimeout
224 #define WAIT1 if (drkbdwaitfor(DRSTAT_KBDCLKIN)) goto Ltimeout
225 
226 int
227 drkbdwaitfor(bit)
228 	int bit;
229 {
230 	int i;
231 
232 
233 
234 	i = 60000;	/* about 50 ms max */
235 
236 	do {
237 		if ((draco_ioct->io_status & DRSTAT_KBDCLKIN) == bit)
238 			return 0;
239 
240 	} while (--i >= 0);
241 
242 	return 1;
243 }
244 
245 /*
246  * Output a raw byte to the keyboard (+ parity and stop bit).
247  * return 0 on success, 1 on timeout.
248  */
249 int
250 drkbdrputc(c)
251 	u_int8_t c;
252 {
253 	u_int8_t parity;
254 	int bitcnt;
255 
256 	DATLO; CLKHI; WAIT1;
257 	parity = 0;
258 
259 	for (bitcnt=7; bitcnt >= 0; bitcnt--) {
260 		WAIT0;
261 		if (c & 1) {
262 			DATHI;
263 		} else {
264 			++parity;
265 			DATLO;
266 		}
267 		c >>= 1;
268 		WAIT1;
269 	}
270 	WAIT0;
271 	/* parity bit */
272 	if (parity & 1) {
273 		DATLO;
274 	} else {
275 		DATHI;
276 	}
277 	WAIT1;
278 	/* stop bit */
279 	WAIT0; DATHI; WAIT1;
280 
281 	WAIT0; /* XXX should check the ack bit here... */
282 	WAIT1;
283 	draco_ioct->io_kbdrst = 0;
284 	return 0;
285 
286 Ltimeout:
287 	DATHI;
288 	draco_ioct->io_kbdrst = 0;
289 	return 1;
290 }
291 
292 /*
293  * Output one cooked byte to the keyboard, with wait for ACK or RESEND,
294  * and retry if necessary. 0 == success, 1 == timeout
295  */
296 int
297 drkbdputc(c)
298 	u_int8_t c;
299 {
300 	int rc;
301 
302 	do {
303 		if (drkbdrputc(c))
304 			return(-1);
305 
306 		rc = drkbdgetc();
307 	} while (rc == 0xfe);
308 	return (!(rc == 0xfa));
309 }
310 
311 /*
312  * same for twobyte sequence
313  */
314 
315 int
316 drkbdputc2(c1, c2)
317 	u_int8_t c1, c2;
318 {
319 	int rc;
320 
321 	do {
322 		do {
323 			if (drkbdrputc(c1))
324 				return(-1);
325 
326 			rc = drkbdgetc();
327 		} while (rc == 0xfe);
328 		if (rc != 0xfa)
329 			return (-1);
330 
331 		if (drkbdrputc(c2))
332 			return(-1);
333 
334 		rc = drkbdgetc();
335 	} while (rc == 0xfe);
336 	return (!(rc == 0xfa));
337 }
338 #endif
339 
340 int
341 kbdopen(dev, flags, mode, p)
342 	dev_t dev;
343 	int flags, mode;
344 	struct proc *p;
345 {
346 
347 	kbdenable();
348 	if (kbd_softc.k_events.ev_io)
349 		return EBUSY;
350 
351 	kbd_softc.k_events.ev_io = p;
352 	ev_init(&kbd_softc.k_events);
353 	return (0);
354 }
355 
356 int
357 kbdclose(dev, flags, mode, p)
358 	dev_t dev;
359 	int flags, mode;
360 	struct proc *p;
361 {
362 
363 	/* Turn off event mode, dump the queue */
364 	kbd_softc.k_event_mode = 0;
365 	ev_fini(&kbd_softc.k_events);
366 	kbd_softc.k_events.ev_io = NULL;
367 	return (0);
368 }
369 
370 int
371 kbdread(dev, uio, flags)
372 	dev_t dev;
373 	struct uio *uio;
374 	int flags;
375 {
376 	return ev_read (&kbd_softc.k_events, uio, flags);
377 }
378 
379 int
380 kbdioctl(dev, cmd, data, flag, p)
381 	dev_t dev;
382 	u_long cmd;
383 	register caddr_t data;
384 	int flag;
385 	struct proc *p;
386 {
387 	register struct kbd_softc *k = &kbd_softc;
388 
389 	switch (cmd) {
390 		case KIOCTRANS:
391 			if (*(int *)data == TR_UNTRANS_EVENT)
392 				return 0;
393 			break;
394 
395 		case KIOCGTRANS:
396 			/* Get translation mode */
397 			*(int *)data = TR_UNTRANS_EVENT;
398 			return 0;
399 
400 		case KIOCSDIRECT:
401 			k->k_event_mode = *(int *)data;
402 			return 0;
403 
404 		case FIONBIO:	/* we will remove this someday (soon???) */
405 			return 0;
406 
407 		case FIOASYNC:
408 			k->k_events.ev_async = *(int *)data != 0;
409 			return 0;
410 
411 		case TIOCSPGRP:
412 			if (*(int *)data != k->k_events.ev_io->p_pgid)
413 				return EPERM;
414 			return 0;
415 
416 		default:
417 			return ENOTTY;
418 	}
419 
420 	/* We identified the ioctl, but we do not handle it. */
421 	return EOPNOTSUPP;	/* misuse, but what the heck */
422 }
423 
424 int
425 kbdpoll(dev, events, p)
426 	dev_t dev;
427 	int events;
428 	struct proc *p;
429 {
430 	return ev_poll (&kbd_softc.k_events, events, p);
431 }
432 
433 
434 void
435 kbdintr(mask)
436 	int mask;
437 {
438 	u_char c;
439 #ifdef KBDRESET
440 	static int reset_warn;
441 #endif
442 
443 	/*
444 	 * now only invoked from generic CIA interrupt handler if there *is*
445 	 * a keyboard interrupt pending
446 	 */
447 
448 	c = ~ciaa.sdr;	/* keyboard data is inverted */
449 	/* ack */
450 	ciaa.cra |= (1 << 6);	/* serial line output */
451 #ifdef KBDRESET
452 	if (reset_warn && c == 0xf0) {
453 #ifdef DEBUG
454 		printf ("kbdintr: !!!! Reset Warning !!!!\n");
455 #endif
456 		bootsync();
457 		reset_warn = 0;
458 		DELAY(30000000);
459 	}
460 #endif
461 	/* wait 200 microseconds (for bloody Cherry keyboards..) */
462 	DELAY(2000);			/* fudge delay a bit for some keyboards */
463 	ciaa.cra &= ~(1 << 6);
464 
465 	/* process the character */
466 	c = (c >> 1) | (c << 7);	/* rotate right once */
467 
468 #ifdef KBDRESET
469 	if (c == 0x78) {
470 #ifdef DEBUG
471 		printf ("kbdintr: Reset Warning started\n");
472 #endif
473 		++reset_warn;
474 		return;
475 	}
476 #endif
477 	kbdstuffchar(c);
478 }
479 
480 #ifdef DRACO
481 /* maps MF-II keycodes to Amiga keycodes */
482 
483 const u_char drkbdtab[] = {
484 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x50,
485 	0x45, 0xff, 0xff, 0xff, 0xff, 0x42, 0x00, 0x51,
486 
487 	0xff, 0x64, 0x60, 0x30, 0x63, 0x10, 0x01, 0x52,
488 	0xff, 0x66, 0x31, 0x21, 0x20, 0x11, 0x02, 0x53,
489 
490 	0xff, 0x33, 0x32, 0x22, 0x12, 0x04, 0x03, 0x54,
491 	0xff, 0x40, 0x34, 0x23, 0x14, 0x13, 0x05, 0x55,
492 
493 	0xff, 0x36, 0x35, 0x25, 0x24, 0x15, 0x06, 0x56,
494 	0xff, 0x67, 0x37, 0x26, 0x16, 0x07, 0x08, 0x57,
495 	/* --- */
496 	0xff, 0x38, 0x27, 0x17, 0x18, 0x0a, 0x09, 0x58,
497 	0xff, 0x39, 0x3a, 0x28, 0x29, 0x19, 0x0b, 0x59,
498 
499 	0xff, 0xff, 0x2a, 0x2b, 0x1a, 0x0c, 0x4b, 0xff,
500 	0x65, 0x61, 0x44, 0x1b, 0xff, 0xff, 0x6f, 0xff,
501 
502 	0x4d, 0x4f, 0xff, 0x4c, 0x0d, 0xff, 0x41, 0x46,
503 	0xff, 0x1d, 0x4e, 0x2d, 0x3d, 0x4a, 0x5f, 0x62,
504 
505 	0x0f, 0x3c, 0x1e, 0x2e, 0x2f, 0x3e, 0x5a, 0x5b,
506 	0xff, 0x43, 0x1f, 0xff, 0x5e, 0x3f, 0x5c, 0xff,
507 	/* --- */
508 	0xff, 0xff, 0xff, 0xff, 0x5d
509 };
510 #endif
511 
512 
513 int
514 kbdgetcn ()
515 {
516 	int s;
517 	u_char ints, mask, c, in;
518 
519 #ifdef DRACO
520 	if (is_draco() && kbd_softc.k_mf2) {
521 		do {
522 			c = 0;
523 			s = spltty ();
524 			while ((draco_ioct->io_status & DRSTAT_KBDRECV) == 0);
525 			in = draco_ioct->io_kbddata;
526 			draco_ioct->io_kbdrst = 0;
527 			if (in == 0xF0) { /* release prefix */
528 				c = 0x80;
529 				while ((draco_ioct->io_status &
530 				    DRSTAT_KBDRECV) == 0);
531 				in = draco_ioct->io_kbddata;
532 				draco_ioct->io_kbdrst = 0;
533 			}
534 			splx(s);
535 #ifdef DRACORAWKEYDEBUG
536 			printf("<%02x>", in);
537 #endif
538 			c |= in>=sizeof(drkbdtab) ? 0xff : drkbdtab[in];
539 		} while (c == 0xff);
540 		return (c);
541 	}
542 #endif
543 	s = spltty();
544 	for (ints = 0; ! ((mask = ciaa.icr) & CIA_ICR_SP);
545 	    ints |= mask) ;
546 
547 	in = ciaa.sdr;
548 	c = ~in;
549 
550 	/* ack */
551 	ciaa.cra |= (1 << 6);	/* serial line output */
552 	ciaa.sdr = 0xff;	/* ack */
553 	/* wait 200 microseconds */
554 	DELAY(2000);	/* XXXX only works as long as DELAY doesn't
555 			 * use a timer and waits.. */
556 	ciaa.cra &= ~(1 << 6);
557 	ciaa.sdr = in;
558 
559 	splx (s);
560 	c = (c >> 1) | (c << 7);
561 
562 	/* take care that no CIA-interrupts are lost */
563 	if (ints)
564 		dispatch_cia_ints (0, ints);
565 
566 	return c;
567 }
568 
569 void
570 kbdstuffchar(c)
571 	u_char c;
572 {
573 	struct firm_event *fe;
574 	struct kbd_softc *k = &kbd_softc;
575 	int put;
576 
577 	/*
578 	 * If not in event mode, deliver straight to ite to process
579 	 * key stroke
580 	 */
581 
582 	if (! k->k_event_mode) {
583 		ite_filter (c, ITEFILT_TTY);
584 		return;
585 	}
586 
587 	/*
588 	 * Keyboard is generating events. Turn this keystroke into an
589 	 * event and put it in the queue. If the queue is full, the
590 	 * keystroke is lost (sorry!).
591 	 */
592 
593 	put = k->k_events.ev_put;
594 	fe = &k->k_events.ev_q[put];
595 	put = (put + 1) % EV_QSIZE;
596 	if (put == k->k_events.ev_get) {
597 		log(LOG_WARNING, "keyboard event queue overflow\n");
598 			/* ??? */
599 		return;
600 	}
601 	fe->id = KEY_CODE(c);
602 	fe->value = KEY_UP(c) ? VKEY_UP : VKEY_DOWN;
603 	fe->time = time;
604 	k->k_events.ev_put = put;
605 	EV_WAKEUP(&k->k_events);
606 }
607 
608 
609 #ifdef DRACO
610 void
611 drkbdintr()
612 {
613 	u_char in;
614 	struct kbd_softc *k = &kbd_softc;
615 
616 	in = draco_ioct->io_kbddata;
617 	draco_ioct->io_kbdrst = 0;
618 
619 	if (in == 0xF0)
620 		k->k_rlprfx = 0x80;
621 	else {
622 		kbdstuffchar(in>=sizeof(drkbdtab) ? 0xff :
623 		    drkbdtab[in] | k->k_rlprfx);
624 		k->k_rlprfx = 0;
625 	}
626 }
627 
628 #endif
629