lk201_ws.c revision 1.8.38.1 1 /* $NetBSD: lk201_ws.c,v 1.8.38.1 2015/01/02 08:09:51 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.8.38.1 2015/01/02 08:09:51 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