kbd.c revision 1.32 1 /* $NetBSD: kbd.c,v 1.32 1998/03/08 19:59: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
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 *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 & DRSTAT_KBDRECV) == 0);
530 in = draco_ioct->io_kbddata;
531 draco_ioct->io_kbdrst = 0;
532 }
533 splx(s);
534 #ifdef DRACORAWKEYDEBUG
535 printf("<%02x>", in);
536 #endif
537 c |= in>=sizeof(drkbdtab) ? 0xff : drkbdtab[in];
538 } while (c == 0xff);
539 return (c);
540 }
541 #endif
542 s = spltty();
543 for (ints = 0; ! ((mask = ciaa.icr) & CIA_ICR_SP);
544 ints |= mask) ;
545
546 in = ciaa.sdr;
547 c = ~in;
548
549 /* ack */
550 ciaa.cra |= (1 << 6); /* serial line output */
551 ciaa.sdr = 0xff; /* ack */
552 /* wait 200 microseconds */
553 DELAY(2000); /* XXXX only works as long as DELAY doesn't
554 * use a timer and waits.. */
555 ciaa.cra &= ~(1 << 6);
556 ciaa.sdr = in;
557
558 splx (s);
559 c = (c >> 1) | (c << 7);
560
561 /* take care that no CIA-interrupts are lost */
562 if (ints)
563 dispatch_cia_ints (0, ints);
564
565 return c;
566 }
567
568 void
569 kbdstuffchar(c)
570 u_char c;
571 {
572 struct firm_event *fe;
573 struct kbd_softc *k = &kbd_softc;
574 int put;
575
576 /*
577 * If not in event mode, deliver straight to ite to process
578 * key stroke
579 */
580
581 if (! k->k_event_mode) {
582 ite_filter (c, ITEFILT_TTY);
583 return;
584 }
585
586 /*
587 * Keyboard is generating events. Turn this keystroke into an
588 * event and put it in the queue. If the queue is full, the
589 * keystroke is lost (sorry!).
590 */
591
592 put = k->k_events.ev_put;
593 fe = &k->k_events.ev_q[put];
594 put = (put + 1) % EV_QSIZE;
595 if (put == k->k_events.ev_get) {
596 log(LOG_WARNING, "keyboard event queue overflow\n");
597 /* ??? */
598 return;
599 }
600 fe->id = KEY_CODE(c);
601 fe->value = KEY_UP(c) ? VKEY_UP : VKEY_DOWN;
602 fe->time = time;
603 k->k_events.ev_put = put;
604 EV_WAKEUP(&k->k_events);
605 }
606
607
608 #ifdef DRACO
609 void
610 drkbdintr()
611 {
612 u_char in;
613 struct kbd_softc *k = &kbd_softc;
614
615 in = draco_ioct->io_kbddata;
616 draco_ioct->io_kbdrst = 0;
617
618 if (in == 0xF0)
619 k->k_rlprfx = 0x80;
620 else {
621 kbdstuffchar(in>=sizeof(drkbdtab) ? 0xff :
622 drkbdtab[in] | k->k_rlprfx);
623 k->k_rlprfx = 0;
624 }
625 }
626
627 #endif
628