1 /* $NetBSD: kbd.c,v 1.52 2009/03/14 15:36:01 dsl Exp $ */
4 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: kbd.c,v 1.52 2009/03/14 15:36:01 dsl Exp $");
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/device.h>
40 #include <sys/ioctl.h>
44 #include <sys/kernel.h>
45 #include <sys/syslog.h>
46 #include <sys/signalvar.h>
49 #include <machine/cpu.h>
50 #include <amiga/amiga/device.h>
51 #include <amiga/amiga/custom.h>
53 #include <m68k/asm_single.h>
54 #include <amiga/amiga/drcustom.h>
56 #include <amiga/amiga/cia.h>
57 #include <amiga/dev/itevar.h>
58 #include <amiga/dev/kbdreg.h>
59 #include <amiga/dev/kbdmap.h>
60 #include <amiga/dev/kbdvar.h>
61 #include <amiga/dev/event_var.h>
62 #include <amiga/dev/vuid_event.h>
70 * If NWSKBD>0 we try to attach an wskbd device to us. What follows
71 * is definitions of callback functions and structures that are passed
72 * to wscons when initializing.
76 * Now with wscons this driver exhibits some weird behaviour.
77 * It may act both as a driver of its own and the md part of the
78 * wskbd driver. Therefore it can be accessed through /dev/kbd
79 * and /dev/wskbd0 both.
81 * The data from they keyboard may end up in at least four different
83 * - If this driver has been opened (/dev/kbd) and the
84 * direct mode (TIOCDIRECT) has been set, data goes to
85 * the process who opened the device. Data will transmit itself
86 * as described by the firm_event structure.
87 * - If wskbd support is compiled in and a wskbd driver has been
88 * attached then the data is sent to it. Wskbd in turn may
89 * - Send the data in the wscons_event form to a process that
90 * has opened /dev/wskbd0
91 * - Feed the data to a virtual terminal.
92 * - If an ite is present the data may be fed to it.
98 #include <dev/wscons/wsconsio.h>
99 #include <dev/wscons/wskbdvar.h>
100 #include <dev/wscons/wsksymdef.h>
101 #include <dev/wscons/wsksymvar.h>
102 #include <amiga/dev/wskbdmap_amiga.h>
105 int kbd_enable(void *, int);
106 void kbd_set_leds(void *, int);
107 int kbd_ioctl(void *, u_long
, void *, int, struct lwp
*);
110 void kbd_getc(void *, u_int
*, int *);
111 void kbd_pollc(void *, int);
112 void kbd_bell(void *, u_int
, u_int
, u_int
);
114 static struct wskbd_accessops kbd_accessops
= {
120 static struct wskbd_consops kbd_consops
= {
127 * Pointer to keymaps. They are defined in wskbdmap_amiga.c.
129 static struct wskbd_mapdata kbd_mapdata
= {
137 int k_event_mode
; /* if true, collect events, else pass to ite */
138 struct evvar k_events
; /* event queue state */
140 u_char k_rlprfx
; /* MF-II rel. prefix has been seen */
144 int k_console
; /* true if used as console keyboard */
146 struct device
*k_wskbddev
; /* pointer to wskbd for sending strokes */
147 int k_pollingmode
; /* polling mode on? whatever it isss... */
150 struct kbd_softc kbd_softc
;
152 int kbdmatch(struct device
*, struct cfdata
*, void *);
153 void kbdattach(struct device
*, struct device
*, void *);
155 void kbdstuffchar(u_char
);
158 int drkbdrputc(u_int8_t
);
159 int drkbdputc(u_int8_t
);
160 int drkbdputc2(u_int8_t
, u_int8_t
);
161 int drkbdwaitfor(int);
163 CFATTACH_DECL(kbd
, sizeof(struct device
),
164 kbdmatch
, kbdattach
, NULL
, NULL
);
166 dev_type_open(kbdopen
);
167 dev_type_close(kbdclose
);
168 dev_type_read(kbdread
);
169 dev_type_ioctl(kbdioctl
);
170 dev_type_poll(kbdpoll
);
171 dev_type_kqfilter(kbdkqfilter
);
173 const struct cdevsw kbd_cdevsw
= {
174 kbdopen
, kbdclose
, kbdread
, nowrite
, kbdioctl
,
175 nostop
, notty
, kbdpoll
, nommap
, kbdkqfilter
,
180 kbdmatch(struct device
*pdp
, struct cfdata
*cfp
, void *auxp
)
183 if (matchname((char *)auxp
, "kbd"))
190 kbdattach(struct device
*pdp
, struct device
*dp
, void *auxp
)
195 printf(": QuickLogic type MF-II\n");
197 printf(": CIA A type Amiga\n");
199 printf(": CIA A type Amiga\n");
205 * Try to attach the wskbd.
207 struct wskbddev_attach_args waa
;
208 waa
.console
= kbd_softc
.k_console
;
209 waa
.keymap
= &kbd_mapdata
;
210 waa
.accessops
= &kbd_accessops
;
211 waa
.accesscookie
= NULL
;
212 kbd_softc
.k_wskbddev
= config_found(dp
, &waa
, wskbddevprint
);
214 kbd_softc
.k_pollingmode
= 0;
221 * This is called when somebody wants to use kbd as the console keyboard.
227 wskbd_cnattach(&kbd_consops
, NULL
, &kbd_mapdata
);
228 kbd_softc
.k_console
= 1;
232 /* definitions for amiga keyboard encoding. */
233 #define KEY_CODE(c) ((c) & 0x7f)
234 #define KEY_UP(c) ((c) & 0x80)
236 #define DATLO single_inst_bclr_b(draco_ioct->io_control, DRCNTRL_KBDDATOUT)
237 #define DATHI single_inst_bset_b(draco_ioct->io_control, DRCNTRL_KBDDATOUT)
239 #define CLKLO single_inst_bclr_b(draco_ioct->io_control, DRCNTRL_KBDCLKOUT)
240 #define CLKHI single_inst_bset_b(draco_ioct->io_control, DRCNTRL_KBDCLKOUT)
245 static int kbd_inited
= 0;
253 * collides with external ints from SCSI, watch out for this when
254 * enabling/disabling interrupts there !!
256 s
= splhigh(); /* don't lower; might be called from early ddb */
267 draco_ioct
->io_kbdrst
= 0;
272 id
= drkbdgetc() << 8;
278 if (drkbdputc2(0xf0, 3)) /* mode 3 */
281 if (drkbdputc(0xf8)) /* make/break, no typematic */
284 if (drkbdputc(0xf4)) /* enable */
287 single_inst_bclr_b(draco_ioct
->io_control
, DRCNTRL_KBDINTENA
);
289 ciaa
.icr
= CIA_ICR_SP
; /* CIA SP interrupt disable */
290 ciaa
.cra
&= ~(1<<6); /* serial line == input */
296 single_inst_bset_b(*draco_intena
, DRIRQ_INT2
);
297 ciaa
.icr
= CIA_ICR_IR_SC
| CIA_ICR_SP
;
298 /* SP interrupt enable */
299 ciaa
.cra
&= ~(1<<6); /* serial line == input */
305 custom
.intena
= INTF_SETCLR
| INTF_PORTS
;
306 ciaa
.icr
= CIA_ICR_IR_SC
| CIA_ICR_SP
; /* SP interrupt enable */
307 ciaa
.cra
&= ~(1<<6); /* serial line == input */
311 kbd_softc
.k_event_mode
= 0;
312 kbd_softc
.k_events
.ev_io
= 0;
318 * call this with kbd interrupt blocked
326 while ((draco_ioct
->io_status
& DRSTAT_KBDRECV
) == 0);
327 in
= draco_ioct
->io_kbddata
;
328 draco_ioct
->io_kbdrst
= 0;
333 #define WAIT0 if (drkbdwaitfor(0)) goto Ltimeout
334 #define WAIT1 if (drkbdwaitfor(DRSTAT_KBDCLKIN)) goto Ltimeout
337 drkbdwaitfor(int bit
)
343 i
= 60000; /* about 50 ms max */
346 if ((draco_ioct
->io_status
& DRSTAT_KBDCLKIN
) == bit
)
355 * Output a raw byte to the keyboard (+ parity and stop bit).
356 * return 0 on success, 1 on timeout.
359 drkbdrputc(u_int8_t c
)
367 for (bitcnt
=7; bitcnt
>= 0; bitcnt
--) {
389 WAIT0
; /* XXX should check the ack bit here... */
391 draco_ioct
->io_kbdrst
= 0;
396 draco_ioct
->io_kbdrst
= 0;
401 * Output one cooked byte to the keyboard, with wait for ACK or RESEND,
402 * and retry if necessary. 0 == success, 1 == timeout
405 drkbdputc(u_int8_t c
)
414 } while (rc
== 0xfe);
415 return (!(rc
== 0xfa));
419 * same for twobyte sequence
423 drkbdputc2(u_int8_t c1
, u_int8_t c2
)
433 } while (rc
== 0xfe);
441 } while (rc
== 0xfe);
442 return (!(rc
== 0xfa));
447 kbdopen(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
451 if (kbd_softc
.k_events
.ev_io
)
454 kbd_softc
.k_events
.ev_io
= l
->l_proc
;
455 ev_init(&kbd_softc
.k_events
);
460 kbdclose(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
463 /* Turn off event mode, dump the queue */
464 kbd_softc
.k_event_mode
= 0;
465 ev_fini(&kbd_softc
.k_events
);
466 kbd_softc
.k_events
.ev_io
= NULL
;
471 kbdread(dev_t dev
, struct uio
*uio
, int flags
)
473 return ev_read (&kbd_softc
.k_events
, uio
, flags
);
477 kbdioctl(dev_t dev
, u_long cmd
, register void *data
, int flag
,
480 register struct kbd_softc
*k
= &kbd_softc
;
484 if (*(int *)data
== TR_UNTRANS_EVENT
)
489 /* Get translation mode */
490 *(int *)data
= TR_UNTRANS_EVENT
;
494 k
->k_event_mode
= *(int *)data
;
497 case FIONBIO
: /* we will remove this someday (soon???) */
501 k
->k_events
.ev_async
= *(int *)data
!= 0;
505 if (-*(int *)data
!= k
->k_events
.ev_io
->p_pgid
506 && *(int *)data
!= k
->k_events
.ev_io
->p_pid
)
511 if (*(int *)data
!= k
->k_events
.ev_io
->p_pgid
)
519 /* We identified the ioctl, but we do not handle it. */
520 return EOPNOTSUPP
; /* misuse, but what the heck */
524 kbdpoll(dev_t dev
, int events
, struct lwp
*l
)
526 return ev_poll (&kbd_softc
.k_events
, events
, l
);
530 kbdkqfilter(dev_t dev
, struct knote
*kn
)
533 return (ev_kqfilter(&kbd_softc
.k_events
, kn
));
541 static int reset_warn
;
545 * now only invoked from generic CIA interrupt handler if there *is*
546 * a keyboard interrupt pending
549 c
= ~ciaa
.sdr
; /* keyboard data is inverted */
551 ciaa
.cra
|= (1 << 6); /* serial line output */
553 if (reset_warn
&& c
== 0xf0) {
555 printf ("kbdintr: !!!! Reset Warning !!!!\n");
562 /* wait 200 microseconds (for bloody Cherry keyboards..) */
563 DELAY(200); /* fudge delay a bit for some keyboards */
564 ciaa
.cra
&= ~(1 << 6);
566 /* process the character */
567 c
= (c
>> 1) | (c
<< 7); /* rotate right once */
572 printf ("kbdintr: Reset Warning started\n");
582 /* maps MF-II keycodes to Amiga keycodes */
584 const u_char drkbdtab
[] = {
585 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x50,
586 0x45, 0xff, 0xff, 0xff, 0xff, 0x42, 0x00, 0x51,
588 0xff, 0x64, 0x60, 0x30, 0x63, 0x10, 0x01, 0x52,
589 0xff, 0x66, 0x31, 0x21, 0x20, 0x11, 0x02, 0x53,
591 0xff, 0x33, 0x32, 0x22, 0x12, 0x04, 0x03, 0x54,
592 0xff, 0x40, 0x34, 0x23, 0x14, 0x13, 0x05, 0x55,
594 0xff, 0x36, 0x35, 0x25, 0x24, 0x15, 0x06, 0x56,
595 0xff, 0x67, 0x37, 0x26, 0x16, 0x07, 0x08, 0x57,
597 0xff, 0x38, 0x27, 0x17, 0x18, 0x0a, 0x09, 0x58,
598 0xff, 0x39, 0x3a, 0x28, 0x29, 0x19, 0x0b, 0x59,
600 0xff, 0xff, 0x2a, 0x2b, 0x1a, 0x0c, 0x4b, 0xff,
601 0x65, 0x61, 0x44, 0x1b, 0xff, 0xff, 0x6f, 0xff,
603 0x4d, 0x4f, 0xff, 0x4c, 0x0d, 0xff, 0x41, 0x46,
604 0xff, 0x1d, 0x4e, 0x2d, 0x3d, 0x4a, 0x5f, 0x62,
606 0x0f, 0x3c, 0x1e, 0x2e, 0x2f, 0x3e, 0x5a, 0x5b,
607 0xff, 0x43, 0x1f, 0xff, 0x5e, 0x3f, 0x5c, 0xff,
609 0xff, 0xff, 0xff, 0xff, 0x5d
618 u_char ints
, mask
, c
, in
;
621 if (is_draco() && kbd_softc
.k_mf2
) {
625 while ((draco_ioct
->io_status
& DRSTAT_KBDRECV
) == 0);
626 in
= draco_ioct
->io_kbddata
;
627 draco_ioct
->io_kbdrst
= 0;
628 if (in
== 0xF0) { /* release prefix */
630 while ((draco_ioct
->io_status
&
631 DRSTAT_KBDRECV
) == 0);
632 in
= draco_ioct
->io_kbddata
;
633 draco_ioct
->io_kbdrst
= 0;
636 #ifdef DRACORAWKEYDEBUG
637 printf("<%02x>", in
);
639 c
|= in
>=sizeof(drkbdtab
) ? 0xff : drkbdtab
[in
];
645 for (ints
= 0; ! ((mask
= ciaa
.icr
) & CIA_ICR_SP
);
652 ciaa
.cra
|= (1 << 6); /* serial line output */
653 ciaa
.sdr
= 0xff; /* ack */
654 /* wait 200 microseconds */
655 DELAY(200); /* XXXX only works as long as DELAY doesn't
656 * use a timer and waits.. */
657 ciaa
.cra
&= ~(1 << 6);
661 c
= (c
>> 1) | (c
<< 7);
663 /* take care that no CIA-interrupts are lost */
665 dispatch_cia_ints (0, ints
);
671 kbdstuffchar(u_char c
)
673 struct firm_event
*fe
;
674 struct kbd_softc
*k
= &kbd_softc
;
679 * If we have attached a wskbd and not in polling mode and
680 * nobody has opened us directly, then send the keystroke
684 if (kbd_softc
.k_pollingmode
== 0
685 && kbd_softc
.k_wskbddev
!= NULL
686 && k
->k_event_mode
== 0) {
687 wskbd_input(kbd_softc
.k_wskbddev
,
689 WSCONS_EVENT_KEY_UP
:
690 WSCONS_EVENT_KEY_DOWN
,
698 * If not in event mode, deliver straight to ite to process
702 if (! k
->k_event_mode
) {
704 ite_filter (c
, ITEFILT_TTY
);
710 * Keyboard is generating events. Turn this keystroke into an
711 * event and put it in the queue. If the queue is full, the
712 * keystroke is lost (sorry!).
715 put
= k
->k_events
.ev_put
;
716 fe
= &k
->k_events
.ev_q
[put
];
717 put
= (put
+ 1) % EV_QSIZE
;
718 if (put
== k
->k_events
.ev_get
) {
719 log(LOG_WARNING
, "keyboard event queue overflow\n");
723 fe
->id
= KEY_CODE(c
);
724 fe
->value
= KEY_UP(c
) ? VKEY_UP
: VKEY_DOWN
;
726 k
->k_events
.ev_put
= put
;
727 EV_WAKEUP(&k
->k_events
);
736 struct kbd_softc
*k
= &kbd_softc
;
738 in
= draco_ioct
->io_kbddata
;
739 draco_ioct
->io_kbdrst
= 0;
744 kbdstuffchar(in
>=sizeof(drkbdtab
) ? 0xff :
745 drkbdtab
[in
] | k
->k_rlprfx
);
755 * These are the callback functions that are passed to wscons.
756 * They really don't do anything worth noting, just call the
757 * other functions above.
761 kbd_enable(void *c
, int on
)
763 /* Wonder what this is supposed to do... */
768 kbd_set_leds(void *c
, int leds
)
773 kbd_ioctl(void *c
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
777 case WSKBDIO_COMPLEXBELL
:
779 case WSKBDIO_SETLEDS
:
781 case WSKBDIO_GETLEDS
:
785 *(u_int
*)data
= WSKBD_TYPE_AMIGA
;
790 * We are supposed to return EPASSTHROUGH to wscons if we didn't
793 return (EPASSTHROUGH
);
797 kbd_getc(void *c
, u_int
*type
, int *data
)
803 *data
= KEY_CODE(key
);
804 *type
= KEY_UP(key
) ? WSCONS_EVENT_KEY_UP
: WSCONS_EVENT_KEY_DOWN
;
808 kbd_pollc(void *c
, int on
)
810 kbd_softc
.k_pollingmode
= on
;
814 kbd_bell(void *c
, u_int x
, u_int y
, u_int z
)