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