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