dtkbd.c revision 1.2
1/*	$NetBSD: dtkbd.c,v 1.2 2003/12/13 23:04:38 ad 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 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *        This product includes software developed by the NetBSD
21 *        Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 *    contributors may be used to endorse or promote products derived
24 *    from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39#include <sys/cdefs.h>
40__KERNEL_RCSID(0, "$NetBSD: dtkbd.c,v 1.2 2003/12/13 23:04:38 ad Exp $");
41
42#include "locators.h"
43
44#include <sys/param.h>
45#include <sys/systm.h>
46#include <sys/device.h>
47#include <sys/ioctl.h>
48#include <sys/callout.h>
49
50#include <dev/wscons/wsconsio.h>
51#include <dev/wscons/wskbdvar.h>
52#include <dev/wscons/wsksymdef.h>
53#include <dev/wscons/wsksymvar.h>
54#include <dev/dec/wskbdmap_lk201.h>
55#include <dev/tc/tcvar.h>
56
57#include <machine/bus.h>
58
59#include <pmax/tc/dtreg.h>
60#include <pmax/tc/dtvar.h>
61
62#include <pmax/pmax/cons.h>
63
64struct dtkbd_softc {
65	struct device	sc_dv;
66	struct device	*sc_wskbddev;
67	int		sc_enabled;
68};
69
70int	dtkbd_match(struct device *, struct cfdata *, void *);
71void	dtkbd_attach(struct device *, struct device *, void *);
72int	dtkbd_enable(void *, int);
73int	dtkbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
74void	dtkbd_cngetc(void *, u_int *, int *);
75void	dtkbd_cnpollc(void *, int);
76int	dtkbd_process_msg(struct dt_msg *, u_int *, int *);
77void	dtkbd_handler(void *);
78void	dtkbd_set_leds(void *, int);
79
80const struct wskbd_accessops dtkbd_accessops = {
81	dtkbd_enable,
82	dtkbd_set_leds,
83	dtkbd_ioctl,
84};
85
86const struct wskbd_consops dtkbd_consops = {
87	dtkbd_cngetc,
88	dtkbd_cnpollc,
89};
90
91CFATTACH_DECL(dtkbd, sizeof(struct dtkbd_softc),
92    dtkbd_match, dtkbd_attach, NULL, NULL);
93
94const struct wskbd_mapdata dtkbd_keymapdata = {
95	lkkbd_keydesctab,
96#ifdef DTKBD_LAYOUT
97	DTKBD_LAYOUT,
98#else
99	KB_US | KB_LK401,
100#endif
101};
102
103int	dtkbd_isconsole;
104int	dtkbd_map[10];
105int	dtkbd_maplen;
106
107int
108dtkbd_match(struct device *parent, struct cfdata *cf, void *aux)
109{
110	struct dt_attach_args *dta;
111	struct dt_ident ident;
112
113	dta = aux;
114
115	/*
116	 * Allow hard-wiring of addresses.
117	 */
118	if (cf->cf_loc[DTCF_ADDR] == dta->dta_addr)
119		return (2);
120
121	/*
122	 * The keyboard and mouse addresses are often swapped.  So, we
123	 * accept the standard address for either, and ask the device to
124	 * identify itself.
125	 */
126	if (cf->cf_loc[DTCF_ADDR] == DTCF_ADDR_DEFAULT &&
127	    (dta->dta_addr == DT_ADDR_KBD || dta->dta_addr == DT_ADDR_MOUSE)) {
128		if (dt_identify(dta->dta_addr, &ident))
129			return (dta->dta_addr == DT_ADDR_KBD);
130		return (strncmp(ident.vendor, "DEC     ", 8) == 0 &&
131		    strncmp(ident.module, "LK501-", 6) == 0);
132	}
133
134	return (0);
135}
136
137void
138dtkbd_attach(struct device *parent, struct device *self, void *aux)
139{
140	struct dt_softc *dt;
141	struct dtkbd_softc *sc;
142	struct dt_attach_args *dta;
143	struct wskbddev_attach_args a;
144
145	dt = (struct dt_softc *)parent;
146	sc = (struct dtkbd_softc *)self;
147	dta = aux;
148
149	printf("\n");
150
151	if (dt_establish_handler(dt, dta->dta_addr, self, dtkbd_handler)) {
152		printf("%s: unable to establish handler\n", self->dv_xname);
153		return;
154	}
155
156	sc->sc_enabled = 1;
157	dt_kbd_addr = dta->dta_addr;
158
159	a.console = dtkbd_isconsole;
160	a.keymap = &dtkbd_keymapdata;
161	a.accessops = &dtkbd_accessops;
162	a.accesscookie = sc;
163	sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
164}
165
166void
167dtkbd_cnattach(void)
168{
169
170	dtkbd_isconsole = 1;
171	dt_cninit();
172
173	wskbd_cnattach(&dtkbd_consops, &dtkbd_map, &dtkbd_keymapdata);
174}
175
176int
177dtkbd_enable(void *v, int on)
178{
179	struct dtkbd_softc *sc;
180
181	sc = v;
182	sc->sc_enabled = on;
183
184	return (0);
185}
186
187void
188dtkbd_cngetc(void *v, u_int *type, int *data)
189{
190	struct dt_msg msg;
191	static u_int types[20];
192	static int cnt, i, vals[20];
193
194	if (i >= cnt) {
195		for (;;) {
196			if (dt_msg_get(&msg, 0) == DT_GET_DONE)
197				if (msg.src == DT_ADDR_KBD &&
198				    !msg.code.val.P)
199					break;
200			DELAY(1000);
201		}
202
203		cnt = dtkbd_process_msg(&msg, types, vals);
204		i = 0;
205	}
206
207	*type = types[i++];
208	*data = vals[i++];
209}
210
211void
212dtkbd_cnpollc(void *v, int on)
213{
214
215	/* XXX */
216}
217
218int
219dtkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
220{
221	struct dtkbd_softc *sc;
222
223	sc = (struct dtkbd_softc *)v;
224
225	switch (cmd) {
226	case WSKBDIO_GTYPE:
227		*(int *)data = WSKBD_TYPE_LK201;
228		return 0;
229	default:
230		/* XXX */
231		return (-1);
232	}
233}
234
235void
236dtkbd_set_leds(void *v, int state)
237{
238
239	/* XXX */
240}
241
242void
243dtkbd_handler(void *cookie)
244{
245	struct dtkbd_softc *sc;
246	struct dt_softc *dt;
247	struct dt_device *dtdv;
248	struct dt_msg *msg;
249	u_int types[20];
250	int i, cnt, vals[20];
251
252	dtdv = cookie;
253	sc = (struct dtkbd_softc *)dtdv->dtdv_dv;
254	dt = (struct dt_softc *)sc->sc_dv.dv_parent;
255
256	while ((msg = dt_msg_dequeue(dtdv)) != NULL) {
257		if (sc->sc_enabled) {
258			if (!msg->code.val.P) {
259				cnt = dtkbd_process_msg(msg, types, vals);
260				for (i = 0; i < cnt; i++)
261					wskbd_input(sc->sc_wskbddev, types[i],
262					    vals[i]);
263			}
264		}
265
266		dt_msg_release(dt, msg);
267	}
268}
269
270int
271dtkbd_process_msg(struct dt_msg *msg, u_int *types, int *vals)
272{
273	u_int len, c, count;
274	int i, j;
275
276	len = msg->code.val.len;
277
278	if ((msg->body[0] < DT_KBD_KEY_MIN && msg->body[0] != DT_KBD_EMPTY) ||
279	    len > 10) {
280		printf("dtkbd0: error: %x %x %x\n", len, msg->body[0],
281		    msg->body[1]);
282
283		/*
284		 * Fake an "all ups" to avoid the stuck key syndrome.
285		 */
286		msg->body[0] = DT_KBD_EMPTY;
287		len = 1;
288	}
289
290	if (msg->body[0] == DT_KBD_EMPTY) {
291		types[0] = WSCONS_EVENT_ALL_KEYS_UP;
292		vals[0] = 0;
293		dtkbd_maplen = 0;
294		return (1);
295	}
296
297	count = 0;
298
299	for (i = 0; i < len; i++) {
300		c = msg->body[i];
301
302		for (j = 0; j < dtkbd_maplen; j++)
303			if (dtkbd_map[j] == c)
304				break;
305
306		if (j == dtkbd_maplen) {
307			types[count] = WSCONS_EVENT_KEY_DOWN;
308			vals[count] = c - MIN_LK201_KEY;
309			count++;
310		}
311	}
312
313	for (j = 0; j < dtkbd_maplen; j++) {
314		c = dtkbd_map[j];
315
316		for (i = 0; i < len; i++)
317			if (msg->body[i] == c)
318				break;
319
320		if (i == len) {
321			types[count] = WSCONS_EVENT_KEY_UP;
322			vals[count] = c - MIN_LK201_KEY;
323			count++;
324		}
325	}
326
327	memcpy(dtkbd_map, msg->body, len);
328	dtkbd_maplen = len;
329
330	return (count);
331}
332