1 /* $NetBSD: kbd.c,v 1.35 2008/06/25 08:14:59 isaki 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
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: kbd.c,v 1.35 2008/06/25 08:14:59 isaki Exp $");
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/device.h>
41 #include <sys/ioctl.h>
47 #include <sys/kernel.h>
48 #include <sys/syslog.h>
49 #include <sys/signalvar.h>
54 #include <arch/x68k/dev/intiovar.h>
55 #include <arch/x68k/dev/mfp.h>
56 #include <arch/x68k/dev/itevar.h>
58 /* for sun-like event mode, if you go thru /dev/kbd. */
59 #include <arch/x68k/dev/event_var.h>
61 #include <machine/kbio.h>
62 #include <machine/kbd.h>
63 #include <machine/vuid_event.h>
66 int sc_event_mode
; /* if true, collect events, else pass to ite */
67 struct evvar sc_events
; /* event queue state */
68 void *sc_softintr_cookie
;
73 void kbdsoftint(void *);
76 void kbd_setLED(void);
77 int kbd_send_command(int);
80 static int kbdmatch(device_t
, cfdata_t
, void *);
81 static void kbdattach(device_t
, device_t
, void *);
83 CFATTACH_DECL_NEW(kbd
, sizeof(struct kbd_softc
),
84 kbdmatch
, kbdattach
, NULL
, NULL
);
86 static int kbd_attached
;
88 dev_type_open(kbdopen
);
89 dev_type_close(kbdclose
);
90 dev_type_read(kbdread
);
91 dev_type_ioctl(kbdioctl
);
92 dev_type_poll(kbdpoll
);
93 dev_type_kqfilter(kbdkqfilter
);
95 const struct cdevsw kbd_cdevsw
= {
96 kbdopen
, kbdclose
, kbdread
, nowrite
, kbdioctl
,
97 nostop
, notty
, kbdpoll
, nommap
, kbdkqfilter
,
101 kbdmatch(device_t parent
, cfdata_t cf
, void *aux
)
104 if (strcmp(aux
, "kbd") != 0)
113 kbdattach(device_t parent
, device_t self
, void *aux
)
115 struct kbd_softc
*sc
= device_private(self
);
116 struct mfp_softc
*mfp
= device_private(parent
);
123 /* MFP interrupt #12 is for USART receive buffer full */
124 intio_intr_establish(mfp
->sc_intr
+ 12, "kbd", kbdintr
, sc
);
125 sc
->sc_softintr_cookie
= softint_establish(SOFTINT_SERIAL
,
129 sc
->sc_event_mode
= 0;
130 sc
->sc_events
.ev_io
= 0;
137 /* definitions for x68k keyboard encoding. */
138 #define KEY_CODE(c) ((c) & 0x7f)
139 #define KEY_UP(c) ((c) & 0x80)
142 kbdenable(int mode
) /* 1: interrupt, 0: poll */
145 intio_set_sysport_keyctrl(8);
146 mfp_bit_clear_iera(MFP_INTR_RCV_FULL
| MFP_INTR_TIMER_B
);
147 mfp_set_tbcr(MFP_TIMERB_RESET
| MFP_TIMERB_STOP
);
148 mfp_set_tbdr(13); /* Timer B interrupt interval */
149 mfp_set_tbcr(1); /* 1/4 delay mode */
150 mfp_set_ucr(MFP_UCR_CLKX16
| MFP_UCR_RW_8
| MFP_UCR_ONESB
);
151 mfp_set_rsr(MFP_RSR_RE
); /* USART receive enable */
152 mfp_set_tsr(MFP_TSR_TE
); /* USART transmit enable */
155 mfp_bit_set_iera(MFP_INTR_RCV_FULL
);
157 * Perform null read in case that an input byte is in the
158 * receiver buffer, which prevents further interrupts.
159 * We could save the input, but probably not so valuable.
161 (void) mfp_get_udr();
164 kbdled
= 0; /* all keyboard LED turn off. */
167 if (!(intio_get_sysport_keyctrl() & 8))
168 aprint_normal(" (no connected keyboard)");
171 extern struct cfdriver kbd_cd
;
174 kbdopen(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
178 k
= device_lookup_private(&kbd_cd
, minor(dev
));
182 if (k
->sc_events
.ev_io
)
184 k
->sc_events
.ev_io
= l
->l_proc
;
185 ev_init(&k
->sc_events
);
191 kbdclose(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
193 struct kbd_softc
*k
= device_lookup_private(&kbd_cd
, minor(dev
));
195 /* Turn off event mode, dump the queue */
196 k
->sc_event_mode
= 0;
197 ev_fini(&k
->sc_events
);
198 k
->sc_events
.ev_io
= NULL
;
205 kbdread(dev_t dev
, struct uio
*uio
, int flags
)
207 struct kbd_softc
*k
= device_lookup_private(&kbd_cd
, minor(dev
));
209 return ev_read(&k
->sc_events
, uio
, flags
);
214 int opm_bell_setup(struct bell_info
*);
215 void opm_bell_on(void);
216 void opm_bell_off(void);
220 kbdioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
222 struct kbd_softc
*k
= device_lookup_private(&kbd_cd
, minor(dev
));
227 if (*(int *)data
== TR_UNTRANS_EVENT
)
233 * Get translation mode
235 *(int *)data
= TR_UNTRANS_EVENT
;
239 k
->sc_event_mode
= *(int *)data
;
243 cmd_data
= *(int *)data
;
244 return kbd_send_command(cmd_data
);
247 kbdled
= *(char *)data
;
252 *(char *)data
= kbdled
;
257 return opm_bell_setup((struct bell_info
*)data
);
259 return (0); /* always success */
262 case FIONBIO
: /* we will remove this someday (soon???) */
266 k
->sc_events
.ev_async
= *(int *)data
!= 0;
270 if (-*(int *)data
!= k
->sc_events
.ev_io
->p_pgid
271 && *(int *)data
!= k
->sc_events
.ev_io
->p_pid
)
276 if (*(int *)data
!= k
->sc_events
.ev_io
->p_pgid
)
285 * We identified the ioctl, but we do not handle it.
287 return (EOPNOTSUPP
); /* misuse, but what the heck */
292 kbdpoll(dev_t dev
, int events
, struct lwp
*l
)
296 k
= device_lookup_private(&kbd_cd
, minor(dev
));
297 return (ev_poll(&k
->sc_events
, events
, l
));
301 kbdkqfilter(dev_t dev
, struct knote
*kn
)
305 k
= device_lookup_private(&kbd_cd
, minor(dev
));
306 return (ev_kqfilter(&k
->sc_events
, kn
));
309 #define KBDBUFMASK 63
311 static u_char kbdbuf
[KBDBUFSIZ
];
312 static int kbdputoff
= 0;
313 static int kbdgetoff
= 0;
319 struct kbd_softc
*sc
= arg
;
320 struct firm_event
*fe
;
323 /* clear receiver error if any */
328 if ((st
& MFP_RSR_BF
) == 0)
329 return 0; /* intr caused by an err -- no char received */
331 /* if not in event mode, deliver straight to ite to process key stroke */
332 if (!sc
->sc_event_mode
) {
333 kbdbuf
[kbdputoff
++ & KBDBUFMASK
] = c
;
334 softint_schedule(sc
->sc_softintr_cookie
);
338 /* Keyboard is generating events. Turn this keystroke into an
339 event and put it in the queue. If the queue is full, the
340 keystroke is lost (sorry!). */
342 put
= sc
->sc_events
.ev_put
;
343 fe
= &sc
->sc_events
.ev_q
[put
];
344 put
= (put
+ 1) % EV_QSIZE
;
345 if (put
== sc
->sc_events
.ev_get
) {
346 log(LOG_WARNING
, "keyboard event queue overflow\n"); /* ??? */
349 fe
->id
= KEY_CODE(c
);
350 fe
->value
= KEY_UP(c
) ? VKEY_UP
: VKEY_DOWN
;
352 sc
->sc_events
.ev_put
= put
;
353 EV_WAKEUP(&sc
->sc_events
);
359 kbdsoftint(void *arg
) /* what if ite is not configured? */
365 while(kbdgetoff
< kbdputoff
)
366 ite_filter(kbdbuf
[kbdgetoff
++ & KBDBUFMASK
]);
367 kbdgetoff
= kbdputoff
= 0;
383 unsigned char kbdled
;
388 mfp_send_usart(~kbdled
| 0x80);
392 kbd_send_command(int cmd
)
423 ints
= mfp_get_iera();
425 mfp_bit_clear_iera(MFP_INTR_RCV_FULL
);
426 mfp_set_rsr(mfp_get_rsr() | MFP_RSR_RE
);
427 c
= mfp_receive_usart();