xref: /netbsd-src/sys/arch/x68k/dev/kbd.c (revision db6316d1518382eecd2fdbe55a1205e0620a1b35)
1 /*	$NetBSD: kbd.c,v 1.21 2004/12/13 02:14:13 chs 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.21 2004/12/13 02:14:13 chs 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 
51 #include <machine/cpu.h>
52 #include <machine/bus.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 	struct device	sc_dev;
67 
68 	int sc_event_mode;	/* if true, collect events, else pass to ite */
69 	struct evvar sc_events; /* event queue state */
70 };
71 
72 void	kbdenable	__P((int));
73 int	kbdintr 	__P((void *));
74 void	kbdsoftint	__P((void));
75 void	kbd_bell	__P((int));
76 int	kbdcngetc	__P((void));
77 void	kbd_setLED	__P((void));
78 int	kbd_send_command __P((int));
79 
80 
81 static int kbdmatch	__P((struct device *, struct cfdata *, void *));
82 static void kbdattach	__P((struct device *, struct device *, void *));
83 
84 CFATTACH_DECL(kbd, sizeof(struct kbd_softc),
85     kbdmatch, kbdattach, NULL, NULL);
86 
87 static int kbd_attached;
88 
89 dev_type_open(kbdopen);
90 dev_type_close(kbdclose);
91 dev_type_read(kbdread);
92 dev_type_ioctl(kbdioctl);
93 dev_type_poll(kbdpoll);
94 dev_type_kqfilter(kbdkqfilter);
95 
96 const struct cdevsw kbd_cdevsw = {
97 	kbdopen, kbdclose, kbdread, nowrite, kbdioctl,
98 	nostop, notty, kbdpoll, nommap, kbdkqfilter,
99 };
100 
101 static int
102 kbdmatch(parent, cf, aux)
103 	struct device *parent;
104 	struct cfdata *cf;
105 	void *aux;
106 {
107 	if (strcmp(aux, "kbd") != 0)
108 		return (0);
109 	if (kbd_attached)
110 		return (0);
111 
112 	return (1);
113 }
114 
115 static void
116 kbdattach(parent, self, aux)
117 	struct device *parent, *self;
118 	void *aux;
119 {
120 	struct kbd_softc *k = (void*) self;
121 	struct mfp_softc *mfp = (void*) parent;
122 	int s = spltty();
123 
124 	kbd_attached = 1;
125 
126 	/* MFP interrupt #12 is for USART receive buffer full */
127 	intio_intr_establish(mfp->sc_intr + 12, "kbd", kbdintr, self);
128 
129 	kbdenable(1);
130 	k->sc_event_mode = 0;
131 	k->sc_events.ev_io = 0;
132 	splx(s);
133 
134 	printf("\n");
135 }
136 
137 
138 /* definitions for x68k keyboard encoding. */
139 #define KEY_CODE(c)  ((c) & 0x7f)
140 #define KEY_UP(c)    ((c) & 0x80)
141 
142 void
143 kbdenable(mode)
144 	int mode;		/* 1: interrupt, 0: poll */
145 {
146 	intio_set_sysport_keyctrl(8);
147 	mfp_bit_clear_iera(MFP_INTR_RCV_FULL | MFP_INTR_TIMER_B);
148 	mfp_set_tbcr(MFP_TIMERB_RESET | MFP_TIMERB_STOP);
149 	mfp_set_tbdr(13);	/* Timer B interrupt interval */
150 	mfp_set_tbcr(1);	/* 1/4 delay mode */
151 	mfp_set_ucr(MFP_UCR_CLKX16 | MFP_UCR_RW_8 | MFP_UCR_ONESB);
152 	mfp_set_rsr(MFP_RSR_RE); /* USART receive enable */
153 	mfp_set_tsr(MFP_TSR_TE); /* USART transmit enable */
154 
155 	if (mode) {
156 		mfp_bit_set_iera(MFP_INTR_RCV_FULL);
157 		/*
158 		 * Perform null read in case that an input byte is in the
159 		 * receiver buffer, which prevents further interrupts.
160 		 * We could save the input, but probably not so valuable.
161 		 */
162 		(void) mfp_get_udr();
163 	}
164 
165 	kbdled = 0;		/* all keyboard LED turn off. */
166 	kbd_setLED();
167 
168 	if (!(intio_get_sysport_keyctrl() & 8))
169 		printf(" (no connected keyboard)");
170 }
171 
172 extern struct cfdriver kbd_cd;
173 
174 int
175 kbdopen(dev, flags, mode, p)
176 	dev_t dev;
177 	int flags, mode;
178 	struct proc *p;
179 {
180 	struct kbd_softc *k;
181 	int unit = minor(dev);
182 
183 	if (unit >= kbd_cd.cd_ndevs)
184 		return (ENXIO);
185 	k = kbd_cd.cd_devs[minor(dev)];
186 	if (k == NULL)
187 		return (ENXIO);
188 
189 	if (k->sc_events.ev_io)
190 		return (EBUSY);
191 	k->sc_events.ev_io = p;
192 	ev_init(&k->sc_events);
193 
194 	return (0);
195 }
196 
197 int
198 kbdclose(dev, flags, mode, p)
199 	dev_t dev;
200 	int flags, mode;
201 	struct proc *p;
202 {
203 	struct kbd_softc *k = kbd_cd.cd_devs[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, uio, flags)
216 	dev_t dev;
217 	struct uio *uio;
218 	int flags;
219 {
220 	struct kbd_softc *k = kbd_cd.cd_devs[minor(dev)];
221 
222 	return ev_read(&k->sc_events, uio, flags);
223 }
224 
225 #if NBELL > 0
226 struct bell_info;
227 int opm_bell_setup __P((struct bell_info *));
228 void opm_bell_on __P((void));
229 void opm_bell_off __P((void));
230 #endif
231 
232 int
233 kbdioctl(dev, cmd, data, flag, p)
234 	dev_t dev;
235 	u_long cmd;
236 	caddr_t data;
237 	int flag;
238 	struct proc *p;
239 {
240 	register struct kbd_softc *k = kbd_cd.cd_devs[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);	/* allways 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 int
310 kbdpoll(dev, events, p)
311 	dev_t dev;
312 	int events;
313 	struct proc *p;
314 {
315 	struct kbd_softc *k;
316 
317 	k = kbd_cd.cd_devs[minor(dev)];
318 	return (ev_poll(&k->sc_events, events, p));
319 }
320 
321 int
322 kbdkqfilter(dev_t dev, struct knote *kn)
323 {
324 	struct kbd_softc *k;
325 
326 	k = kbd_cd.cd_devs[minor(dev)];
327 	return (ev_kqfilter(&k->sc_events, kn));
328 }
329 
330 #define KBDBUFMASK 63
331 #define KBDBUFSIZ 64
332 static u_char kbdbuf[KBDBUFSIZ];
333 static int kbdputoff = 0;
334 static int kbdgetoff = 0;
335 
336 int
337 kbdintr(arg)
338 	void *arg;
339 {
340 	u_char c, st;
341 	struct kbd_softc *k = arg; /* XXX */
342 	struct firm_event *fe;
343 	int put;
344 
345 	/* clear receiver error if any */
346 	st = mfp_get_rsr();
347 
348 	c = mfp_get_udr();
349 
350 	if ((st & MFP_RSR_BF) == 0)
351 		return 0;	/* intr caused by an err -- no char received */
352 
353 	/* if not in event mode, deliver straight to ite to process key stroke */
354 	if (! k->sc_event_mode) {
355 		kbdbuf[kbdputoff++ & KBDBUFMASK] = c;
356 		setsoftkbd();
357 		return 0;
358 	}
359 
360 	/* Keyboard is generating events.  Turn this keystroke into an
361 	   event and put it in the queue.  If the queue is full, the
362 	   keystroke is lost (sorry!). */
363 
364 	put = k->sc_events.ev_put;
365 	fe = &k->sc_events.ev_q[put];
366 	put = (put + 1) % EV_QSIZE;
367 	if (put == k->sc_events.ev_get) {
368 		log(LOG_WARNING, "keyboard event queue overflow\n"); /* ??? */
369 		return 0;
370 	}
371 	fe->id = KEY_CODE(c);
372 	fe->value = KEY_UP(c) ? VKEY_UP : VKEY_DOWN;
373 	fe->time = time;
374 	k->sc_events.ev_put = put;
375 	EV_WAKEUP(&k->sc_events);
376 
377 	return 0;
378 }
379 
380 void
381 kbdsoftint()			/* what if ite is not configured? */
382 {
383 	int s = spltty();
384 
385 	while(kbdgetoff < kbdputoff)
386 		ite_filter(kbdbuf[kbdgetoff++ & KBDBUFMASK]);
387 	kbdgetoff = kbdputoff = 0;
388 
389 	splx(s);
390 }
391 
392 void
393 kbd_bell(mode)
394 	int mode;
395 {
396 #if NBELL > 0
397 	if (mode)
398 		opm_bell_on();
399 	else
400 		opm_bell_off();
401 #endif
402 }
403 
404 unsigned char kbdled;
405 void
406 kbd_setLED()
407 {
408         mfp_send_usart(~kbdled | 0x80);
409 }
410 
411 int
412 kbd_send_command(cmd)
413 	int cmd;
414 {
415 	switch (cmd) {
416 	case KBD_CMD_RESET:
417 		/* XXX */
418 		return 0;
419 
420 	case KBD_CMD_BELL:
421 		kbd_bell(1);
422 		return 0;
423 
424 	case KBD_CMD_NOBELL:
425 		kbd_bell(0);
426 		return 0;
427 
428 	default:
429 		return ENOTTY;
430 	}
431 }
432 
433 /*
434  * for console
435  */
436 #include "ite.h"
437 #if NITE > 0
438 int
439 kbdcngetc()
440 {
441 	int s;
442 	u_char ints, c;
443 
444 	s = splhigh();
445 	ints = mfp_get_iera();
446 
447 	mfp_bit_clear_iera(MFP_INTR_RCV_FULL);
448 	mfp_set_rsr(mfp_get_rsr() | MFP_RSR_RE);
449 	c = mfp_receive_usart();
450 
451 	mfp_set_iera(ints);
452 	splx(s);
453 
454 	return c;
455 }
456 #endif
457