xref: /netbsd-src/sys/arch/amiga/dev/kbd.c (revision 2a399c6883d870daece976daec6ffa7bb7f934ce)
1 /*	$NetBSD: kbd.c,v 1.28 1996/12/23 09:10:22 veego 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 struct cfdriver kbd_cd = {
84 	NULL, "kbd", DV_DULL, NULL, 0
85 };
86 
87 /*ARGSUSED*/
88 int
89 kbdmatch(pdp, cfp, auxp)
90 	struct device *pdp;
91 	struct cfdata *cfp;
92 	void *auxp;
93 {
94 
95 	if (matchname((char *)auxp, "kbd"))
96 		return(1);
97 	return(0);
98 }
99 
100 /*ARGSUSED*/
101 void
102 kbdattach(pdp, dp, auxp)
103 	struct device *pdp, *dp;
104 	void *auxp;
105 {
106 #ifdef DRACO
107 	/*
108 	 * XXX Must be kept in sync with kbdenable() switch.
109 	 * XXX This should be probed, but this way we dont need to initialize
110 	 * the keyboards.
111 	 */
112 	switch (is_draco()) {
113 		case 0:
114 		case 1:
115 		case 2:
116 			printf(": CIA A type Amiga\n");
117 			break;
118 		case 3:
119 		case 4:
120 		default:
121 			printf(": QuickLogic type MF-II\n");
122 			break;
123 	}
124 #else
125 	printf(": CIA A type Amiga\n");
126 #endif
127 
128 }
129 
130 /* definitions for amiga keyboard encoding. */
131 #define KEY_CODE(c)  ((c) & 0x7f)
132 #define KEY_UP(c)    ((c) & 0x80)
133 
134 void
135 kbdenable()
136 {
137 	int s;
138 
139 #ifdef DRACO
140 	u_char c;
141 #endif
142 	/*
143 	 * collides with external ints from SCSI, watch out for this when
144 	 * enabling/disabling interrupts there !!
145 	 */
146 	s = spltty();
147 #ifdef DRACO
148 	switch (is_draco()) {
149 		case 0:
150 			custom.intena = INTF_SETCLR | INTF_PORTS;
151 
152 			ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_SP;
153 						/* SP interrupt enable */
154 			ciaa.cra &= ~(1<<6);	/* serial line == input */
155 			break;
156 		case 1:
157 		case 2:
158 			/* XXX: tobedone: conditionally enable that one */
159 			/* XXX: for now, just enable DraCo ports and CIA */
160 			*draco_intena |= DRIRQ_INT2;
161 			ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_SP;
162 						/* SP interrupt enable */
163 			ciaa.cra &= ~(1<<6);	/* serial line == input */
164 			break;
165 
166 		case 3:
167 			ciaa.icr = CIA_ICR_SP;  /* CIA SP interrupt disable */
168 			ciaa.cra &= ~(1<<6);	/* serial line == input */
169 			/* FALLTHROUGH */
170 		case 4:
171 		default:
172 			/* XXX: for now: always enable own keyboard */
173 
174 			while (draco_ioct->io_status & DRSTAT_KBDRECV) {
175 				c = draco_ioct->io_kbddata;
176 				draco_ioct->io_kbdrst = 0;
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 kbdpoll(dev, events, p)
279 	dev_t dev;
280 	int events;
281 	struct proc *p;
282 {
283 	return ev_poll (&kbd_softc.k_events, events, 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 const 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