xref: /netbsd/sys/arch/pmax/tc/dtkbd.c (revision 6550d01e)
1 /*	$NetBSD: dtkbd.c,v 1.8 2008/04/28 20:23:31 martin Exp $	*/
2 
3 /*-
4  * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Andrew Doran.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: dtkbd.c,v 1.8 2008/04/28 20:23:31 martin Exp $");
34 
35 #include "locators.h"
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/device.h>
40 #include <sys/ioctl.h>
41 #include <sys/callout.h>
42 
43 #include <dev/wscons/wsconsio.h>
44 #include <dev/wscons/wskbdvar.h>
45 #include <dev/wscons/wsksymdef.h>
46 #include <dev/wscons/wsksymvar.h>
47 #include <dev/dec/wskbdmap_lk201.h>
48 #include <dev/tc/tcvar.h>
49 
50 #include <machine/bus.h>
51 
52 #include <pmax/tc/dtreg.h>
53 #include <pmax/tc/dtvar.h>
54 
55 #include <pmax/pmax/cons.h>
56 
57 struct dtkbd_softc {
58 	struct device	sc_dv;
59 	struct device	*sc_wskbddev;
60 	int		sc_enabled;
61 };
62 
63 int	dtkbd_match(struct device *, struct cfdata *, void *);
64 void	dtkbd_attach(struct device *, struct device *, void *);
65 int	dtkbd_enable(void *, int);
66 int	dtkbd_ioctl(void *, u_long, void *, int, struct lwp *);
67 void	dtkbd_cngetc(void *, u_int *, int *);
68 void	dtkbd_cnpollc(void *, int);
69 int	dtkbd_process_msg(struct dt_msg *, u_int *, int *);
70 void	dtkbd_handler(void *, struct dt_msg *);
71 void	dtkbd_set_leds(void *, int);
72 
73 const struct wskbd_accessops dtkbd_accessops = {
74 	dtkbd_enable,
75 	dtkbd_set_leds,
76 	dtkbd_ioctl,
77 };
78 
79 const struct wskbd_consops dtkbd_consops = {
80 	dtkbd_cngetc,
81 	dtkbd_cnpollc,
82 };
83 
84 CFATTACH_DECL(dtkbd, sizeof(struct dtkbd_softc),
85     dtkbd_match, dtkbd_attach, NULL, NULL);
86 
87 const struct wskbd_mapdata dtkbd_keymapdata = {
88 	lkkbd_keydesctab,
89 #ifdef DTKBD_LAYOUT
90 	DTKBD_LAYOUT,
91 #else
92 	KB_US | KB_LK401,
93 #endif
94 };
95 
96 int	dtkbd_isconsole;
97 uint8_t	dtkbd_map[10];
98 int	dtkbd_maplen;
99 
100 int
101 dtkbd_match(struct device *parent, struct cfdata *cf, void *aux)
102 {
103 	struct dt_attach_args *dta;
104 
105 	dta = aux;
106 	return (dta->dta_addr == DT_ADDR_KBD);
107 }
108 
109 void
110 dtkbd_attach(struct device *parent, struct device *self, void *aux)
111 {
112 	struct dt_softc *dt;
113 	struct dtkbd_softc *sc;
114 	struct wskbddev_attach_args a;
115 
116 	dt = (struct dt_softc *)parent;
117 	sc = (struct dtkbd_softc *)self;
118 
119 	printf("\n");
120 
121 	if (dt_establish_handler(dt, &dt_kbd_dv, self, dtkbd_handler)) {
122 		printf("%s: unable to establish handler\n", self->dv_xname);
123 		return;
124 	}
125 
126 	sc->sc_enabled = 1;
127 
128 	a.console = dtkbd_isconsole;
129 	a.keymap = &dtkbd_keymapdata;
130 	a.accessops = &dtkbd_accessops;
131 	a.accesscookie = sc;
132 	sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
133 }
134 
135 void
136 dtkbd_cnattach(void)
137 {
138 
139 	dtkbd_isconsole = 1;
140 	dt_cninit();
141 
142 	wskbd_cnattach(&dtkbd_consops, &dtkbd_map, &dtkbd_keymapdata);
143 }
144 
145 int
146 dtkbd_enable(void *v, int on)
147 {
148 	struct dtkbd_softc *sc;
149 
150 	sc = v;
151 	sc->sc_enabled = on;
152 
153 	return (0);
154 }
155 
156 void
157 dtkbd_cngetc(void *v, u_int *type, int *data)
158 {
159 	struct dt_msg msg;
160 	static u_int types[20];
161 	static int cnt, i, vals[20];
162 
163 	while (i >= cnt) {
164 		for (;;) {
165 			if (dt_msg_get(&msg, 0) == DT_GET_DONE)
166 				if (msg.src == dt_kbd_addr &&
167 				    !DT_CTL_P(msg.ctl))
168 					break;
169 			DELAY(1000);
170 		}
171 
172 		cnt = dtkbd_process_msg(&msg, types, vals);
173 		i = 0;
174 	}
175 
176 	*type = types[i++];
177 	*data = vals[i++];
178 }
179 
180 void
181 dtkbd_cnpollc(void *v, int on)
182 {
183 
184 	/* XXX */
185 }
186 
187 int
188 dtkbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
189 {
190 	struct dtkbd_softc *sc;
191 
192 	sc = (struct dtkbd_softc *)v;
193 
194 	switch (cmd) {
195 	case WSKBDIO_GTYPE:
196 		*(int *)data = WSKBD_TYPE_LK201;
197 		return 0;
198 	default:
199 		/* XXX */
200 		return (EPASSTHROUGH);
201 	}
202 }
203 
204 void
205 dtkbd_set_leds(void *v, int state)
206 {
207 
208 	/* XXX */
209 }
210 
211 void
212 dtkbd_handler(void *cookie, struct dt_msg *msg)
213 {
214 	struct dtkbd_softc *sc;
215 	u_int types[20];
216 	int i, cnt, vals[20];
217 
218 	sc = cookie;
219 
220 	if (!sc->sc_enabled)
221 		return;
222 
223 	cnt = dtkbd_process_msg(msg, types, vals);
224 	for (i = 0; i < cnt; i++)
225 		wskbd_input(sc->sc_wskbddev, types[i], vals[i]);
226 }
227 
228 int
229 dtkbd_process_msg(struct dt_msg *msg, u_int *types, int *vals)
230 {
231 	u_int len, c, count;
232 	int i, j;
233 
234 	len = DT_CTL_LEN(msg->ctl);
235 
236 	if ((msg->body[0] < DT_KBD_KEY_MIN && msg->body[0] != DT_KBD_EMPTY) ||
237 	    len > 10) {
238 		printf("dtkbd0: error: %x %x %x\n", len, msg->body[0],
239 		    msg->body[1]);
240 
241 		/*
242 		 * Fake an "all ups" to avoid the stuck key syndrome.
243 		 */
244 		msg->body[0] = DT_KBD_EMPTY;
245 		len = 1;
246 	}
247 
248 	if (msg->body[0] == DT_KBD_EMPTY) {
249 		types[0] = WSCONS_EVENT_ALL_KEYS_UP;
250 		vals[0] = 0;
251 		dtkbd_maplen = 0;
252 		return (1);
253 	}
254 
255 	count = 0;
256 
257 	for (i = 0; i < len; i++) {
258 		c = msg->body[i];
259 
260 		for (j = 0; j < dtkbd_maplen; j++)
261 			if (dtkbd_map[j] == c)
262 				break;
263 
264 		if (j == dtkbd_maplen) {
265 			types[count] = WSCONS_EVENT_KEY_DOWN;
266 			vals[count] = c - MIN_LK201_KEY;
267 			count++;
268 		}
269 	}
270 
271 	for (j = 0; j < dtkbd_maplen; j++) {
272 		c = dtkbd_map[j];
273 
274 		for (i = 0; i < len; i++)
275 			if (msg->body[i] == c)
276 				break;
277 
278 		if (i == len) {
279 			types[count] = WSCONS_EVENT_KEY_UP;
280 			vals[count] = c - MIN_LK201_KEY;
281 			count++;
282 		}
283 	}
284 
285 	memcpy(dtkbd_map, msg->body, len);
286 	dtkbd_maplen = len;
287 
288 	return (count);
289 }
290