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