xref: /netbsd/sys/arch/x68k/dev/kbd.c (revision 6550d01e)
1 /*	$NetBSD: kbd.c,v 1.36 2009/01/17 03:26:31 isaki 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.36 2009/01/17 03:26:31 isaki 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 	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;
69 };
70 
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);
78 
79 
80 static int kbdmatch(device_t, cfdata_t, void *);
81 static void kbdattach(device_t, device_t, void *);
82 
83 CFATTACH_DECL_NEW(kbd, sizeof(struct kbd_softc),
84     kbdmatch, kbdattach, NULL, NULL);
85 
86 static int kbd_attached;
87 
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);
94 
95 const struct cdevsw kbd_cdevsw = {
96 	kbdopen, kbdclose, kbdread, nowrite, kbdioctl,
97 	nostop, notty, kbdpoll, nommap, kbdkqfilter,
98 };
99 
100 static int
101 kbdmatch(device_t parent, cfdata_t cf, void *aux)
102 {
103 
104 	if (strcmp(aux, "kbd") != 0)
105 		return (0);
106 	if (kbd_attached)
107 		return (0);
108 
109 	return (1);
110 }
111 
112 static void
113 kbdattach(device_t parent, device_t self, void *aux)
114 {
115 	struct kbd_softc *sc = device_private(self);
116 	struct mfp_softc *mfp = device_private(parent);
117 	int s;
118 
119 	kbd_attached = 1;
120 
121 	s = spltty();
122 
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);
127 
128 	kbdenable(1);
129 	sc->sc_event_mode = 0;
130 	sc->sc_events.ev_io = 0;
131 	splx(s);
132 
133 	aprint_normal("\n");
134 }
135 
136 
137 /* definitions for x68k keyboard encoding. */
138 #define KEY_CODE(c)  ((c) & 0x7f)
139 #define KEY_UP(c)    ((c) & 0x80)
140 
141 void
142 kbdenable(int mode)	/* 1: interrupt, 0: poll */
143 {
144 
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 */
153 
154 	if (mode) {
155 		mfp_bit_set_iera(MFP_INTR_RCV_FULL);
156 		/*
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.
160 		 */
161 		(void) mfp_get_udr();
162 	}
163 
164 	kbdled = 0;		/* all keyboard LED turn off. */
165 	kbd_setLED();
166 
167 	if (!(intio_get_sysport_keyctrl() & 8))
168 		aprint_normal(" (no connected keyboard)");
169 }
170 
171 extern struct cfdriver kbd_cd;
172 
173 int
174 kbdopen(dev_t dev, int flags, int mode, struct lwp *l)
175 {
176 	struct kbd_softc *k;
177 
178 	k = device_lookup_private(&kbd_cd, minor(dev));
179 	if (k == NULL)
180 		return (ENXIO);
181 
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);
186 
187 	return (0);
188 }
189 
190 int
191 kbdclose(dev_t dev, int flags, int mode, struct lwp *l)
192 {
193 	struct kbd_softc *k = device_lookup_private(&kbd_cd, minor(dev));
194 
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;
199 
200 	return (0);
201 }
202 
203 
204 int
205 kbdread(dev_t dev, struct uio *uio, int flags)
206 {
207 	struct kbd_softc *k = device_lookup_private(&kbd_cd, minor(dev));
208 
209 	return ev_read(&k->sc_events, uio, flags);
210 }
211 
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
218 
219 int
220 kbdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
221 {
222 	struct kbd_softc *k = device_lookup_private(&kbd_cd, minor(dev));
223 	int cmd_data;
224 
225 	switch (cmd) {
226 	case KIOCTRANS:
227 		if (*(int *)data == TR_UNTRANS_EVENT)
228 			return (0);
229 		break;
230 
231 	case KIOCGTRANS:
232 		/*
233 		 * Get translation mode
234 		 */
235 		*(int *)data = TR_UNTRANS_EVENT;
236 		return (0);
237 
238 	case KIOCSDIRECT:
239 		k->sc_event_mode = *(int *)data;
240 		return (0);
241 
242 	case KIOCCMD:
243 		cmd_data = *(int *)data;
244 		return kbd_send_command(cmd_data);
245 
246 	case KIOCSLED:
247 		kbdled = *(char *)data;
248 		kbd_setLED();
249 		return (0);
250 
251 	case KIOCGLED:
252 		*(char *)data = kbdled;
253 		return (0);
254 
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
261 
262 	case FIONBIO:		/* we will remove this someday (soon???) */
263 		return (0);
264 
265 	case FIOASYNC:
266 		k->sc_events.ev_async = *(int *)data != 0;
267 		return (0);
268 
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;
274 
275 	case TIOCSPGRP:
276 		if (*(int *)data != k->sc_events.ev_io->p_pgid)
277 			return (EPERM);
278 		return (0);
279 
280 	default:
281 		return (ENOTTY);
282 	}
283 
284 	/*
285 	 * We identified the ioctl, but we do not handle it.
286 	 */
287 	return (EOPNOTSUPP);		/* misuse, but what the heck */
288 }
289 
290 
291 int
292 kbdpoll(dev_t dev, int events, struct lwp *l)
293 {
294 	struct kbd_softc *k;
295 
296 	k = device_lookup_private(&kbd_cd, minor(dev));
297 	return (ev_poll(&k->sc_events, events, l));
298 }
299 
300 int
301 kbdkqfilter(dev_t dev, struct knote *kn)
302 {
303 	struct kbd_softc *k;
304 
305 	k = device_lookup_private(&kbd_cd, minor(dev));
306 	return (ev_kqfilter(&k->sc_events, kn));
307 }
308 
309 #define KBDBUFMASK 63
310 #define KBDBUFSIZ 64
311 static u_char kbdbuf[KBDBUFSIZ];
312 static int kbdputoff = 0;
313 static int kbdgetoff = 0;
314 
315 int
316 kbdintr(void *arg)
317 {
318 	u_char c, st;
319 	struct kbd_softc *sc = arg;
320 	struct firm_event *fe;
321 	int put;
322 
323 	/* clear receiver error if any */
324 	st = mfp_get_rsr();
325 
326 	c = mfp_get_udr();
327 
328 	if ((st & MFP_RSR_BF) == 0)
329 		return 0;	/* intr caused by an err -- no char received */
330 
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;
336 	}
337 
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!). */
341 
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;
348 	}
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);
354 
355 	return 0;
356 }
357 
358 void
359 kbdsoftint(void *arg)			/* what if ite is not configured? */
360 {
361 	int s;
362 
363 	s = spltty();
364 
365 	while(kbdgetoff < kbdputoff)
366 		ite_filter(kbdbuf[kbdgetoff++ & KBDBUFMASK]);
367 	kbdgetoff = kbdputoff = 0;
368 
369 	splx(s);
370 }
371 
372 void
373 kbd_bell(int mode)
374 {
375 #if NBELL > 0
376 	if (mode)
377 		opm_bell_on();
378 	else
379 		opm_bell_off();
380 #endif
381 }
382 
383 unsigned char kbdled;
384 
385 void
386 kbd_setLED(void)
387 {
388 	mfp_send_usart(~kbdled | 0x80);
389 }
390 
391 int
392 kbd_send_command(int cmd)
393 {
394 	switch (cmd) {
395 	case KBD_CMD_RESET:
396 		/* XXX */
397 		return 0;
398 
399 	case KBD_CMD_BELL:
400 		kbd_bell(1);
401 		return 0;
402 
403 	case KBD_CMD_NOBELL:
404 		kbd_bell(0);
405 		return 0;
406 
407 	default:
408 		return ENOTTY;
409 	}
410 }
411 
412 /*
413  * for console
414  */
415 #if NITE > 0
416 int
417 kbdcngetc(void)
418 {
419 	int s;
420 	u_char ints, c;
421 
422 	s = splhigh();
423 	ints = mfp_get_iera();
424 
425 	mfp_bit_clear_iera(MFP_INTR_RCV_FULL);
426 	mfp_set_rsr(mfp_get_rsr() | MFP_RSR_RE);
427 	c = mfp_receive_usart();
428 
429 	mfp_set_iera(ints);
430 	splx(s);
431 
432 	return c;
433 }
434 #endif
435