lk201_ws.c revision 1.10.24.1 1 1.10.24.1 martin /* $NetBSD: lk201_ws.c,v 1.10.24.1 2024/02/17 16:19:14 martin 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.10.24.1 martin __KERNEL_RCSID(0, "$NetBSD: lk201_ws.c,v 1.10.24.1 2024/02/17 16:19:14 martin 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 const char *lkkbd_descr[] = {
47 1.9 jklos "no keyboard",
48 1.9 jklos "LK-201 keyboard",
49 1.9 jklos "LK-401 keyboard",
50 1.9 jklos };
51 1.9 jklos
52 1.2 drochner int
53 1.8 dsl lk201_init(struct lk201_state *lks)
54 1.1 drochner {
55 1.1 drochner int i;
56 1.1 drochner
57 1.9 jklos lks->waitack = 0;
58 1.9 jklos
59 1.2 drochner send(lks, LK_LED_ENABLE);
60 1.2 drochner send(lks, LK_LED_ALL);
61 1.2 drochner
62 1.2 drochner /*
63 1.2 drochner * set all keys to updown mode; autorepeat is
64 1.2 drochner * done by wskbd software
65 1.2 drochner */
66 1.2 drochner for (i = 1; i <= 14; i++)
67 1.2 drochner send(lks, LK_CMD_MODE(LK_UPDOWN, i));
68 1.2 drochner
69 1.2 drochner send(lks, LK_CL_ENABLE);
70 1.2 drochner send(lks, LK_PARAM_VOLUME(3));
71 1.3 ad lks->kcvol = (8 - 3) * 100 / 8;
72 1.2 drochner
73 1.2 drochner lks->bellvol = -1; /* not yet set */
74 1.2 drochner
75 1.1 drochner for (i = 0; i < LK_KLL; i++)
76 1.1 drochner lks->down_keys_list[i] = -1;
77 1.2 drochner send(lks, LK_KBD_ENABLE);
78 1.2 drochner
79 1.2 drochner send(lks, LK_LED_DISABLE);
80 1.2 drochner send(lks, LK_LED_ALL);
81 1.2 drochner lks->leds_state = 0;
82 1.2 drochner
83 1.9 jklos /*
84 1.9 jklos * Swallow all the keyboard acknowledges from lk201_init().
85 1.9 jklos * There should be 14 of them - one per LK_CMD_MODE command.
86 1.9 jklos */
87 1.9 jklos for(;;) {
88 1.9 jklos lks->waitack = 1;
89 1.9 jklos for (i = 100; i != 0; i--) {
90 1.9 jklos DELAY(1000);
91 1.9 jklos if (lks->waitack == 0)
92 1.9 jklos break;
93 1.9 jklos }
94 1.9 jklos if (i == 0)
95 1.9 jklos break;
96 1.9 jklos }
97 1.9 jklos
98 1.9 jklos /*
99 1.9 jklos * Try to set the keyboard in LK-401 mode.
100 1.9 jklos * If we receive an error, this is an LK-201 keyboard.
101 1.9 jklos */
102 1.9 jklos lks->waitack = 1;
103 1.9 jklos send(lks, LK_ENABLE_401);
104 1.9 jklos for (i = 100; i != 0; i--) {
105 1.9 jklos DELAY(1000);
106 1.9 jklos if (lks->waitack == 0)
107 1.9 jklos break;
108 1.9 jklos }
109 1.9 jklos if (lks->waitack != 0)
110 1.9 jklos lks->kbdtype = KBD_NONE;
111 1.9 jklos else {
112 1.9 jklos if (lks->ackdata == LK_INPUT_ERROR)
113 1.9 jklos lks->kbdtype = KBD_LK201;
114 1.9 jklos else
115 1.9 jklos lks->kbdtype = KBD_LK401;
116 1.9 jklos }
117 1.9 jklos lks->waitack = 0;
118 1.9 jklos
119 1.9 jklos printf("lkkbd0: %s\n", lkkbd_descr[lks->kbdtype]);
120 1.10 skrll
121 1.10 skrll return 0;
122 1.9 jklos }
123 1.9 jklos
124 1.1 drochner int
125 1.9 jklos lk201_decode(struct lk201_state *lks, int wantmulti, int datain, u_int *type, int *dataout)
126 1.1 drochner {
127 1.1 drochner int i, freeslot;
128 1.1 drochner
129 1.9 jklos if (lks->waitack != 0) {
130 1.9 jklos lks->ackdata = datain;
131 1.9 jklos lks->waitack = 0;
132 1.9 jklos return LKD_NODATA;
133 1.9 jklos }
134 1.9 jklos
135 1.1 drochner switch (datain) {
136 1.1 drochner case LK_POWER_UP:
137 1.1 drochner printf("lk201_decode: powerup detected\n");
138 1.2 drochner lk201_init(lks);
139 1.10.24.1 martin return LKD_NODATA;
140 1.1 drochner case LK_KDOWN_ERROR:
141 1.1 drochner case LK_POWER_ERROR:
142 1.1 drochner case LK_OUTPUT_ERROR:
143 1.1 drochner case LK_INPUT_ERROR:
144 1.1 drochner printf("lk201_decode: error %x\n", datain);
145 1.1 drochner /* FALLTHRU */
146 1.1 drochner case LK_KEY_REPEAT: /* autorepeat handled by wskbd */
147 1.1 drochner case LK_MODE_CHANGE: /* ignore silently */
148 1.10.24.1 martin return LKD_NODATA;
149 1.1 drochner }
150 1.1 drochner
151 1.9 jklos
152 1.9 jklos if (datain == LK_KEY_UP) {
153 1.9 jklos if (wantmulti) {
154 1.9 jklos for (i = 0; i < LK_KLL; i++)
155 1.9 jklos if (lks->down_keys_list[i] != -1) {
156 1.9 jklos *type = WSCONS_EVENT_KEY_UP;
157 1.9 jklos *dataout = lks->down_keys_list[i] -
158 1.9 jklos MIN_LK201_KEY;
159 1.9 jklos lks->down_keys_list[i] = -1;
160 1.10.24.1 martin return LKD_MORE;
161 1.9 jklos }
162 1.10.24.1 martin return LKD_NODATA;
163 1.9 jklos } else {
164 1.9 jklos for (i = 0; i < LK_KLL; i++)
165 1.9 jklos lks->down_keys_list[i] = -1;
166 1.9 jklos *type = WSCONS_EVENT_ALL_KEYS_UP;
167 1.10.24.1 martin return LKD_COMPLETE;
168 1.9 jklos }
169 1.9 jklos } else if (datain < MIN_LK201_KEY || datain > MAX_LK201_KEY) {
170 1.1 drochner printf("lk201_decode: %x\n", datain);
171 1.10.24.1 martin return LKD_NODATA;
172 1.1 drochner }
173 1.1 drochner
174 1.1 drochner *dataout = datain - MIN_LK201_KEY;
175 1.1 drochner
176 1.1 drochner freeslot = -1;
177 1.1 drochner for (i = 0; i < LK_KLL; i++) {
178 1.1 drochner if (lks->down_keys_list[i] == datain) {
179 1.1 drochner *type = WSCONS_EVENT_KEY_UP;
180 1.1 drochner lks->down_keys_list[i] = -1;
181 1.10.24.1 martin return LKD_COMPLETE;
182 1.1 drochner }
183 1.1 drochner if (lks->down_keys_list[i] == -1 && freeslot == -1)
184 1.1 drochner freeslot = i;
185 1.1 drochner }
186 1.1 drochner
187 1.1 drochner if (freeslot == -1) {
188 1.1 drochner printf("lk201_decode: down(%d) no free slot\n", datain);
189 1.10.24.1 martin return LKD_NODATA;
190 1.1 drochner }
191 1.1 drochner
192 1.1 drochner *type = WSCONS_EVENT_KEY_DOWN;
193 1.1 drochner lks->down_keys_list[freeslot] = datain;
194 1.10.24.1 martin return LKD_COMPLETE;
195 1.2 drochner }
196 1.2 drochner
197 1.2 drochner void
198 1.8 dsl lk201_bell(struct lk201_state *lks, struct wskbd_bell_data *bell)
199 1.2 drochner {
200 1.2 drochner unsigned int vol;
201 1.2 drochner
202 1.2 drochner if (bell->which & WSKBD_BELL_DOVOLUME) {
203 1.2 drochner vol = 8 - bell->volume * 8 / 100;
204 1.2 drochner if (vol > 7)
205 1.2 drochner vol = 7;
206 1.2 drochner } else
207 1.2 drochner vol = 3;
208 1.2 drochner
209 1.2 drochner if (vol != lks->bellvol) {
210 1.2 drochner send(lks, LK_BELL_ENABLE);
211 1.2 drochner send(lks, LK_PARAM_VOLUME(vol));
212 1.2 drochner lks->bellvol = vol;
213 1.2 drochner }
214 1.2 drochner send(lks, LK_RING_BELL);
215 1.2 drochner }
216 1.2 drochner
217 1.2 drochner void
218 1.8 dsl lk201_set_leds(struct lk201_state *lks, int leds)
219 1.2 drochner {
220 1.2 drochner int newleds;
221 1.2 drochner
222 1.2 drochner newleds = 0;
223 1.2 drochner if (leds & WSKBD_LED_SCROLL)
224 1.2 drochner newleds |= LK_LED_WAIT;
225 1.2 drochner if (leds & WSKBD_LED_CAPS)
226 1.2 drochner newleds |= LK_LED_LOCK;
227 1.2 drochner
228 1.2 drochner send(lks, LK_LED_DISABLE);
229 1.2 drochner send(lks, (0x80 | (~newleds & 0x0f)));
230 1.2 drochner
231 1.2 drochner send(lks, LK_LED_ENABLE);
232 1.2 drochner send(lks, (0x80 | (newleds & 0x0f)));
233 1.2 drochner
234 1.2 drochner lks->leds_state = leds;
235 1.3 ad }
236 1.3 ad
237 1.3 ad void
238 1.8 dsl lk201_set_keyclick(struct lk201_state *lks, int vol)
239 1.3 ad {
240 1.3 ad unsigned int newvol;
241 1.3 ad
242 1.3 ad if (vol == 0)
243 1.3 ad send(lks, LK_CL_DISABLE);
244 1.3 ad else {
245 1.3 ad newvol = 8 - vol * 8 / 100;
246 1.3 ad if (newvol > 7)
247 1.3 ad newvol = 7;
248 1.3 ad
249 1.3 ad send(lks, LK_CL_ENABLE);
250 1.3 ad send(lks, LK_PARAM_VOLUME(newvol));
251 1.3 ad }
252 1.4 ad
253 1.4 ad lks->kcvol = vol;
254 1.1 drochner }
255