xref: /netbsd-src/sys/arch/next68k/dev/nextkbd.c (revision bada23909e740596d0a3785a73bd3583a9807fb8)
1 /* $NetBSD: nextkbd.c,v 1.1 1999/01/28 11:46:23 dbj Exp $ */
2 /*
3  * Copyright (c) 1998 Matt DeBergalis
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Matt DeBergalis
17  * 4. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/proc.h>
38 #include <sys/device.h>
39 #include <sys/malloc.h>
40 #include <sys/errno.h>
41 #include <sys/queue.h>
42 #include <sys/lock.h>
43 
44 #include <machine/autoconf.h>
45 #include <machine/cpu.h>
46 #include <machine/intr.h>
47 #include <machine/bus.h>
48 
49 #include <next68k/dev/nextkbdvar.h>
50 #include <next68k/dev/wskbdmap_mfii.h>
51 
52 #include <dev/wscons/wsconsio.h>
53 #include <dev/wscons/wskbdvar.h>
54 #include <dev/wscons/wsksymdef.h>
55 #include <dev/wscons/wsksymvar.h>
56 
57 #include <next68k/next68k/isr.h>
58 
59 struct nextkbd_internal {
60 	int num_ints; /* interrupt total */
61 	int polling;
62 	int isconsole;
63 
64 	bus_space_tag_t iot;
65 	bus_space_handle_t ioh;
66 	struct nextkbd_softc *t_sc; /* back pointer */
67 	u_int32_t mods;
68 };
69 
70 struct mon_regs {
71 	u_int32_t mon_csr;
72 	u_int32_t mon_1;
73 	u_int32_t mon_data;
74 };
75 
76 int nextkbd_match __P((struct device *, struct cfdata *, void *));
77 void nextkbd_attach __P((struct device *, struct device *, void *));
78 
79 int nextkbc_cnattach __P((bus_space_tag_t));
80 
81 struct cfattach nextkbd_ca = {
82 	sizeof(struct nextkbd_softc), nextkbd_match, nextkbd_attach
83 };
84 
85 int	nextkbd_enable __P((void *, int));
86 void	nextkbd_set_leds __P((void *, int));
87 int	nextkbd_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
88 
89 const struct wskbd_accessops nextkbd_accessops = {
90 	nextkbd_enable,
91 	nextkbd_set_leds,
92 	nextkbd_ioctl,
93 };
94 
95 void	nextkbd_cngetc __P((void *, u_int *, int *));
96 void	nextkbd_cnpollc __P((void *, int));
97 
98 const struct wskbd_consops nextkbd_consops = {
99 	nextkbd_cngetc,
100 	nextkbd_cnpollc,
101 };
102 
103 const struct wskbd_mapdata nextkbd_keymapdata = {
104 	nextkbd_keydesctab,
105 	KB_US,
106 };
107 
108 static int nextkbd_poll_data __P((bus_space_tag_t, bus_space_handle_t));
109 static int nextkbd_decode __P((struct nextkbd_internal *, int, u_int *, int *));
110 
111 static struct nextkbd_internal nextkbd_consdata;
112 static int nextkbd_is_console __P((bus_space_tag_t bst));
113 
114 int nextkbdhard __P((void *));
115 
116 static int
117 nextkbd_is_console(bst)
118 	bus_space_tag_t bst;
119 {
120 	return (nextkbd_consdata.isconsole
121 			&& (bst == nextkbd_consdata.iot));
122 }
123 
124 int
125 nextkbd_match(parent, match, aux)
126 	struct device *parent;
127 	struct cfdata *match;
128 	void *aux;
129 {
130 	return 1;
131 }
132 
133 void
134 nextkbd_attach(parent, self, aux)
135 	struct device *parent, *self;
136 	void *aux;
137 {
138 	struct nextkbd_softc *sc = (struct nextkbd_softc *)self;
139 	int isconsole;
140 	struct wskbddev_attach_args a;
141 
142 	printf("\n");
143 
144 	isconsole = nextkbd_is_console(NEXT68K_INTIO_BUS_SPACE); /* XXX */
145 
146 	if (isconsole) {
147 		sc->id = &nextkbd_consdata;
148 	} else {
149 		sc->id = malloc(sizeof(struct nextkbd_internal),
150 				M_DEVBUF, M_WAITOK);
151 
152 		bzero(sc->id, sizeof(struct nextkbd_internal));
153 		sc->id->iot = NEXT68K_INTIO_BUS_SPACE;
154 		if (bus_space_map(sc->id->iot, NEXT_P_MON,
155 				sizeof(struct mon_regs),
156 				0, &sc->id->ioh)) {
157 			printf("%s: can't map mon status control register\n",
158 					sc->sc_dev.dv_xname);
159 			return;
160 		}
161 	}
162 
163 	sc->id->t_sc = sc; /* set back pointer */
164 
165 	isrlink_autovec(nextkbdhard, sc, NEXT_I_IPL(NEXT_I_KYBD_MOUSE), 0);
166 
167 	INTR_ENABLE(NEXT_I_KYBD_MOUSE);
168 
169 	a.console = isconsole;
170 	a.keymap = &nextkbd_keymapdata;
171 	a.accessops = &nextkbd_accessops;
172 	a.accesscookie = sc;
173 
174 	/*
175 	 * Attach the wskbd, saving a handle to it.
176 	 * XXX XXX XXX
177 	 */
178 	sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
179 }
180 
181 int
182 nextkbd_enable(v, on)
183 	void *v;
184 	int on;
185 {
186 	/* XXX not sure if this should do anything */
187 	printf("nextkbd_enable %d\n", on);
188 	return 0;
189 }
190 
191 /* XXX not yet implemented */
192 void
193 nextkbd_set_leds(v, leds)
194 	void *v;
195 	int leds;
196 {
197 	return;
198 }
199 
200 int
201 nextkbd_ioctl(v, cmd, data, flag, p)
202 	void *v;
203 	u_long cmd;
204 	caddr_t data;
205 	int flag;
206 	struct proc *p;
207 {
208 	/* XXX struct nextkbd_softc *nc = v; */
209 
210 	switch (cmd) {
211 	case WSKBDIO_GTYPE:
212 		/* XXX */
213 		*(int *)data = WSKBD_TYPE_PC_AT;
214 		return (0);
215 	case WSKBDIO_SETLEDS:
216 		return (0);
217 	case WSKBDIO_GETLEDS:
218 		*(int *)data = 0;
219 		return (0);
220 	case WSKBDIO_COMPLEXBELL:
221 		return (0);
222 	}
223 	return -1;
224 }
225 
226 int
227 nextkbdhard(arg)
228 	void *arg;
229 {
230 	register struct nextkbd_softc *sc = arg;
231 	struct mon_regs stat;
232 	unsigned char device;
233 	u_int32_t scan_code;
234 	int type, key;
235 
236 	if (!INTR_OCCURRED(NEXT_I_KYBD_MOUSE)) return 0;
237 
238 #define CSR_INT 0x00800000
239 #define CSR_DATA 0x00400000
240 
241 #define KD_KEYMASK			0x007f
242 #define KD_DIRECTION		0x0080 /* pressed or released */
243 #define KD_CNTL					0x0100
244 #define KD_LSHIFT				0x0200
245 #define KD_RSHIFT				0x0400
246 #define KD_LCOMM				0x0800
247 #define KD_RCOMM				0x1000
248 #define KD_LALT					0x2000
249 #define KD_RALT					0x4000
250 #define KD_VALID				0x8000 /* only set for scancode keys ? */
251 #define KD_MODS					0x4f00
252 
253 	bus_space_read_region_4(sc->id->iot, sc->id->ioh, 0, &stat, 3);
254 	if (stat.mon_csr & CSR_INT) {
255 		if (stat.mon_csr & CSR_DATA) {
256 			sc->id->num_ints++;
257 			stat.mon_csr &= ~CSR_INT;
258 			bus_space_write_4(sc->id->iot, sc->id->ioh, 0, stat.mon_csr);
259 			device = stat.mon_data >> 28;
260 			if (device != 1) return(0);
261 
262 			scan_code = stat.mon_data & 0xffff;
263 			if (nextkbd_decode(sc->id, scan_code, &type, &key)) {
264 				wskbd_input(sc->sc_wskbddev, type, key);
265 			}
266 		}
267 	}
268 
269 	return(1);
270 }
271 
272 int
273 nextkbd_cnattach(bst)
274 	bus_space_tag_t bst;
275 {
276 	bus_space_handle_t bsh;
277 
278 	if (bus_space_map(bst, NEXT_P_MON, sizeof(struct mon_regs),
279 			0, &bsh))
280 		return (ENXIO);
281 
282 	bzero(&nextkbd_consdata, sizeof(nextkbd_consdata));
283 
284 	nextkbd_consdata.iot = bst;
285 	nextkbd_consdata.ioh = bsh;
286 	nextkbd_consdata.isconsole = 1;
287 
288 	wskbd_cnattach(&nextkbd_consops, &nextkbd_consdata,
289 			&nextkbd_keymapdata);
290 
291 	return (0);
292 }
293 
294 /* ARGSUSED */
295 void
296 nextkbd_cngetc(v, type, data)
297 	void *v;
298 	u_int *type;
299 	int *data;
300 {
301 	struct nextkbd_internal *t = v;
302 	int val;
303 
304 	/* printf("cngetc: data at %08x (%08x)\n", t, v); */
305 	for (;;) {
306 		val = nextkbd_poll_data(t->iot, t->ioh);
307 		/* printf("%08x\n", val); */
308 		if ((val != -1) && nextkbd_decode(t, val, type, data))
309 			return;
310 	}
311 }
312 
313 void
314 nextkbd_cnpollc(v, on)
315 	void *v;
316 	int on;
317 {
318 	struct nextkbd_internal *t = v;
319 
320 	printf("cnpollc %d\n", on);
321 	t->polling = on;
322 	if (on) {
323 		INTR_DISABLE(NEXT_I_KYBD_MOUSE);
324 	} else {
325 		INTR_ENABLE(NEXT_I_KYBD_MOUSE);
326 	}
327 
328 }
329 
330 static int
331 nextkbd_poll_data(iot, ioh)
332 	bus_space_tag_t iot;
333 	bus_space_handle_t ioh;
334 {
335 	int i;
336 	struct mon_regs stat;
337 
338 	/* printf("cnstart\n"); */
339 	for (i=100000; i; i--) {
340 		bus_space_read_region_4(iot, ioh, 0, &stat, 3);
341 		if ( (stat.mon_csr & CSR_DATA) ) {
342 			stat.mon_csr &= ~CSR_INT;
343 			if ( (stat.mon_data >> 28) == 1) {
344 																/* printf("cnkey %08x %08x\n", stat.mon_csr, stat.mon_data); */
345 				bus_space_write_4(iot, ioh, 0, stat.mon_csr);
346 				return (stat.mon_data & 0xffff);
347 			}
348 		}
349 	}
350 	/* printf("cnend %08x %08x\n", stat.mon_csr, stat.mon_data); */
351 	return (-1);
352 }
353 
354 static int
355 nextkbd_decode(id, datain, type, dataout)
356 	struct nextkbd_internal *id;
357 	int datain;
358 	u_int *type;
359 	int *dataout;
360 {
361 	/* printf("datain %08x mods %08x\n", datain, id->mods); */
362 
363 	if ((datain ^ id->mods) & KD_LSHIFT) {
364 		id->mods ^= KD_LSHIFT;
365 		*dataout = 90;
366 		if (datain & KD_LSHIFT)
367 			*type = WSCONS_EVENT_KEY_DOWN;
368 		else
369 			*type = WSCONS_EVENT_KEY_UP;
370 	} else if ((datain ^ id->mods) & KD_RSHIFT) {
371 		id->mods ^= KD_RSHIFT;
372 		*dataout = 91;
373 		if (datain & KD_RSHIFT)
374 			*type = WSCONS_EVENT_KEY_DOWN;
375 		else
376 			*type = WSCONS_EVENT_KEY_UP;
377 	} else if ((datain ^ id->mods) & KD_LALT) {
378 		id->mods ^= KD_LALT;
379 		*dataout = 92;
380 		if (datain & KD_LALT)
381 			*type = WSCONS_EVENT_KEY_DOWN;
382 		else
383 			*type = WSCONS_EVENT_KEY_UP;
384 	} else if ((datain ^ id->mods) & KD_RALT) {
385 		id->mods ^= KD_RALT;
386 		*dataout = 93;
387 		if (datain & KD_RALT)
388 			*type = WSCONS_EVENT_KEY_DOWN;
389 		else
390 			*type = WSCONS_EVENT_KEY_UP;
391 	} else if ((datain ^ id->mods) & KD_CNTL) {
392 		id->mods ^= KD_CNTL;
393 		*dataout = 94;
394 		if (datain & KD_CNTL)
395 			*type = WSCONS_EVENT_KEY_DOWN;
396 		else
397 			*type = WSCONS_EVENT_KEY_UP;
398 	} else if ((datain ^ id->mods) & KD_LCOMM) {
399 		id->mods ^= KD_LCOMM;
400 		*dataout = 95;
401 		if (datain & KD_LCOMM)
402 			*type = WSCONS_EVENT_KEY_DOWN;
403 		else
404 			*type = WSCONS_EVENT_KEY_UP;
405 	} else if ((datain ^ id->mods) & KD_RCOMM) {
406 		id->mods ^= KD_RCOMM;
407 		*dataout = 96;
408 		if (datain & KD_RCOMM)
409 			*type = WSCONS_EVENT_KEY_DOWN;
410 		else
411 			*type = WSCONS_EVENT_KEY_UP;
412 	} else if (datain & KD_KEYMASK) {
413 		if (datain & KD_DIRECTION)
414 			*type = WSCONS_EVENT_KEY_UP;
415 		else
416 			*type = WSCONS_EVENT_KEY_DOWN;
417 
418 		*dataout = (datain & KD_KEYMASK);
419 	} else {
420 		*dataout = 0;
421 	}
422 
423 	return 1;
424 }
425