xref: /netbsd/sys/arch/x68k/dev/kbd.c (revision bf9ec67e)
1 /*	$NetBSD: kbd.c,v 1.11 2001/06/12 15:17:21 wiz 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	kbdopen 	__P((dev_t, int, int, struct proc *));
75 int	kbdclose	__P((dev_t, int, int, struct proc *));
76 int	kbdread 	__P((dev_t, struct uio *, int));
77 int	kbdwrite	__P((dev_t, struct uio *, int));
78 int	kbdioctl	__P((dev_t, u_long, caddr_t, int, struct proc *));
79 int	kbdpoll 	__P((dev_t, int, struct proc *));
80 int	kbdintr 	__P((void *));
81 void	kbdsoftint	__P((void));
82 void	kbd_bell	__P((int));
83 int	kbdcngetc	__P((void));
84 void	kbd_setLED	__P((void));
85 int	kbd_send_command __P((int));
86 
87 
88 static int kbdmatch	__P((struct device *, struct cfdata *, void *));
89 static void kbdattach	__P((struct device *, struct device *, void *));
90 
91 struct cfattach kbd_ca = {
92 	sizeof(struct kbd_softc), kbdmatch, kbdattach
93 };
94 
95 
96 static int
97 kbdmatch(parent, cf, aux)
98 	struct device *parent;
99 	struct cfdata *cf;
100 	void *aux;
101 {
102 	if (strcmp(aux, "kbd") != 0)
103 		return (0);
104 	if (cf->cf_unit != 0)
105 		return (0);
106 
107 	return (1);
108 }
109 
110 static void
111 kbdattach(parent, self, aux)
112 	struct device *parent, *self;
113 	void *aux;
114 {
115 	struct kbd_softc *k = (void*) self;
116 	struct mfp_softc *mfp = (void*) parent;
117 	int s = spltty();
118 
119 	/* MFP interrupt #12 is for USART receive buffer full */
120 	intio_intr_establish(mfp->sc_intr + 12, "kbd", kbdintr, self);
121 
122 	kbdenable(1);
123 	k->sc_event_mode = 0;
124 	k->sc_events.ev_io = 0;
125 	splx(s);
126 
127 	printf("\n");
128 }
129 
130 
131 /* definitions for x68k keyboard encoding. */
132 #define KEY_CODE(c)  ((c) & 0x7f)
133 #define KEY_UP(c)    ((c) & 0x80)
134 
135 void
136 kbdenable(mode)
137 	int mode;		/* 1: interrupt, 0: poll */
138 {
139 	intio_set_sysport_keyctrl(8);
140 	mfp_bit_clear_iera(MFP_INTR_RCV_FULL | MFP_INTR_TIMER_B);
141 	mfp_set_tbcr(MFP_TIMERB_RESET | MFP_TIMERB_STOP);
142 	mfp_set_tbdr(13);	/* Timer B interrupt interval */
143 	mfp_set_tbcr(1);	/* 1/4 delay mode */
144 	mfp_set_ucr(MFP_UCR_CLKX16 | MFP_UCR_RW_8 | MFP_UCR_ONESB);
145 	mfp_set_rsr(MFP_RSR_RE); /* USART receive enable */
146 	mfp_set_tsr(MFP_TSR_TE); /* USART transmit enable */
147 
148 	if (mode) {
149 		mfp_bit_set_iera(MFP_INTR_RCV_FULL);
150 		/*
151 		 * Perform null read in case that an input byte is in the
152 		 * receiver buffer, which prevents further interrupts.
153 		 * We could save the input, but probably not so valuable.
154 		 */
155 		(void) mfp_get_udr();
156 	}
157 
158 	kbdled = 0;		/* all keyboard LED turn off. */
159 	kbd_setLED();
160 
161 	if (!(intio_get_sysport_keyctrl() & 8))
162 		printf(" (no connected keyboard)");
163 }
164 
165 extern struct cfdriver kbd_cd;
166 
167 int
168 kbdopen(dev, flags, mode, p)
169 	dev_t dev;
170 	int flags, mode;
171 	struct proc *p;
172 {
173 	struct kbd_softc *k;
174 	int unit = minor(dev);
175 
176 	if (unit >= kbd_cd.cd_ndevs)
177 		return (ENXIO);
178 	k = kbd_cd.cd_devs[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 = p;
185 	ev_init(&k->sc_events);
186 
187 	return (0);
188 }
189 
190 int
191 kbdclose(dev, flags, mode, p)
192 	dev_t dev;
193 	int flags, mode;
194 	struct proc *p;
195 {
196 	struct kbd_softc *k = kbd_cd.cd_devs[minor(dev)];
197 
198 	/* Turn off event mode, dump the queue */
199 	k->sc_event_mode = 0;
200 	ev_fini(&k->sc_events);
201 	k->sc_events.ev_io = NULL;
202 
203 	return (0);
204 }
205 
206 
207 int
208 kbdread(dev, uio, flags)
209 	dev_t dev;
210 	struct uio *uio;
211 	int flags;
212 {
213 	struct kbd_softc *k = kbd_cd.cd_devs[minor(dev)];
214 
215 	return ev_read(&k->sc_events, uio, flags);
216 }
217 
218 /* this routine should not exist, but is convenient to write here for now */
219 int
220 kbdwrite(dev, uio, flags)
221 	dev_t dev;
222 	struct uio *uio;
223 	int flags;
224 {
225 	return EOPNOTSUPP;
226 }
227 
228 #if NBELL > 0
229 struct bell_info;
230 int opm_bell_setup __P((struct bell_info *));
231 void opm_bell_on __P((void));
232 void opm_bell_off __P((void));
233 #endif
234 
235 int
236 kbdioctl(dev, cmd, data, flag, p)
237 	dev_t dev;
238 	u_long cmd;
239 	caddr_t data;
240 	int flag;
241 	struct proc *p;
242 {
243 	register struct kbd_softc *k = kbd_cd.cd_devs[minor(dev)];
244 	int cmd_data;
245 
246 	switch (cmd) {
247 	case KIOCTRANS:
248 		if (*(int *)data == TR_UNTRANS_EVENT)
249 			return (0);
250 		break;
251 
252 	case KIOCGTRANS:
253 		/*
254 		 * Get translation mode
255 		 */
256 		*(int *)data = TR_UNTRANS_EVENT;
257 		return (0);
258 
259 	case KIOCSDIRECT:
260 		k->sc_event_mode = *(int *)data;
261 		return (0);
262 
263 	case KIOCCMD:
264 		cmd_data = *(int *)data;
265 		return kbd_send_command(cmd_data);
266 
267 	case KIOCSLED:
268 		kbdled = *(char *)data;
269 		kbd_setLED();
270 		return (0);
271 
272 	case KIOCGLED:
273 		*(char *)data = kbdled;
274 		return (0);
275 
276 	case KIOCSBELL:
277 #if NBELL > 0
278 		return opm_bell_setup((struct bell_info *)data);
279 #else
280 		return (0);	/* allways success */
281 #endif
282 
283 	case FIONBIO:		/* we will remove this someday (soon???) */
284 		return (0);
285 
286 	case FIOASYNC:
287 		k->sc_events.ev_async = *(int *)data != 0;
288 		return (0);
289 
290 	case TIOCSPGRP:
291 		if (*(int *)data != k->sc_events.ev_io->p_pgid)
292 			return (EPERM);
293 		return (0);
294 
295 	default:
296 		return (ENOTTY);
297 	}
298 
299 	/*
300 	 * We identified the ioctl, but we do not handle it.
301 	 */
302 	return (EOPNOTSUPP);		/* misuse, but what the heck */
303 }
304 
305 
306 int
307 kbdpoll(dev, events, p)
308 	dev_t dev;
309 	int events;
310 	struct proc *p;
311 {
312 	struct kbd_softc *k;
313 
314 	k = kbd_cd.cd_devs[minor(dev)];
315 	return (ev_poll(&k->sc_events, events, p));
316 }
317 
318 
319 #define KBDBUFMASK 63
320 #define KBDBUFSIZ 64
321 static u_char kbdbuf[KBDBUFSIZ];
322 static int kbdputoff = 0;
323 static int kbdgetoff = 0;
324 
325 int
326 kbdintr(arg)
327 	void *arg;
328 {
329 	u_char c, st;
330 	struct kbd_softc *k = arg; /* XXX */
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 (! k->sc_event_mode) {
344 		kbdbuf[kbdputoff++ & KBDBUFMASK] = c;
345 		setsoftkbd();
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 = k->sc_events.ev_put;
354 	fe = &k->sc_events.ev_q[put];
355 	put = (put + 1) % EV_QSIZE;
356 	if (put == k->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 	fe->time = time;
363 	k->sc_events.ev_put = put;
364 	EV_WAKEUP(&k->sc_events);
365 
366 	return 0;
367 }
368 
369 void
370 kbdsoftint()			/* what if ite is not configured? */
371 {
372 	int s = spltty();
373 
374 	while(kbdgetoff < kbdputoff)
375 		ite_filter(kbdbuf[kbdgetoff++ & KBDBUFMASK]);
376 	kbdgetoff = kbdputoff = 0;
377 
378 	splx(s);
379 }
380 
381 void
382 kbd_bell(mode)
383 	int mode;
384 {
385 #if NBELL > 0
386 	if (mode)
387 		opm_bell_on();
388 	else
389 		opm_bell_off();
390 #endif
391 }
392 
393 unsigned char kbdled;
394 void
395 kbd_setLED()
396 {
397         mfp_send_usart(~kbdled | 0x80);
398 }
399 
400 int
401 kbd_send_command(cmd)
402 	int cmd;
403 {
404 	switch (cmd) {
405 	case KBD_CMD_RESET:
406 		/* XXX */
407 		return 0;
408 
409 	case KBD_CMD_BELL:
410 		kbd_bell(1);
411 		return 0;
412 
413 	case KBD_CMD_NOBELL:
414 		kbd_bell(0);
415 		return 0;
416 
417 	default:
418 		return ENOTTY;
419 	}
420 }
421 
422 /*
423  * for console
424  */
425 #include "ite.h"
426 #if NITE > 0
427 int
428 kbdcngetc()
429 {
430 	int s;
431 	u_char ints, c;
432 
433 	s = splhigh();
434 	ints = mfp_get_iera();
435 
436 	mfp_bit_clear_iera(MFP_INTR_RCV_FULL);
437 	mfp_set_rsr(mfp_get_rsr() | MFP_RSR_RE);
438 	c = mfp_receive_usart();
439 
440 	mfp_set_iera(ints);
441 	splx(s);
442 
443 	return c;
444 }
445 #endif
446