xref: /netbsd-src/sys/arch/x68k/dev/kbd.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: kbd.c,v 1.33 2007/12/03 15:34:25 ad 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. 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.
18  *
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.
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: kbd.c,v 1.33 2007/12/03 15:34:25 ad Exp $");
34 
35 #include "ite.h"
36 #include "bell.h"
37 
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>
53 
54 #include <arch/x68k/dev/intiovar.h>
55 #include <arch/x68k/dev/mfp.h>
56 #include <arch/x68k/dev/itevar.h>
57 
58 /* for sun-like event mode, if you go thru /dev/kbd. */
59 #include <arch/x68k/dev/event_var.h>
60 
61 #include <machine/kbio.h>
62 #include <machine/kbd.h>
63 #include <machine/vuid_event.h>
64 
65 struct kbd_softc {
66 	struct device	sc_dev;
67 
68 	int sc_event_mode;	/* if true, collect events, else pass to ite */
69 	struct evvar sc_events; /* event queue state */
70 	void *sc_softintr_cookie;
71 };
72 
73 void	kbdenable(int);
74 int	kbdintr(void *);
75 void	kbdsoftint(void *);
76 void	kbd_bell(int);
77 int	kbdcngetc(void);
78 void	kbd_setLED(void);
79 int	kbd_send_command(int);
80 
81 
82 static int kbdmatch(struct device *, struct cfdata *, void *);
83 static void kbdattach(struct device *, struct device *, void *);
84 
85 CFATTACH_DECL(kbd, sizeof(struct kbd_softc),
86     kbdmatch, kbdattach, NULL, NULL);
87 
88 static int kbd_attached;
89 
90 dev_type_open(kbdopen);
91 dev_type_close(kbdclose);
92 dev_type_read(kbdread);
93 dev_type_ioctl(kbdioctl);
94 dev_type_poll(kbdpoll);
95 dev_type_kqfilter(kbdkqfilter);
96 
97 const struct cdevsw kbd_cdevsw = {
98 	kbdopen, kbdclose, kbdread, nowrite, kbdioctl,
99 	nostop, notty, kbdpoll, nommap, kbdkqfilter,
100 };
101 
102 static int
103 kbdmatch(struct device *parent, struct cfdata *cf, void *aux)
104 {
105 
106 	if (strcmp(aux, "kbd") != 0)
107 		return (0);
108 	if (kbd_attached)
109 		return (0);
110 
111 	return (1);
112 }
113 
114 static void
115 kbdattach(struct device *parent, struct device *self, void *aux)
116 {
117 	struct kbd_softc *sc = (void *)self;
118 	struct mfp_softc *mfp = (void *)parent;
119 	int s;
120 
121 	kbd_attached = 1;
122 
123 	s = spltty();
124 
125 	/* MFP interrupt #12 is for USART receive buffer full */
126 	intio_intr_establish(mfp->sc_intr + 12, "kbd", kbdintr, sc);
127 	sc->sc_softintr_cookie = softint_establish(SOFTINT_SERIAL,
128 	    kbdsoftint, sc);
129 
130 	kbdenable(1);
131 	sc->sc_event_mode = 0;
132 	sc->sc_events.ev_io = 0;
133 	splx(s);
134 
135 	printf("\n");
136 }
137 
138 
139 /* definitions for x68k keyboard encoding. */
140 #define KEY_CODE(c)  ((c) & 0x7f)
141 #define KEY_UP(c)    ((c) & 0x80)
142 
143 void
144 kbdenable(int mode)	/* 1: interrupt, 0: poll */
145 {
146 
147 	intio_set_sysport_keyctrl(8);
148 	mfp_bit_clear_iera(MFP_INTR_RCV_FULL | MFP_INTR_TIMER_B);
149 	mfp_set_tbcr(MFP_TIMERB_RESET | MFP_TIMERB_STOP);
150 	mfp_set_tbdr(13);	/* Timer B interrupt interval */
151 	mfp_set_tbcr(1);	/* 1/4 delay mode */
152 	mfp_set_ucr(MFP_UCR_CLKX16 | MFP_UCR_RW_8 | MFP_UCR_ONESB);
153 	mfp_set_rsr(MFP_RSR_RE); /* USART receive enable */
154 	mfp_set_tsr(MFP_TSR_TE); /* USART transmit enable */
155 
156 	if (mode) {
157 		mfp_bit_set_iera(MFP_INTR_RCV_FULL);
158 		/*
159 		 * Perform null read in case that an input byte is in the
160 		 * receiver buffer, which prevents further interrupts.
161 		 * We could save the input, but probably not so valuable.
162 		 */
163 		(void) mfp_get_udr();
164 	}
165 
166 	kbdled = 0;		/* all keyboard LED turn off. */
167 	kbd_setLED();
168 
169 	if (!(intio_get_sysport_keyctrl() & 8))
170 		printf(" (no connected keyboard)");
171 }
172 
173 extern struct cfdriver kbd_cd;
174 
175 int
176 kbdopen(dev_t dev, int flags, int mode, struct lwp *l)
177 {
178 	struct kbd_softc *k;
179 	int unit = minor(dev);
180 
181 	if (unit >= kbd_cd.cd_ndevs)
182 		return (ENXIO);
183 	k = kbd_cd.cd_devs[minor(dev)];
184 	if (k == NULL)
185 		return (ENXIO);
186 
187 	if (k->sc_events.ev_io)
188 		return (EBUSY);
189 	k->sc_events.ev_io = l->l_proc;
190 	ev_init(&k->sc_events);
191 
192 	return (0);
193 }
194 
195 int
196 kbdclose(dev_t dev, int flags, int mode, struct lwp *l)
197 {
198 	struct kbd_softc *k = kbd_cd.cd_devs[minor(dev)];
199 
200 	/* Turn off event mode, dump the queue */
201 	k->sc_event_mode = 0;
202 	ev_fini(&k->sc_events);
203 	k->sc_events.ev_io = NULL;
204 
205 	return (0);
206 }
207 
208 
209 int
210 kbdread(dev_t dev, struct uio *uio, int flags)
211 {
212 	struct kbd_softc *k = kbd_cd.cd_devs[minor(dev)];
213 
214 	return ev_read(&k->sc_events, uio, flags);
215 }
216 
217 #if NBELL > 0
218 struct bell_info;
219 int opm_bell_setup(struct bell_info *);
220 void opm_bell_on(void);
221 void opm_bell_off(void);
222 #endif
223 
224 int
225 kbdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
226 {
227 	struct kbd_softc *k = kbd_cd.cd_devs[minor(dev)];
228 	int cmd_data;
229 
230 	switch (cmd) {
231 	case KIOCTRANS:
232 		if (*(int *)data == TR_UNTRANS_EVENT)
233 			return (0);
234 		break;
235 
236 	case KIOCGTRANS:
237 		/*
238 		 * Get translation mode
239 		 */
240 		*(int *)data = TR_UNTRANS_EVENT;
241 		return (0);
242 
243 	case KIOCSDIRECT:
244 		k->sc_event_mode = *(int *)data;
245 		return (0);
246 
247 	case KIOCCMD:
248 		cmd_data = *(int *)data;
249 		return kbd_send_command(cmd_data);
250 
251 	case KIOCSLED:
252 		kbdled = *(char *)data;
253 		kbd_setLED();
254 		return (0);
255 
256 	case KIOCGLED:
257 		*(char *)data = kbdled;
258 		return (0);
259 
260 	case KIOCSBELL:
261 #if NBELL > 0
262 		return opm_bell_setup((struct bell_info *)data);
263 #else
264 		return (0);	/* always success */
265 #endif
266 
267 	case FIONBIO:		/* we will remove this someday (soon???) */
268 		return (0);
269 
270 	case FIOASYNC:
271 		k->sc_events.ev_async = *(int *)data != 0;
272 		return (0);
273 
274 	case FIOSETOWN:
275 		if (-*(int *)data != k->sc_events.ev_io->p_pgid
276 		    && *(int *)data != k->sc_events.ev_io->p_pid)
277 			return (EPERM);
278 		return 0;
279 
280 	case TIOCSPGRP:
281 		if (*(int *)data != k->sc_events.ev_io->p_pgid)
282 			return (EPERM);
283 		return (0);
284 
285 	default:
286 		return (ENOTTY);
287 	}
288 
289 	/*
290 	 * We identified the ioctl, but we do not handle it.
291 	 */
292 	return (EOPNOTSUPP);		/* misuse, but what the heck */
293 }
294 
295 
296 int
297 kbdpoll(dev_t dev, int events, struct lwp *l)
298 {
299 	struct kbd_softc *k;
300 
301 	k = kbd_cd.cd_devs[minor(dev)];
302 	return (ev_poll(&k->sc_events, events, l));
303 }
304 
305 int
306 kbdkqfilter(dev_t dev, struct knote *kn)
307 {
308 	struct kbd_softc *k;
309 
310 	k = kbd_cd.cd_devs[minor(dev)];
311 	return (ev_kqfilter(&k->sc_events, kn));
312 }
313 
314 #define KBDBUFMASK 63
315 #define KBDBUFSIZ 64
316 static u_char kbdbuf[KBDBUFSIZ];
317 static int kbdputoff = 0;
318 static int kbdgetoff = 0;
319 
320 int
321 kbdintr(void *arg)
322 {
323 	u_char c, st;
324 	struct kbd_softc *sc = arg;
325 	struct firm_event *fe;
326 	int put;
327 
328 	/* clear receiver error if any */
329 	st = mfp_get_rsr();
330 
331 	c = mfp_get_udr();
332 
333 	if ((st & MFP_RSR_BF) == 0)
334 		return 0;	/* intr caused by an err -- no char received */
335 
336 	/* if not in event mode, deliver straight to ite to process key stroke */
337 	if (!sc->sc_event_mode) {
338 		kbdbuf[kbdputoff++ & KBDBUFMASK] = c;
339 		softint_schedule(sc->sc_softintr_cookie);
340 		return 0;
341 	}
342 
343 	/* Keyboard is generating events.  Turn this keystroke into an
344 	   event and put it in the queue.  If the queue is full, the
345 	   keystroke is lost (sorry!). */
346 
347 	put = sc->sc_events.ev_put;
348 	fe = &sc->sc_events.ev_q[put];
349 	put = (put + 1) % EV_QSIZE;
350 	if (put == sc->sc_events.ev_get) {
351 		log(LOG_WARNING, "keyboard event queue overflow\n"); /* ??? */
352 		return 0;
353 	}
354 	fe->id = KEY_CODE(c);
355 	fe->value = KEY_UP(c) ? VKEY_UP : VKEY_DOWN;
356 	getmicrotime(&fe->time);
357 	sc->sc_events.ev_put = put;
358 	EV_WAKEUP(&sc->sc_events);
359 
360 	return 0;
361 }
362 
363 void
364 kbdsoftint(void *arg)			/* what if ite is not configured? */
365 {
366 	int s;
367 
368 	s = spltty();
369 
370 	while(kbdgetoff < kbdputoff)
371 		ite_filter(kbdbuf[kbdgetoff++ & KBDBUFMASK]);
372 	kbdgetoff = kbdputoff = 0;
373 
374 	splx(s);
375 }
376 
377 void
378 kbd_bell(int mode)
379 {
380 #if NBELL > 0
381 	if (mode)
382 		opm_bell_on();
383 	else
384 		opm_bell_off();
385 #endif
386 }
387 
388 unsigned char kbdled;
389 
390 void
391 kbd_setLED(void)
392 {
393 	mfp_send_usart(~kbdled | 0x80);
394 }
395 
396 int
397 kbd_send_command(int cmd)
398 {
399 	switch (cmd) {
400 	case KBD_CMD_RESET:
401 		/* XXX */
402 		return 0;
403 
404 	case KBD_CMD_BELL:
405 		kbd_bell(1);
406 		return 0;
407 
408 	case KBD_CMD_NOBELL:
409 		kbd_bell(0);
410 		return 0;
411 
412 	default:
413 		return ENOTTY;
414 	}
415 }
416 
417 /*
418  * for console
419  */
420 #if NITE > 0
421 int
422 kbdcngetc(void)
423 {
424 	int s;
425 	u_char ints, c;
426 
427 	s = splhigh();
428 	ints = mfp_get_iera();
429 
430 	mfp_bit_clear_iera(MFP_INTR_RCV_FULL);
431 	mfp_set_rsr(mfp_get_rsr() | MFP_RSR_RE);
432 	c = mfp_receive_usart();
433 
434 	mfp_set_iera(ints);
435 	splx(s);
436 
437 	return c;
438 }
439 #endif
440