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