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