kbd.c revision 1.31 1 /* $NetBSD: kbd.c,v 1.31 1998/02/28 21:53:15 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 <m68k/asm_single.h>
49 #include <machine/cpu.h>
50 #include <amiga/amiga/device.h>
51 #include <amiga/amiga/custom.h>
52 #ifdef DRACO
53 #include <amiga/amiga/drcustom.h>
54 #endif
55 #include <amiga/amiga/cia.h>
56 #include <amiga/dev/itevar.h>
57 #include <amiga/dev/kbdreg.h>
58 #include <amiga/dev/kbdmap.h>
59 #include <amiga/dev/event_var.h>
60 #include <amiga/dev/vuid_event.h>
61 #include "kbd.h"
62
63 #include <sys/conf.h>
64 #include <machine/conf.h>
65
66 struct kbd_softc {
67 int k_event_mode; /* if true, collect events, else pass to ite */
68 struct evvar k_events; /* event queue state */
69 #ifdef DRACO
70 u_char k_rlprfx; /* MF-II rel. prefix has been seen */
71 u_char k_mf2;
72 #endif
73 };
74 struct kbd_softc kbd_softc;
75
76 int kbdmatch __P((struct device *, struct cfdata *, void *));
77 void kbdattach __P((struct device *, struct device *, void *));
78 void kbdintr __P((int));
79 void kbdstuffchar __P((u_char));
80
81 int drkbdgetc __P((void));
82 int drkbdrputc __P((int));
83 int drkbdputc __P((int));
84 int drkbdputc2 __P((int, int));
85 int drkbdwaitfor __P((int));
86
87 struct cfattach kbd_ca = {
88 sizeof(struct device), kbdmatch, kbdattach
89 };
90
91 /*ARGSUSED*/
92 int
93 kbdmatch(pdp, cfp, auxp)
94 struct device *pdp;
95 struct cfdata *cfp;
96 void *auxp;
97 {
98
99 if (matchname((char *)auxp, "kbd"))
100 return(1);
101 return(0);
102 }
103
104 /*ARGSUSED*/
105 void
106 kbdattach(pdp, dp, auxp)
107 struct device *pdp, *dp;
108 void *auxp;
109 {
110 #ifdef DRACO
111 kbdenable();
112 if (kbd_softc.k_mf2)
113 printf(": QuickLogic type MF-II\n");
114 else
115 printf(": CIA A type Amiga\n");
116 #else
117 printf(": CIA A type Amiga\n");
118 #endif
119
120 }
121
122 /* definitions for amiga keyboard encoding. */
123 #define KEY_CODE(c) ((c) & 0x7f)
124 #define KEY_UP(c) ((c) & 0x80)
125
126 #define DATLO single_inst_bclr_b(draco_ioct->io_control, DRCNTRL_KBDDATOUT)
127 #define DATHI single_inst_bset_b(draco_ioct->io_control, DRCNTRL_KBDDATOUT)
128
129 #define CLKLO single_inst_bclr_b(draco_ioct->io_control, DRCNTRL_KBDCLKOUT)
130 #define CLKHI single_inst_bset_b(draco_ioct->io_control, DRCNTRL_KBDCLKOUT)
131
132 void
133 kbdenable()
134 {
135 static int kbd_inited = 0;
136
137 int s;
138
139 #ifdef DRACO
140 int id;
141 #endif
142 /*
143 * collides with external ints from SCSI, watch out for this when
144 * enabling/disabling interrupts there !!
145 */
146 s = splhigh(); /* don't lower; might be called from early ddb */
147 if (kbd_inited) {
148 splx(s);
149 return;
150 }
151 kbd_inited = 1;
152 #ifdef DRACO
153 if (is_draco()) {
154
155 CLKLO;
156 delay(5000);
157 draco_ioct->io_kbdrst = 0;
158
159 if (drkbdputc(0xf2))
160 goto LnoMFII;
161
162 id = drkbdgetc() << 8;
163 id |= drkbdgetc();
164
165 if (id != 0xab83)
166 goto LnoMFII;
167
168 if (drkbdputc2(0xf0, 3)) /* mode 3 */
169 goto LnoMFII;
170
171 if (drkbdputc(0xf8)) /* make/break, no typematic */
172 goto LnoMFII;
173
174 if (drkbdputc(0xf4)) /* enable */
175 goto LnoMFII;
176 kbd_softc.k_mf2 = 1;
177 draco_ioct->io_control &= ~DRCNTRL_KBDINTENA;
178 /*draco_ioct->io_control &= ~DRCNTRL_KBDKBDACK;*/
179 printf("ioctrl: 0x%02x, iostat: 0x%02x\n",
180 draco_ioct->io_control, draco_ioct->io_status);
181
182 ciaa.icr = CIA_ICR_SP; /* CIA SP interrupt disable */
183 ciaa.cra &= ~(1<<6); /* serial line == input */
184 splx(s);
185 return;
186
187 LnoMFII:
188 kbd_softc.k_mf2 = 0;
189 *draco_intena |= DRIRQ_INT2;
190 ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_SP;
191 /* SP interrupt enable */
192 ciaa.cra &= ~(1<<6); /* serial line == input */
193 splx(s);
194 return;
195
196 } else {
197 #endif
198 custom.intena = INTF_SETCLR | INTF_PORTS;
199 ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_SP; /* SP interrupt enable */
200 ciaa.cra &= ~(1<<6); /* serial line == input */
201 #ifdef DRACO
202 }
203 #endif
204 kbd_softc.k_event_mode = 0;
205 kbd_softc.k_events.ev_io = 0;
206 splx(s);
207 }
208
209 /*
210 * call this with kbd interupt blocked
211 */
212
213 int
214 drkbdgetc()
215 {
216 u_int8_t in;
217
218 while ((draco_ioct->io_status & DRSTAT_KBDRECV) == 0);
219 in = draco_ioct->io_kbddata;
220 draco_ioct->io_kbdrst = 0;
221
222 return in;
223 }
224
225 #define WAIT0 if (drkbdwaitfor(0)) goto Ltimeout
226 #define WAIT1 if (drkbdwaitfor(DRSTAT_KBDCLKIN)) goto Ltimeout
227
228 int
229 drkbdwaitfor(bit)
230 int bit;
231 {
232 int i;
233
234
235
236 i = 60000; /* about 50 ms max */
237
238 do {
239 if ((draco_ioct->io_status & DRSTAT_KBDCLKIN) == bit)
240 return 0;
241
242 } while (--i >= 0);
243
244 return 1;
245 }
246
247 /*
248 * Output a raw byte to the keyboard (+ parity and stop bit).
249 * return 0 on success, 1 on timeout.
250 */
251 int
252 drkbdrputc(c)
253 u_int8_t c;
254 {
255 u_int8_t parity;
256 int bitcnt;
257
258 DATLO; CLKHI; WAIT1;
259 parity = 0;
260
261 for (bitcnt=7; bitcnt >= 0; bitcnt--) {
262 WAIT0;
263 if (c & 1) {
264 DATHI;
265 } else {
266 ++parity;
267 DATLO;
268 }
269 c >>= 1;
270 WAIT1;
271 }
272 WAIT0;
273 /* parity bit */
274 if (parity & 1) {
275 DATLO;
276 } else {
277 DATHI;
278 }
279 WAIT1;
280 /* stop bit */
281 WAIT0; DATHI; WAIT1;
282
283 WAIT0; /* XXX should check the ack bit here... */
284 WAIT1;
285 draco_ioct->io_kbdrst = 0;
286 return 0;
287
288 Ltimeout:
289 DATHI;
290 draco_ioct->io_kbdrst = 0;
291 return 1;
292 }
293
294 /*
295 * Output one cooked byte to the keyboard, with wait for ACK or RESEND,
296 * and retry if necessary. 0 == success, 1 == timeout
297 */
298 int
299 drkbdputc(c)
300 u_int8_t c;
301 {
302 int rc;
303
304 do {
305 if (drkbdrputc(c))
306 return(-1);
307
308 rc = drkbdgetc();
309 } while (rc == 0xfe);
310 return (!(rc == 0xfa));
311 }
312
313 /*
314 * same for twobyte sequence
315 */
316
317 int
318 drkbdputc2(c1, c2)
319 u_int8_t c1, c2;
320 {
321 int rc;
322
323 do {
324 do {
325 if (drkbdrputc(c1))
326 return(-1);
327
328 rc = drkbdgetc();
329 } while (rc == 0xfe);
330 if (rc != 0xfa)
331 return (-1);
332
333 if (drkbdrputc(c2))
334 return(-1);
335
336 rc = drkbdgetc();
337 } while (rc == 0xfe);
338 return (!(rc == 0xfa));
339 }
340
341 int
342 kbdopen(dev, flags, mode, p)
343 dev_t dev;
344 int flags, mode;
345 struct proc *p;
346 {
347
348 kbdenable();
349 if (kbd_softc.k_events.ev_io)
350 return EBUSY;
351
352 kbd_softc.k_events.ev_io = p;
353 ev_init(&kbd_softc.k_events);
354 return (0);
355 }
356
357 int
358 kbdclose(dev, flags, mode, p)
359 dev_t dev;
360 int flags, mode;
361 struct proc *p;
362 {
363
364 /* Turn off event mode, dump the queue */
365 kbd_softc.k_event_mode = 0;
366 ev_fini(&kbd_softc.k_events);
367 kbd_softc.k_events.ev_io = NULL;
368 return (0);
369 }
370
371 int
372 kbdread(dev, uio, flags)
373 dev_t dev;
374 struct uio *uio;
375 int flags;
376 {
377 return ev_read (&kbd_softc.k_events, uio, flags);
378 }
379
380 int
381 kbdioctl(dev, cmd, data, flag, p)
382 dev_t dev;
383 u_long cmd;
384 register caddr_t data;
385 int flag;
386 struct proc *p;
387 {
388 register struct kbd_softc *k = &kbd_softc;
389
390 switch (cmd) {
391 case KIOCTRANS:
392 if (*(int *)data == TR_UNTRANS_EVENT)
393 return 0;
394 break;
395
396 case KIOCGTRANS:
397 /* Get translation mode */
398 *(int *)data = TR_UNTRANS_EVENT;
399 return 0;
400
401 case KIOCSDIRECT:
402 k->k_event_mode = *(int *)data;
403 return 0;
404
405 case FIONBIO: /* we will remove this someday (soon???) */
406 return 0;
407
408 case FIOASYNC:
409 k->k_events.ev_async = *(int *)data != 0;
410 return 0;
411
412 case TIOCSPGRP:
413 if (*(int *)data != k->k_events.ev_io->p_pgid)
414 return EPERM;
415 return 0;
416
417 default:
418 return ENOTTY;
419 }
420
421 /* We identified the ioctl, but we do not handle it. */
422 return EOPNOTSUPP; /* misuse, but what the heck */
423 }
424
425 int
426 kbdpoll(dev, events, p)
427 dev_t dev;
428 int events;
429 struct proc *p;
430 {
431 return ev_poll (&kbd_softc.k_events, events, p);
432 }
433
434
435 void
436 kbdintr(mask)
437 int mask;
438 {
439 u_char c;
440 #ifdef KBDRESET
441 static int reset_warn;
442 #endif
443
444 /*
445 * now only invoked from generic CIA interrupt handler if there *is*
446 * a keyboard interrupt pending
447 */
448
449 c = ~ciaa.sdr; /* keyboard data is inverted */
450 /* ack */
451 ciaa.cra |= (1 << 6); /* serial line output */
452 #ifdef KBDRESET
453 if (reset_warn && c == 0xf0) {
454 #ifdef DEBUG
455 printf ("kbdintr: !!!! Reset Warning !!!!\n");
456 #endif
457 bootsync();
458 reset_warn = 0;
459 DELAY(30000000);
460 }
461 #endif
462 /* wait 200 microseconds (for bloody Cherry keyboards..) */
463 DELAY(2000); /* fudge delay a bit for some keyboards */
464 ciaa.cra &= ~(1 << 6);
465
466 /* process the character */
467 c = (c >> 1) | (c << 7); /* rotate right once */
468
469 #ifdef KBDRESET
470 if (c == 0x78) {
471 #ifdef DEBUG
472 printf ("kbdintr: Reset Warning started\n");
473 #endif
474 ++reset_warn;
475 return;
476 }
477 #endif
478 kbdstuffchar(c);
479 }
480
481 #ifdef DRACO
482 /* maps MF-II keycodes to Amiga keycodes */
483
484 const u_char drkbdtab[] = {
485 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x50,
486 0x45, 0xff, 0xff, 0xff, 0xff, 0x42, 0x00, 0x51,
487
488 0xff, 0x64, 0x60, 0x30, 0x63, 0x10, 0x01, 0x52,
489 0xff, 0x66, 0x31, 0x21, 0x20, 0x11, 0x02, 0x53,
490
491 0xff, 0x33, 0x32, 0x22, 0x12, 0x04, 0x03, 0x54,
492 0xff, 0x40, 0x34, 0x23, 0x14, 0x13, 0x05, 0x55,
493
494 0xff, 0x36, 0x35, 0x25, 0x24, 0x15, 0x06, 0x56,
495 0xff, 0x67, 0x37, 0x26, 0x16, 0x07, 0x08, 0x57,
496 /* --- */
497 0xff, 0x38, 0x27, 0x17, 0x18, 0x0a, 0x09, 0x58,
498 0xff, 0x39, 0x3a, 0x28, 0x29, 0x19, 0x0b, 0x59,
499
500 0xff, 0xff, 0x2a, 0x2b, 0x1a, 0x0c, 0x4b, 0xff,
501 0x65, 0x61, 0x44, 0x1b, 0xff, 0xff, 0x6f, 0xff,
502
503 0x4d, 0x4f, 0xff, 0x4c, 0x0d, 0xff, 0x41, 0x46,
504 0xff, 0x1d, 0x4e, 0x2d, 0x3d, 0x4a, 0x5f, 0x62,
505
506 0x0f, 0x3c, 0x1e, 0x2e, 0x2f, 0x3e, 0x5a, 0x5b,
507 0xff, 0x43, 0x1f, 0xff, 0x5e, 0x3f, 0x5c, 0xff,
508 /* --- */
509 0xff, 0xff, 0xff, 0xff, 0x5d
510 };
511 #endif
512
513
514 int
515 kbdgetcn ()
516 {
517 int s;
518 u_char ints, mask, c, in;
519
520 #ifdef DRACO
521 /*
522 * XXX todo: if CIA DraCo, get from cia if cia kbd
523 * installed.
524 */
525 if (is_draco() && kbd_softc.k_mf2) {
526 do {
527 c = 0;
528 s = spltty ();
529 while ((draco_ioct->io_status & DRSTAT_KBDRECV) == 0);
530 in = draco_ioct->io_kbddata;
531 draco_ioct->io_kbdrst = 0;
532 if (in == 0xF0) { /* release prefix */
533 c = 0x80;
534 while ((draco_ioct->io_status & DRSTAT_KBDRECV) == 0);
535 in = draco_ioct->io_kbddata;
536 draco_ioct->io_kbdrst = 0;
537 }
538 splx(s);
539 #ifdef DRACORAWKEYDEBUG
540 printf("<%02x>", in);
541 #endif
542 c |= in>=sizeof(drkbdtab) ? 0xff : drkbdtab[in];
543 } while (c == 0xff);
544 return (c);
545 }
546 #endif
547 s = spltty();
548 for (ints = 0; ! ((mask = ciaa.icr) & CIA_ICR_SP);
549 ints |= mask) ;
550
551 in = ciaa.sdr;
552 c = ~in;
553
554 /* ack */
555 ciaa.cra |= (1 << 6); /* serial line output */
556 ciaa.sdr = 0xff; /* ack */
557 /* wait 200 microseconds */
558 DELAY(2000); /* XXXX only works as long as DELAY doesn't
559 * use a timer and waits.. */
560 ciaa.cra &= ~(1 << 6);
561 ciaa.sdr = in;
562
563 splx (s);
564 c = (c >> 1) | (c << 7);
565
566 /* take care that no CIA-interrupts are lost */
567 if (ints)
568 dispatch_cia_ints (0, ints);
569
570 return c;
571 }
572
573 void
574 kbdstuffchar(c)
575 u_char c;
576 {
577 struct firm_event *fe;
578 struct kbd_softc *k = &kbd_softc;
579 int put;
580
581 /*
582 * If not in event mode, deliver straight to ite to process
583 * key stroke
584 */
585
586 if (! k->k_event_mode) {
587 ite_filter (c, ITEFILT_TTY);
588 return;
589 }
590
591 /*
592 * Keyboard is generating events. Turn this keystroke into an
593 * event and put it in the queue. If the queue is full, the
594 * keystroke is lost (sorry!).
595 */
596
597 put = k->k_events.ev_put;
598 fe = &k->k_events.ev_q[put];
599 put = (put + 1) % EV_QSIZE;
600 if (put == k->k_events.ev_get) {
601 log(LOG_WARNING, "keyboard event queue overflow\n");
602 /* ??? */
603 return;
604 }
605 fe->id = KEY_CODE(c);
606 fe->value = KEY_UP(c) ? VKEY_UP : VKEY_DOWN;
607 fe->time = time;
608 k->k_events.ev_put = put;
609 EV_WAKEUP(&k->k_events);
610 }
611
612
613 #ifdef DRACO
614 void
615 drkbdintr()
616 {
617 u_char in;
618 struct kbd_softc *k = &kbd_softc;
619
620 in = draco_ioct->io_kbddata;
621 draco_ioct->io_kbdrst = 0;
622
623 if (in == 0xF0)
624 k->k_rlprfx = 0x80;
625 else {
626 kbdstuffchar(in>=sizeof(drkbdtab) ? 0xff :
627 drkbdtab[in] | k->k_rlprfx);
628 k->k_rlprfx = 0;
629 }
630 }
631
632 #endif
633