xref: /netbsd-src/sys/arch/x68k/dev/kbd.c (revision d710132b4b8ce7f7cccaaf660cb16aa16b4077a0)
1 /*	$NetBSD: kbd.c,v 1.16 2002/10/23 09:12:45 jdolecek 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. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include "ite.h"
37 #include "bell.h"
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/device.h>
42 #include <sys/ioctl.h>
43 #include <sys/tty.h>
44 #include <sys/proc.h>
45 #include <sys/conf.h>
46 #include <sys/file.h>
47 #include <sys/uio.h>
48 #include <sys/kernel.h>
49 #include <sys/syslog.h>
50 #include <sys/signalvar.h>
51 
52 #include <machine/cpu.h>
53 #include <machine/bus.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 	struct device	sc_dev;
68 
69 	int sc_event_mode;	/* if true, collect events, else pass to ite */
70 	struct evvar sc_events; /* event queue state */
71 };
72 
73 void	kbdenable	__P((int));
74 int	kbdintr 	__P((void *));
75 void	kbdsoftint	__P((void));
76 void	kbd_bell	__P((int));
77 int	kbdcngetc	__P((void));
78 void	kbd_setLED	__P((void));
79 int	kbd_send_command __P((int));
80 
81 
82 static int kbdmatch	__P((struct device *, struct cfdata *, void *));
83 static void kbdattach	__P((struct device *, struct device *, void *));
84 
85 CFATTACH_DECL(kbd, sizeof(struct kbd_softc),
86     kbdmatch, kbdattach, NULL, NULL);
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(parent, cf, aux)
102 	struct device *parent;
103 	struct cfdata *cf;
104 	void *aux;
105 {
106 	if (strcmp(aux, "kbd") != 0)
107 		return (0);
108 	if (cf->cf_unit != 0)
109 		return (0);
110 
111 	return (1);
112 }
113 
114 static void
115 kbdattach(parent, self, aux)
116 	struct device *parent, *self;
117 	void *aux;
118 {
119 	struct kbd_softc *k = (void*) self;
120 	struct mfp_softc *mfp = (void*) parent;
121 	int s = spltty();
122 
123 	/* MFP interrupt #12 is for USART receive buffer full */
124 	intio_intr_establish(mfp->sc_intr + 12, "kbd", kbdintr, self);
125 
126 	kbdenable(1);
127 	k->sc_event_mode = 0;
128 	k->sc_events.ev_io = 0;
129 	splx(s);
130 
131 	printf("\n");
132 }
133 
134 
135 /* definitions for x68k keyboard encoding. */
136 #define KEY_CODE(c)  ((c) & 0x7f)
137 #define KEY_UP(c)    ((c) & 0x80)
138 
139 void
140 kbdenable(mode)
141 	int mode;		/* 1: interrupt, 0: poll */
142 {
143 	intio_set_sysport_keyctrl(8);
144 	mfp_bit_clear_iera(MFP_INTR_RCV_FULL | MFP_INTR_TIMER_B);
145 	mfp_set_tbcr(MFP_TIMERB_RESET | MFP_TIMERB_STOP);
146 	mfp_set_tbdr(13);	/* Timer B interrupt interval */
147 	mfp_set_tbcr(1);	/* 1/4 delay mode */
148 	mfp_set_ucr(MFP_UCR_CLKX16 | MFP_UCR_RW_8 | MFP_UCR_ONESB);
149 	mfp_set_rsr(MFP_RSR_RE); /* USART receive enable */
150 	mfp_set_tsr(MFP_TSR_TE); /* USART transmit enable */
151 
152 	if (mode) {
153 		mfp_bit_set_iera(MFP_INTR_RCV_FULL);
154 		/*
155 		 * Perform null read in case that an input byte is in the
156 		 * receiver buffer, which prevents further interrupts.
157 		 * We could save the input, but probably not so valuable.
158 		 */
159 		(void) mfp_get_udr();
160 	}
161 
162 	kbdled = 0;		/* all keyboard LED turn off. */
163 	kbd_setLED();
164 
165 	if (!(intio_get_sysport_keyctrl() & 8))
166 		printf(" (no connected keyboard)");
167 }
168 
169 extern struct cfdriver kbd_cd;
170 
171 int
172 kbdopen(dev, flags, mode, p)
173 	dev_t dev;
174 	int flags, mode;
175 	struct proc *p;
176 {
177 	struct kbd_softc *k;
178 	int unit = minor(dev);
179 
180 	if (unit >= kbd_cd.cd_ndevs)
181 		return (ENXIO);
182 	k = kbd_cd.cd_devs[minor(dev)];
183 	if (k == NULL)
184 		return (ENXIO);
185 
186 	if (k->sc_events.ev_io)
187 		return (EBUSY);
188 	k->sc_events.ev_io = p;
189 	ev_init(&k->sc_events);
190 
191 	return (0);
192 }
193 
194 int
195 kbdclose(dev, flags, mode, p)
196 	dev_t dev;
197 	int flags, mode;
198 	struct proc *p;
199 {
200 	struct kbd_softc *k = kbd_cd.cd_devs[minor(dev)];
201 
202 	/* Turn off event mode, dump the queue */
203 	k->sc_event_mode = 0;
204 	ev_fini(&k->sc_events);
205 	k->sc_events.ev_io = NULL;
206 
207 	return (0);
208 }
209 
210 
211 int
212 kbdread(dev, uio, flags)
213 	dev_t dev;
214 	struct uio *uio;
215 	int flags;
216 {
217 	struct kbd_softc *k = kbd_cd.cd_devs[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 __P((struct bell_info *));
225 void opm_bell_on __P((void));
226 void opm_bell_off __P((void));
227 #endif
228 
229 int
230 kbdioctl(dev, cmd, data, flag, p)
231 	dev_t dev;
232 	u_long cmd;
233 	caddr_t data;
234 	int flag;
235 	struct proc *p;
236 {
237 	register struct kbd_softc *k = kbd_cd.cd_devs[minor(dev)];
238 	int cmd_data;
239 
240 	switch (cmd) {
241 	case KIOCTRANS:
242 		if (*(int *)data == TR_UNTRANS_EVENT)
243 			return (0);
244 		break;
245 
246 	case KIOCGTRANS:
247 		/*
248 		 * Get translation mode
249 		 */
250 		*(int *)data = TR_UNTRANS_EVENT;
251 		return (0);
252 
253 	case KIOCSDIRECT:
254 		k->sc_event_mode = *(int *)data;
255 		return (0);
256 
257 	case KIOCCMD:
258 		cmd_data = *(int *)data;
259 		return kbd_send_command(cmd_data);
260 
261 	case KIOCSLED:
262 		kbdled = *(char *)data;
263 		kbd_setLED();
264 		return (0);
265 
266 	case KIOCGLED:
267 		*(char *)data = kbdled;
268 		return (0);
269 
270 	case KIOCSBELL:
271 #if NBELL > 0
272 		return opm_bell_setup((struct bell_info *)data);
273 #else
274 		return (0);	/* allways success */
275 #endif
276 
277 	case FIONBIO:		/* we will remove this someday (soon???) */
278 		return (0);
279 
280 	case FIOASYNC:
281 		k->sc_events.ev_async = *(int *)data != 0;
282 		return (0);
283 
284 	case TIOCSPGRP:
285 		if (*(int *)data != k->sc_events.ev_io->p_pgid)
286 			return (EPERM);
287 		return (0);
288 
289 	default:
290 		return (ENOTTY);
291 	}
292 
293 	/*
294 	 * We identified the ioctl, but we do not handle it.
295 	 */
296 	return (EOPNOTSUPP);		/* misuse, but what the heck */
297 }
298 
299 
300 int
301 kbdpoll(dev, events, p)
302 	dev_t dev;
303 	int events;
304 	struct proc *p;
305 {
306 	struct kbd_softc *k;
307 
308 	k = kbd_cd.cd_devs[minor(dev)];
309 	return (ev_poll(&k->sc_events, events, p));
310 }
311 
312 int
313 kbdkqfilter(dev_t dev, struct knote *kn)
314 {
315 	struct kbd_softc *k;
316 
317 	k = kbd_cd.cd_devs[minor(dev)];
318 	return (ev_kqfilter(&k->sc_events, kn));
319 }
320 
321 #define KBDBUFMASK 63
322 #define KBDBUFSIZ 64
323 static u_char kbdbuf[KBDBUFSIZ];
324 static int kbdputoff = 0;
325 static int kbdgetoff = 0;
326 
327 int
328 kbdintr(arg)
329 	void *arg;
330 {
331 	u_char c, st;
332 	struct kbd_softc *k = arg; /* XXX */
333 	struct firm_event *fe;
334 	int put;
335 
336 	/* clear receiver error if any */
337 	st = mfp_get_rsr();
338 
339 	c = mfp_get_udr();
340 
341 	if ((st & MFP_RSR_BF) == 0)
342 		return 0;	/* intr caused by an err -- no char received */
343 
344 	/* if not in event mode, deliver straight to ite to process key stroke */
345 	if (! k->sc_event_mode) {
346 		kbdbuf[kbdputoff++ & KBDBUFMASK] = c;
347 		setsoftkbd();
348 		return 0;
349 	}
350 
351 	/* Keyboard is generating events.  Turn this keystroke into an
352 	   event and put it in the queue.  If the queue is full, the
353 	   keystroke is lost (sorry!). */
354 
355 	put = k->sc_events.ev_put;
356 	fe = &k->sc_events.ev_q[put];
357 	put = (put + 1) % EV_QSIZE;
358 	if (put == k->sc_events.ev_get) {
359 		log(LOG_WARNING, "keyboard event queue overflow\n"); /* ??? */
360 		return 0;
361 	}
362 	fe->id = KEY_CODE(c);
363 	fe->value = KEY_UP(c) ? VKEY_UP : VKEY_DOWN;
364 	fe->time = time;
365 	k->sc_events.ev_put = put;
366 	EV_WAKEUP(&k->sc_events);
367 
368 	return 0;
369 }
370 
371 void
372 kbdsoftint()			/* what if ite is not configured? */
373 {
374 	int s = spltty();
375 
376 	while(kbdgetoff < kbdputoff)
377 		ite_filter(kbdbuf[kbdgetoff++ & KBDBUFMASK]);
378 	kbdgetoff = kbdputoff = 0;
379 
380 	splx(s);
381 }
382 
383 void
384 kbd_bell(mode)
385 	int mode;
386 {
387 #if NBELL > 0
388 	if (mode)
389 		opm_bell_on();
390 	else
391 		opm_bell_off();
392 #endif
393 }
394 
395 unsigned char kbdled;
396 void
397 kbd_setLED()
398 {
399         mfp_send_usart(~kbdled | 0x80);
400 }
401 
402 int
403 kbd_send_command(cmd)
404 	int cmd;
405 {
406 	switch (cmd) {
407 	case KBD_CMD_RESET:
408 		/* XXX */
409 		return 0;
410 
411 	case KBD_CMD_BELL:
412 		kbd_bell(1);
413 		return 0;
414 
415 	case KBD_CMD_NOBELL:
416 		kbd_bell(0);
417 		return 0;
418 
419 	default:
420 		return ENOTTY;
421 	}
422 }
423 
424 /*
425  * for console
426  */
427 #include "ite.h"
428 #if NITE > 0
429 int
430 kbdcngetc()
431 {
432 	int s;
433 	u_char ints, c;
434 
435 	s = splhigh();
436 	ints = mfp_get_iera();
437 
438 	mfp_bit_clear_iera(MFP_INTR_RCV_FULL);
439 	mfp_set_rsr(mfp_get_rsr() | MFP_RSR_RE);
440 	c = mfp_receive_usart();
441 
442 	mfp_set_iera(ints);
443 	splx(s);
444 
445 	return c;
446 }
447 #endif
448