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