kbd.c revision 1.33 1 /* $NetBSD: kbd.c,v 1.33 1998/07/26 06:45:19 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 single_inst_bclr_b(draco_ioct->io_control, DRCNTRL_KBDINTENA);
178
179 ciaa.icr = CIA_ICR_SP; /* CIA SP interrupt disable */
180 ciaa.cra &= ~(1<<6); /* serial line == input */
181 splx(s);
182 return;
183
184 LnoMFII:
185 kbd_softc.k_mf2 = 0;
186 single_inst_bset_b(*draco_intena, DRIRQ_INT2);
187 ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_SP;
188 /* SP interrupt enable */
189 ciaa.cra &= ~(1<<6); /* serial line == input */
190 splx(s);
191 return;
192
193 } else {
194 #endif
195 custom.intena = INTF_SETCLR | INTF_PORTS;
196 ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_SP; /* SP interrupt enable */
197 ciaa.cra &= ~(1<<6); /* serial line == input */
198 #ifdef DRACO
199 }
200 #endif
201 kbd_softc.k_event_mode = 0;
202 kbd_softc.k_events.ev_io = 0;
203 splx(s);
204 }
205
206 #ifdef DRACO
207 /*
208 * call this with kbd interupt blocked
209 */
210
211 int
212 drkbdgetc()
213 {
214 u_int8_t in;
215
216 while ((draco_ioct->io_status & DRSTAT_KBDRECV) == 0);
217 in = draco_ioct->io_kbddata;
218 draco_ioct->io_kbdrst = 0;
219
220 return in;
221 }
222
223 #define WAIT0 if (drkbdwaitfor(0)) goto Ltimeout
224 #define WAIT1 if (drkbdwaitfor(DRSTAT_KBDCLKIN)) goto Ltimeout
225
226 int
227 drkbdwaitfor(bit)
228 int bit;
229 {
230 int i;
231
232
233
234 i = 60000; /* about 50 ms max */
235
236 do {
237 if ((draco_ioct->io_status & DRSTAT_KBDCLKIN) == bit)
238 return 0;
239
240 } while (--i >= 0);
241
242 return 1;
243 }
244
245 /*
246 * Output a raw byte to the keyboard (+ parity and stop bit).
247 * return 0 on success, 1 on timeout.
248 */
249 int
250 drkbdrputc(c)
251 u_int8_t c;
252 {
253 u_int8_t parity;
254 int bitcnt;
255
256 DATLO; CLKHI; WAIT1;
257 parity = 0;
258
259 for (bitcnt=7; bitcnt >= 0; bitcnt--) {
260 WAIT0;
261 if (c & 1) {
262 DATHI;
263 } else {
264 ++parity;
265 DATLO;
266 }
267 c >>= 1;
268 WAIT1;
269 }
270 WAIT0;
271 /* parity bit */
272 if (parity & 1) {
273 DATLO;
274 } else {
275 DATHI;
276 }
277 WAIT1;
278 /* stop bit */
279 WAIT0; DATHI; WAIT1;
280
281 WAIT0; /* XXX should check the ack bit here... */
282 WAIT1;
283 draco_ioct->io_kbdrst = 0;
284 return 0;
285
286 Ltimeout:
287 DATHI;
288 draco_ioct->io_kbdrst = 0;
289 return 1;
290 }
291
292 /*
293 * Output one cooked byte to the keyboard, with wait for ACK or RESEND,
294 * and retry if necessary. 0 == success, 1 == timeout
295 */
296 int
297 drkbdputc(c)
298 u_int8_t c;
299 {
300 int rc;
301
302 do {
303 if (drkbdrputc(c))
304 return(-1);
305
306 rc = drkbdgetc();
307 } while (rc == 0xfe);
308 return (!(rc == 0xfa));
309 }
310
311 /*
312 * same for twobyte sequence
313 */
314
315 int
316 drkbdputc2(c1, c2)
317 u_int8_t c1, c2;
318 {
319 int rc;
320
321 do {
322 do {
323 if (drkbdrputc(c1))
324 return(-1);
325
326 rc = drkbdgetc();
327 } while (rc == 0xfe);
328 if (rc != 0xfa)
329 return (-1);
330
331 if (drkbdrputc(c2))
332 return(-1);
333
334 rc = drkbdgetc();
335 } while (rc == 0xfe);
336 return (!(rc == 0xfa));
337 }
338 #endif
339
340 int
341 kbdopen(dev, flags, mode, p)
342 dev_t dev;
343 int flags, mode;
344 struct proc *p;
345 {
346
347 kbdenable();
348 if (kbd_softc.k_events.ev_io)
349 return EBUSY;
350
351 kbd_softc.k_events.ev_io = p;
352 ev_init(&kbd_softc.k_events);
353 return (0);
354 }
355
356 int
357 kbdclose(dev, flags, mode, p)
358 dev_t dev;
359 int flags, mode;
360 struct proc *p;
361 {
362
363 /* Turn off event mode, dump the queue */
364 kbd_softc.k_event_mode = 0;
365 ev_fini(&kbd_softc.k_events);
366 kbd_softc.k_events.ev_io = NULL;
367 return (0);
368 }
369
370 int
371 kbdread(dev, uio, flags)
372 dev_t dev;
373 struct uio *uio;
374 int flags;
375 {
376 return ev_read (&kbd_softc.k_events, uio, flags);
377 }
378
379 int
380 kbdioctl(dev, cmd, data, flag, p)
381 dev_t dev;
382 u_long cmd;
383 register caddr_t data;
384 int flag;
385 struct proc *p;
386 {
387 register struct kbd_softc *k = &kbd_softc;
388
389 switch (cmd) {
390 case KIOCTRANS:
391 if (*(int *)data == TR_UNTRANS_EVENT)
392 return 0;
393 break;
394
395 case KIOCGTRANS:
396 /* Get translation mode */
397 *(int *)data = TR_UNTRANS_EVENT;
398 return 0;
399
400 case KIOCSDIRECT:
401 k->k_event_mode = *(int *)data;
402 return 0;
403
404 case FIONBIO: /* we will remove this someday (soon???) */
405 return 0;
406
407 case FIOASYNC:
408 k->k_events.ev_async = *(int *)data != 0;
409 return 0;
410
411 case TIOCSPGRP:
412 if (*(int *)data != k->k_events.ev_io->p_pgid)
413 return EPERM;
414 return 0;
415
416 default:
417 return ENOTTY;
418 }
419
420 /* We identified the ioctl, but we do not handle it. */
421 return EOPNOTSUPP; /* misuse, but what the heck */
422 }
423
424 int
425 kbdpoll(dev, events, p)
426 dev_t dev;
427 int events;
428 struct proc *p;
429 {
430 return ev_poll (&kbd_softc.k_events, events, p);
431 }
432
433
434 void
435 kbdintr(mask)
436 int mask;
437 {
438 u_char c;
439 #ifdef KBDRESET
440 static int reset_warn;
441 #endif
442
443 /*
444 * now only invoked from generic CIA interrupt handler if there *is*
445 * a keyboard interrupt pending
446 */
447
448 c = ~ciaa.sdr; /* keyboard data is inverted */
449 /* ack */
450 ciaa.cra |= (1 << 6); /* serial line output */
451 #ifdef KBDRESET
452 if (reset_warn && c == 0xf0) {
453 #ifdef DEBUG
454 printf ("kbdintr: !!!! Reset Warning !!!!\n");
455 #endif
456 bootsync();
457 reset_warn = 0;
458 DELAY(30000000);
459 }
460 #endif
461 /* wait 200 microseconds (for bloody Cherry keyboards..) */
462 DELAY(2000); /* fudge delay a bit for some keyboards */
463 ciaa.cra &= ~(1 << 6);
464
465 /* process the character */
466 c = (c >> 1) | (c << 7); /* rotate right once */
467
468 #ifdef KBDRESET
469 if (c == 0x78) {
470 #ifdef DEBUG
471 printf ("kbdintr: Reset Warning started\n");
472 #endif
473 ++reset_warn;
474 return;
475 }
476 #endif
477 kbdstuffchar(c);
478 }
479
480 #ifdef DRACO
481 /* maps MF-II keycodes to Amiga keycodes */
482
483 const u_char drkbdtab[] = {
484 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x50,
485 0x45, 0xff, 0xff, 0xff, 0xff, 0x42, 0x00, 0x51,
486
487 0xff, 0x64, 0x60, 0x30, 0x63, 0x10, 0x01, 0x52,
488 0xff, 0x66, 0x31, 0x21, 0x20, 0x11, 0x02, 0x53,
489
490 0xff, 0x33, 0x32, 0x22, 0x12, 0x04, 0x03, 0x54,
491 0xff, 0x40, 0x34, 0x23, 0x14, 0x13, 0x05, 0x55,
492
493 0xff, 0x36, 0x35, 0x25, 0x24, 0x15, 0x06, 0x56,
494 0xff, 0x67, 0x37, 0x26, 0x16, 0x07, 0x08, 0x57,
495 /* --- */
496 0xff, 0x38, 0x27, 0x17, 0x18, 0x0a, 0x09, 0x58,
497 0xff, 0x39, 0x3a, 0x28, 0x29, 0x19, 0x0b, 0x59,
498
499 0xff, 0xff, 0x2a, 0x2b, 0x1a, 0x0c, 0x4b, 0xff,
500 0x65, 0x61, 0x44, 0x1b, 0xff, 0xff, 0x6f, 0xff,
501
502 0x4d, 0x4f, 0xff, 0x4c, 0x0d, 0xff, 0x41, 0x46,
503 0xff, 0x1d, 0x4e, 0x2d, 0x3d, 0x4a, 0x5f, 0x62,
504
505 0x0f, 0x3c, 0x1e, 0x2e, 0x2f, 0x3e, 0x5a, 0x5b,
506 0xff, 0x43, 0x1f, 0xff, 0x5e, 0x3f, 0x5c, 0xff,
507 /* --- */
508 0xff, 0xff, 0xff, 0xff, 0x5d
509 };
510 #endif
511
512
513 int
514 kbdgetcn ()
515 {
516 int s;
517 u_char ints, mask, c, in;
518
519 #ifdef DRACO
520 if (is_draco() && kbd_softc.k_mf2) {
521 do {
522 c = 0;
523 s = spltty ();
524 while ((draco_ioct->io_status & DRSTAT_KBDRECV) == 0);
525 in = draco_ioct->io_kbddata;
526 draco_ioct->io_kbdrst = 0;
527 if (in == 0xF0) { /* release prefix */
528 c = 0x80;
529 while ((draco_ioct->io_status &
530 DRSTAT_KBDRECV) == 0);
531 in = draco_ioct->io_kbddata;
532 draco_ioct->io_kbdrst = 0;
533 }
534 splx(s);
535 #ifdef DRACORAWKEYDEBUG
536 printf("<%02x>", in);
537 #endif
538 c |= in>=sizeof(drkbdtab) ? 0xff : drkbdtab[in];
539 } while (c == 0xff);
540 return (c);
541 }
542 #endif
543 s = spltty();
544 for (ints = 0; ! ((mask = ciaa.icr) & CIA_ICR_SP);
545 ints |= mask) ;
546
547 in = ciaa.sdr;
548 c = ~in;
549
550 /* ack */
551 ciaa.cra |= (1 << 6); /* serial line output */
552 ciaa.sdr = 0xff; /* ack */
553 /* wait 200 microseconds */
554 DELAY(2000); /* XXXX only works as long as DELAY doesn't
555 * use a timer and waits.. */
556 ciaa.cra &= ~(1 << 6);
557 ciaa.sdr = in;
558
559 splx (s);
560 c = (c >> 1) | (c << 7);
561
562 /* take care that no CIA-interrupts are lost */
563 if (ints)
564 dispatch_cia_ints (0, ints);
565
566 return c;
567 }
568
569 void
570 kbdstuffchar(c)
571 u_char c;
572 {
573 struct firm_event *fe;
574 struct kbd_softc *k = &kbd_softc;
575 int put;
576
577 /*
578 * If not in event mode, deliver straight to ite to process
579 * key stroke
580 */
581
582 if (! k->k_event_mode) {
583 ite_filter (c, ITEFILT_TTY);
584 return;
585 }
586
587 /*
588 * Keyboard is generating events. Turn this keystroke into an
589 * event and put it in the queue. If the queue is full, the
590 * keystroke is lost (sorry!).
591 */
592
593 put = k->k_events.ev_put;
594 fe = &k->k_events.ev_q[put];
595 put = (put + 1) % EV_QSIZE;
596 if (put == k->k_events.ev_get) {
597 log(LOG_WARNING, "keyboard event queue overflow\n");
598 /* ??? */
599 return;
600 }
601 fe->id = KEY_CODE(c);
602 fe->value = KEY_UP(c) ? VKEY_UP : VKEY_DOWN;
603 fe->time = time;
604 k->k_events.ev_put = put;
605 EV_WAKEUP(&k->k_events);
606 }
607
608
609 #ifdef DRACO
610 void
611 drkbdintr()
612 {
613 u_char in;
614 struct kbd_softc *k = &kbd_softc;
615
616 in = draco_ioct->io_kbddata;
617 draco_ioct->io_kbdrst = 0;
618
619 if (in == 0xF0)
620 k->k_rlprfx = 0x80;
621 else {
622 kbdstuffchar(in>=sizeof(drkbdtab) ? 0xff :
623 drkbdtab[in] | k->k_rlprfx);
624 k->k_rlprfx = 0;
625 }
626 }
627
628 #endif
629