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