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