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