1/*	$NetBSD: dzkbd.c,v 1.22 2009/05/12 12:11:54 cegger Exp $	*/
2
3/*
4 * Copyright (c) 1992, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This software was developed by the Computer Systems Engineering group
8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9 * contributed to Berkeley.
10 *
11 * All advertising materials mentioning features or use of this software
12 * must display the following acknowledgement:
13 *	This product includes software developed by the University of
14 *	California, Lawrence Berkeley Laboratory.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 *    notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 *    notice, this list of conditions and the following disclaimer in the
23 *    documentation and/or other materials provided with the distribution.
24 * 3. Neither the name of the University nor the names of its contributors
25 *    may be used to endorse or promote products derived from this software
26 *    without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 *	@(#)kbd.c	8.2 (Berkeley) 10/30/93
41 */
42
43/*
44 * LK200/LK400 keyboard attached to line 0 of the DZ*-11
45 */
46
47#include <sys/cdefs.h>
48__KERNEL_RCSID(0, "$NetBSD: dzkbd.c,v 1.22 2009/05/12 12:11:54 cegger Exp $");
49
50#include <sys/param.h>
51#include <sys/systm.h>
52#include <sys/device.h>
53#include <sys/ioctl.h>
54#include <sys/syslog.h>
55#include <sys/malloc.h>
56#include <sys/intr.h>
57
58#include <dev/wscons/wsconsio.h>
59#include <dev/wscons/wskbdvar.h>
60#include <dev/wscons/wsksymdef.h>
61#include <dev/wscons/wsksymvar.h>
62#include <dev/dec/wskbdmap_lk201.h>
63
64#include <sys/bus.h>
65
66#include <dev/dec/dzreg.h>
67#include <dev/dec/dzvar.h>
68#include <dev/dec/dzkbdvar.h>
69#include <dev/dec/lk201reg.h>
70#include <dev/dec/lk201var.h>
71
72#include "locators.h"
73
74struct dzkbd_internal {
75	struct dz_linestate *dzi_ls;
76	struct lk201_state dzi_ks;
77};
78
79struct dzkbd_internal dzkbd_console_internal;
80
81struct dzkbd_softc {
82	struct device dzkbd_dev;	/* required first: base device */
83
84	struct dzkbd_internal *sc_itl;
85
86	int sc_enabled;
87	int kbd_type;
88
89	device_t sc_wskbddev;
90};
91
92static int	dzkbd_input(void *, int);
93
94static int	dzkbd_match(device_t, cfdata_t, void *);
95static void	dzkbd_attach(device_t, device_t, void *);
96
97CFATTACH_DECL(dzkbd, sizeof(struct dzkbd_softc),
98    dzkbd_match, dzkbd_attach, NULL, NULL);
99
100static int	dzkbd_enable(void *, int);
101static void	dzkbd_set_leds(void *, int);
102static int	dzkbd_ioctl(void *, u_long, void *, int, struct lwp *);
103
104const struct wskbd_accessops dzkbd_accessops = {
105	dzkbd_enable,
106	dzkbd_set_leds,
107	dzkbd_ioctl,
108};
109
110static void	dzkbd_cngetc(void *, u_int *, int *);
111static void	dzkbd_cnpollc(void *, int);
112
113const struct wskbd_consops dzkbd_consops = {
114	dzkbd_cngetc,
115	dzkbd_cnpollc,
116};
117
118static int dzkbd_sendchar(void *, u_char);
119
120const struct wskbd_mapdata dzkbd_keymapdata = {
121	lkkbd_keydesctab,
122#ifdef DZKBD_LAYOUT
123	DZKBD_LAYOUT,
124#else
125	KB_US | KB_LK401,
126#endif
127};
128
129/*
130 * kbd_match: how is this dz line configured?
131 */
132static int
133dzkbd_match(device_t parent, cfdata_t cf, void *aux)
134{
135	struct dzkm_attach_args *daa = aux;
136
137	/* Exact match is better than wildcard. */
138	if (cf->cf_loc[DZCF_LINE] == daa->daa_line)
139		return 2;
140
141	/* This driver accepts wildcard. */
142	if (cf->cf_loc[DZCF_LINE] == DZCF_LINE_DEFAULT)
143		return 1;
144
145	return 0;
146}
147
148static void
149dzkbd_attach(device_t parent, device_t self, void *aux)
150{
151	struct dz_softc *dz = device_private(parent);
152	struct dzkbd_softc *dzkbd = device_private(self);
153	struct dzkm_attach_args *daa = aux;
154	struct dz_linestate *ls;
155	struct dzkbd_internal *dzi;
156	struct wskbddev_attach_args a;
157	int isconsole;
158
159	dz->sc_dz[daa->daa_line].dz_catch = dzkbd_input;
160	dz->sc_dz[daa->daa_line].dz_private = dzkbd;
161	ls = &dz->sc_dz[daa->daa_line];
162
163	isconsole = (daa->daa_flags & DZKBD_CONSOLE);
164
165	if (isconsole) {
166		dzi = &dzkbd_console_internal;
167	} else {
168		dzi = malloc(sizeof(struct dzkbd_internal),
169				       M_DEVBUF, M_NOWAIT);
170		dzi->dzi_ks.attmt.sendchar = dzkbd_sendchar;
171		dzi->dzi_ks.attmt.cookie = ls;
172	}
173	dzi->dzi_ls = ls;
174	dzkbd->sc_itl = dzi;
175
176	printf("\n");
177
178	if (!isconsole) {
179		DELAY(100000);
180		lk201_init(&dzi->dzi_ks);
181	}
182
183	/* XXX should identify keyboard ID here XXX */
184	/* XXX layout and the number of LED is varying XXX */
185
186	dzkbd->kbd_type = WSKBD_TYPE_LK201;
187
188	dzkbd->sc_enabled = 1;
189
190	a.console = isconsole;
191	a.keymap = &dzkbd_keymapdata;
192	a.accessops = &dzkbd_accessops;
193	a.accesscookie = dzkbd;
194
195	dzkbd->sc_wskbddev = config_found(self, &a, wskbddevprint);
196}
197
198int
199dzkbd_cnattach(struct dz_linestate *ls)
200{
201
202	dzkbd_console_internal.dzi_ks.attmt.sendchar = dzkbd_sendchar;
203	dzkbd_console_internal.dzi_ks.attmt.cookie = ls;
204	lk201_init(&dzkbd_console_internal.dzi_ks);
205	dzkbd_console_internal.dzi_ls = ls;
206
207	wskbd_cnattach(&dzkbd_consops, &dzkbd_console_internal,
208		       &dzkbd_keymapdata);
209
210	return 0;
211}
212
213static int
214dzkbd_enable(void *v, int on)
215{
216	struct dzkbd_softc *sc = v;
217
218	sc->sc_enabled = on;
219	return 0;
220}
221
222static int
223dzkbd_sendchar(void *v, u_char c)
224{
225	struct dz_linestate *ls = v;
226	int s;
227
228	s = spltty();
229	dzputc(ls, c);
230	splx(s);
231	return (0);
232}
233
234static void
235dzkbd_cngetc(void *v, u_int *type, int *data)
236{
237	struct dzkbd_internal *dzi = v;
238	int c;
239
240	do {
241		c = dzgetc(dzi->dzi_ls);
242	} while (!lk201_decode(&dzi->dzi_ks, c, type, data));
243}
244
245static void
246dzkbd_cnpollc(void *v, int on)
247{
248#if 0
249	struct dzkbd_internal *dzi = v;
250#endif
251}
252
253static void
254dzkbd_set_leds(void *v, int leds)
255{
256	struct dzkbd_softc *sc = (struct dzkbd_softc *)v;
257
258//printf("dzkbd_set_leds\n");
259	lk201_set_leds(&sc->sc_itl->dzi_ks, leds);
260}
261
262static int
263dzkbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
264{
265	struct dzkbd_softc *sc = (struct dzkbd_softc *)v;
266
267	switch (cmd) {
268	case WSKBDIO_GTYPE:
269		*(int *)data = sc->kbd_type;
270		return 0;
271	case WSKBDIO_SETLEDS:
272		lk201_set_leds(&sc->sc_itl->dzi_ks, *(int *)data);
273		return 0;
274	case WSKBDIO_GETLEDS:
275		/* XXX don't dig in kbd internals */
276		*(int *)data = sc->sc_itl->dzi_ks.leds_state;
277		return 0;
278	case WSKBDIO_COMPLEXBELL:
279		lk201_bell(&sc->sc_itl->dzi_ks,
280			   (struct wskbd_bell_data *)data);
281		return 0;
282	case WSKBDIO_SETKEYCLICK:
283		lk201_set_keyclick(&sc->sc_itl->dzi_ks, *(int *)data);
284		return 0;
285	case WSKBDIO_GETKEYCLICK:
286		/* XXX don't dig in kbd internals */
287		*(int *)data = sc->sc_itl->dzi_ks.kcvol;
288		return 0;
289	}
290	return (EPASSTHROUGH);
291}
292
293static int
294dzkbd_input(void *v, int data)
295{
296	struct dzkbd_softc *sc = (struct dzkbd_softc *)v;
297	u_int type;
298	int val;
299
300	if (sc->sc_enabled == 0)
301		return(0);
302
303	if (lk201_decode(&sc->sc_itl->dzi_ks, data, &type, &val))
304		wskbd_input(sc->sc_wskbddev, type, val);
305	return(1);
306}
307
308