Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / arch / x68k / dev / kbd.c
blobe988228f296c85bee1cc4bd7e53e0d7c9a7e15aa
1 /* $NetBSD: kbd.c,v 1.35 2008/06/25 08:14:59 isaki Exp $ */
3 /*
4 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
5 * All rights reserved.
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. 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
29 * SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: kbd.c,v 1.35 2008/06/25 08:14:59 isaki Exp $");
35 #include "ite.h"
36 #include "bell.h"
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/device.h>
41 #include <sys/ioctl.h>
42 #include <sys/tty.h>
43 #include <sys/proc.h>
44 #include <sys/conf.h>
45 #include <sys/file.h>
46 #include <sys/uio.h>
47 #include <sys/kernel.h>
48 #include <sys/syslog.h>
49 #include <sys/signalvar.h>
50 #include <sys/cpu.h>
51 #include <sys/bus.h>
52 #include <sys/intr.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>
65 struct kbd_softc {
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;
71 void kbdenable(int);
72 int kbdintr(void *);
73 void kbdsoftint(void *);
74 void kbd_bell(int);
75 int kbdcngetc(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,
100 static int
101 kbdmatch(device_t parent, cfdata_t cf, void *aux)
104 if (strcmp(aux, "kbd") != 0)
105 return (0);
106 if (kbd_attached)
107 return (0);
109 return (1);
112 static void
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);
117 int s;
119 kbd_attached = 1;
121 s = spltty();
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,
126 kbdsoftint, sc);
128 kbdenable(1);
129 sc->sc_event_mode = 0;
130 sc->sc_events.ev_io = 0;
131 splx(s);
133 aprint_normal("\n");
137 /* definitions for x68k keyboard encoding. */
138 #define KEY_CODE(c) ((c) & 0x7f)
139 #define KEY_UP(c) ((c) & 0x80)
141 void
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 */
154 if (mode) {
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. */
165 kbd_setLED();
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)
176 struct kbd_softc *k;
178 k = device_lookup_private(&kbd_cd, minor(dev));
179 if (k == NULL)
180 return (ENXIO);
182 if (k->sc_events.ev_io)
183 return (EBUSY);
184 k->sc_events.ev_io = l->l_proc;
185 ev_init(&k->sc_events);
187 return (0);
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;
200 return (0);
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);
212 #if NBELL > 0
213 struct bell_info;
214 int opm_bell_setup(struct bell_info *);
215 void opm_bell_on(void);
216 void opm_bell_off(void);
217 #endif
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));
223 int cmd_data;
225 switch (cmd) {
226 case KIOCTRANS:
227 if (*(int *)data == TR_UNTRANS_EVENT)
228 return (0);
229 break;
231 case KIOCGTRANS:
233 * Get translation mode
235 *(int *)data = TR_UNTRANS_EVENT;
236 return (0);
238 case KIOCSDIRECT:
239 k->sc_event_mode = *(int *)data;
240 return (0);
242 case KIOCCMD:
243 cmd_data = *(int *)data;
244 return kbd_send_command(cmd_data);
246 case KIOCSLED:
247 kbdled = *(char *)data;
248 kbd_setLED();
249 return (0);
251 case KIOCGLED:
252 *(char *)data = kbdled;
253 return (0);
255 case KIOCSBELL:
256 #if NBELL > 0
257 return opm_bell_setup((struct bell_info *)data);
258 #else
259 return (0); /* always success */
260 #endif
262 case FIONBIO: /* we will remove this someday (soon???) */
263 return (0);
265 case FIOASYNC:
266 k->sc_events.ev_async = *(int *)data != 0;
267 return (0);
269 case FIOSETOWN:
270 if (-*(int *)data != k->sc_events.ev_io->p_pgid
271 && *(int *)data != k->sc_events.ev_io->p_pid)
272 return (EPERM);
273 return 0;
275 case TIOCSPGRP:
276 if (*(int *)data != k->sc_events.ev_io->p_pgid)
277 return (EPERM);
278 return (0);
280 default:
281 return (ENOTTY);
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)
294 struct kbd_softc *k;
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)
303 struct kbd_softc *k;
305 k = device_lookup_private(&kbd_cd, minor(dev));
306 return (ev_kqfilter(&k->sc_events, kn));
309 #define KBDBUFMASK 63
310 #define KBDBUFSIZ 64
311 static u_char kbdbuf[KBDBUFSIZ];
312 static int kbdputoff = 0;
313 static int kbdgetoff = 0;
316 kbdintr(void *arg)
318 u_char c, st;
319 struct kbd_softc *sc = arg;
320 struct firm_event *fe;
321 int put;
323 /* clear receiver error if any */
324 st = mfp_get_rsr();
326 c = mfp_get_udr();
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);
335 return 0;
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"); /* ??? */
347 return 0;
349 fe->id = KEY_CODE(c);
350 fe->value = KEY_UP(c) ? VKEY_UP : VKEY_DOWN;
351 firm_gettime(fe);
352 sc->sc_events.ev_put = put;
353 EV_WAKEUP(&sc->sc_events);
355 return 0;
358 void
359 kbdsoftint(void *arg) /* what if ite is not configured? */
361 int s;
363 s = spltty();
365 while(kbdgetoff < kbdputoff)
366 ite_filter(kbdbuf[kbdgetoff++ & KBDBUFMASK]);
367 kbdgetoff = kbdputoff = 0;
369 splx(s);
372 void
373 kbd_bell(int mode)
375 #if NBELL > 0
376 if (mode)
377 opm_bell_on();
378 else
379 opm_bell_off();
380 #endif
383 unsigned char kbdled;
385 void
386 kbd_setLED(void)
388 mfp_send_usart(~kbdled | 0x80);
392 kbd_send_command(int cmd)
394 switch (cmd) {
395 case KBD_CMD_RESET:
396 /* XXX */
397 return 0;
399 case KBD_CMD_BELL:
400 kbd_bell(1);
401 return 0;
403 case KBD_CMD_NOBELL:
404 kbd_bell(0);
405 return 0;
407 default:
408 return ENOTTY;
413 * for console
415 #if NITE > 0
417 kbdcngetc(void)
419 int s;
420 u_char ints, c;
422 s = splhigh();
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();
429 mfp_set_iera(ints);
430 splx(s);
432 return c;
434 #endif