xref: /netbsd-src/sys/dev/dec/lk201_ws.c (revision a24efa7dea9f1f56c3bdb15a927d3516792ace1c)
1 /* $NetBSD: lk201_ws.c,v 1.9 2015/01/02 21:32:26 jklos Exp $ */
2 
3 /*
4  * Copyright (c) 1998
5  *	Matthias Drochner.  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  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: lk201_ws.c,v 1.9 2015/01/02 21:32:26 jklos Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/callout.h>
35 
36 #include <dev/wscons/wsconsio.h>
37 
38 #include <dev/dec/lk201reg.h>
39 #include <dev/dec/lk201var.h>
40 #include <dev/dec/wskbdmap_lk201.h> /* for {MIN,MAX}_LK201_KEY */
41 
42 #define send(lks, c) ((*((lks)->attmt.sendchar))((lks)->attmt.cookie, c))
43 
44 void lk201_identify(void *);
45 
46 static callout_t lkkbd_id;
47 
48 static const char *lkkbd_descr[] = {
49 	"no keyboard",
50 	"LK-201 keyboard",
51 	"LK-401 keyboard",
52 };
53 
54 int
55 lk201_init(struct lk201_state *lks)
56 {
57 	int i;
58 
59 	lks->waitack = 0;
60 
61 	send(lks, LK_LED_ENABLE);
62 	send(lks, LK_LED_ALL);
63 
64 	/*
65 	 * set all keys to updown mode; autorepeat is
66 	 * done by wskbd software
67 	 */
68 	for (i = 1; i <= 14; i++)
69 		send(lks, LK_CMD_MODE(LK_UPDOWN, i));
70 
71 	send(lks, LK_CL_ENABLE);
72 	send(lks, LK_PARAM_VOLUME(3));
73 	lks->kcvol = (8 - 3) * 100 / 8;
74 
75 	lks->bellvol = -1; /* not yet set */
76 
77 	for (i = 0; i < LK_KLL; i++)
78 		lks->down_keys_list[i] = -1;
79 	send(lks, LK_KBD_ENABLE);
80 
81 	send(lks, LK_LED_DISABLE);
82 	send(lks, LK_LED_ALL);
83 	lks->leds_state = 0;
84 
85 	callout_init(&lkkbd_id, 0);
86 	callout_setfunc(&lkkbd_id, lk201_identify, lks);
87 	callout_schedule(&lkkbd_id, 0);
88 
89 	return (0);
90 }
91 
92 void
93 lk201_identify(void *v)
94 {
95 	struct lk201_state *lks = v;
96 	int i;
97 
98 	callout_destroy(&lkkbd_id);
99 	/*
100 	 * Swallow all the keyboard acknowledges from lk201_init().
101 	 * There should be 14 of them - one per LK_CMD_MODE command.
102 	 */
103 	for(;;) {
104 		lks->waitack = 1;
105 		for (i = 100; i != 0; i--) {
106 			DELAY(1000);
107 			if (lks->waitack == 0)
108 				break;
109 		}
110 		if (i == 0)
111 			break;
112 	}
113 
114 	/*
115 	 * Try to set the keyboard in LK-401 mode.
116 	 * If we receive an error, this is an LK-201 keyboard.
117 	 */
118 	lks->waitack = 1;
119 	send(lks, LK_ENABLE_401);
120 	for (i = 100; i != 0; i--) {
121 		DELAY(1000);
122 		if (lks->waitack == 0)
123 			break;
124 	}
125 	if (lks->waitack != 0)
126 		lks->kbdtype = KBD_NONE;
127 	else {
128 		if (lks->ackdata == LK_INPUT_ERROR)
129 			lks->kbdtype = KBD_LK201;
130 		else
131 			lks->kbdtype = KBD_LK401;
132 	}
133 	lks->waitack = 0;
134 
135 	printf("lkkbd0: %s\n", lkkbd_descr[lks->kbdtype]);
136 }
137 
138 int
139 lk201_decode(struct lk201_state *lks, int wantmulti, int datain, u_int *type, int *dataout)
140 {
141 	int i, freeslot;
142 
143 	if (lks->waitack != 0) {
144 		lks->ackdata = datain;
145 		lks->waitack = 0;
146 		return LKD_NODATA;
147 	}
148 
149 	switch (datain) {
150 #if 0
151 	    case LK_KEY_UP:
152 		for (i = 0; i < LK_KLL; i++)
153 			lks->down_keys_list[i] = -1;
154 		*type = WSCONS_EVENT_ALL_KEYS_UP;
155 		return (1);
156 #endif
157 	    case LK_POWER_UP:
158 		printf("lk201_decode: powerup detected\n");
159 		lk201_init(lks);
160 		return (0);
161 	    case LK_KDOWN_ERROR:
162 	    case LK_POWER_ERROR:
163 	    case LK_OUTPUT_ERROR:
164 	    case LK_INPUT_ERROR:
165 		printf("lk201_decode: error %x\n", datain);
166 		/* FALLTHRU */
167 	    case LK_KEY_REPEAT: /* autorepeat handled by wskbd */
168 	    case LK_MODE_CHANGE: /* ignore silently */
169 		return (0);
170 	}
171 
172 
173 	if (datain == LK_KEY_UP) {
174 		if (wantmulti) {
175 			for (i = 0; i < LK_KLL; i++)
176 				if (lks->down_keys_list[i] != -1) {
177 					*type = WSCONS_EVENT_KEY_UP;
178 					*dataout = lks->down_keys_list[i] -
179 					    MIN_LK201_KEY;
180 					lks->down_keys_list[i] = -1;
181 					return (LKD_MORE);
182 				}
183 			return (LKD_NODATA);
184 		} else {
185 			for (i = 0; i < LK_KLL; i++)
186 				lks->down_keys_list[i] = -1;
187 			*type = WSCONS_EVENT_ALL_KEYS_UP;
188 			return (LKD_COMPLETE);
189 		}
190 	} else if (datain < MIN_LK201_KEY || datain > MAX_LK201_KEY) {
191 		printf("lk201_decode: %x\n", datain);
192 		return (0);
193 	}
194 
195 	*dataout = datain - MIN_LK201_KEY;
196 
197 	freeslot = -1;
198 	for (i = 0; i < LK_KLL; i++) {
199 		if (lks->down_keys_list[i] == datain) {
200 			*type = WSCONS_EVENT_KEY_UP;
201 			lks->down_keys_list[i] = -1;
202 			return (1);
203 		}
204 		if (lks->down_keys_list[i] == -1 && freeslot == -1)
205 			freeslot = i;
206 	}
207 
208 	if (freeslot == -1) {
209 		printf("lk201_decode: down(%d) no free slot\n", datain);
210 		return (0);
211 	}
212 
213 	*type = WSCONS_EVENT_KEY_DOWN;
214 	lks->down_keys_list[freeslot] = datain;
215 	return (1);
216 }
217 
218 void
219 lk201_bell(struct lk201_state *lks, struct wskbd_bell_data *bell)
220 {
221 	unsigned int vol;
222 
223 	if (bell->which & WSKBD_BELL_DOVOLUME) {
224 		vol = 8 - bell->volume * 8 / 100;
225 		if (vol > 7)
226 			vol = 7;
227 	} else
228 		vol = 3;
229 
230 	if (vol != lks->bellvol) {
231 		send(lks, LK_BELL_ENABLE);
232 		send(lks, LK_PARAM_VOLUME(vol));
233 		lks->bellvol = vol;
234 	}
235 	send(lks, LK_RING_BELL);
236 }
237 
238 void
239 lk201_set_leds(struct lk201_state *lks, int leds)
240 {
241 	int newleds;
242 
243 	newleds = 0;
244 	if (leds & WSKBD_LED_SCROLL)
245 		newleds |= LK_LED_WAIT;
246 	if (leds & WSKBD_LED_CAPS)
247 		newleds |= LK_LED_LOCK;
248 
249 	send(lks, LK_LED_DISABLE);
250 	send(lks, (0x80 | (~newleds & 0x0f)));
251 
252 	send(lks, LK_LED_ENABLE);
253 	send(lks, (0x80 | (newleds & 0x0f)));
254 
255 	lks->leds_state = leds;
256 }
257 
258 void
259 lk201_set_keyclick(struct lk201_state *lks, int vol)
260 {
261 	unsigned int newvol;
262 
263 	if (vol == 0)
264 		send(lks, LK_CL_DISABLE);
265 	else {
266 		newvol = 8 - vol * 8 / 100;
267 		if (newvol > 7)
268 			newvol = 7;
269 
270 		send(lks, LK_CL_ENABLE);
271 		send(lks, LK_PARAM_VOLUME(newvol));
272 	}
273 
274 	lks->kcvol = vol;
275 }
276