Annotation of sys/arch/vax/dec/lk201_ws.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: lk201_ws.c,v 1.10 2006/08/27 16:50:43 miod Exp $ */
2: /* $NetBSD: lk201_ws.c,v 1.2 1998/10/22 17:55:20 drochner Exp $ */
3:
4: /*
5: * Copyright (c) 1998
6: * Matthias Drochner. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed for the NetBSD Project
19: * by Matthias Drochner.
20: * 4. The name of the author may not be used to endorse or promote products
21: * derived from this software without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33: *
34: */
35:
36: #include <sys/param.h>
37: #include <sys/systm.h>
38: #include <sys/kernel.h>
39: #include <sys/proc.h>
40: #include <sys/tty.h>
41: #include <sys/timeout.h>
42:
43: #include <dev/wscons/wsconsio.h>
44:
45: #include <vax/dec/lk201reg.h>
46: #include <vax/dec/lk201var.h>
47: #include <vax/dec/wskbdmap_lk201.h> /* for {MIN,MAX}_LK201_KEY */
48:
49: struct cfdriver lkkbd_cd = {
50: NULL, "lkkbd", DV_DULL
51: };
52:
53: void lk201_identify(void *);
54:
55: static const char *lkkbd_descr[] = {
56: "no keyboard",
57: "LK-201 keyboard",
58: "LK-401 keyboard"
59: };
60:
61: #define send(lks, c) ((*((lks)->attmt.sendchar))((lks)->attmt.cookie, c))
62:
63: void
64: lk201_init(struct lk201_state *lks)
65: {
66: int i;
67:
68: lks->waitack = 0;
69:
70: send(lks, LK_LED_ENABLE);
71: send(lks, LK_LED_ALL);
72:
73: /*
74: * set all keys to updown mode; autorepeat is
75: * done by wskbd software
76: */
77: for (i = 1; i <= 14; i++)
78: send(lks, LK_CMD_MODE(LK_UPDOWN, i));
79:
80: send(lks, LK_CL_DISABLE);
81: lks->kcvol = 0;
82:
83: lks->bellvol = -1; /* not yet set */
84:
85: for (i = 0; i < LK_KLL; i++)
86: lks->down_keys_list[i] = -1;
87: send(lks, LK_KBD_ENABLE);
88:
89: send(lks, LK_LED_DISABLE);
90: send(lks, LK_LED_ALL);
91: lks->leds_state = 0;
92:
93: /*
94: * Note that, when attaching lkkbd initially, this timeout will
95: * be scheduled but will not run until interrupts are enabled.
96: * This is not a problem, since lk201_identify() relies upon
97: * interrupts being enabled.
98: */
99: timeout_set(&lks->probetmo, lk201_identify, lks);
100: timeout_add(&lks->probetmo, 0);
101: }
102:
103: void
104: lk201_identify(void *v)
105: {
106: struct lk201_state *lks = v;
107: int i;
108:
109: /*
110: * Swallow all the keyboard acknowledges from lk201_init().
111: * There should be 14 of them - one per LK_CMD_MODE command.
112: */
113: for(;;) {
114: lks->waitack = 1;
115: for (i = 100; i != 0; i--) {
116: DELAY(1000);
117: if (lks->waitack == 0)
118: break;
119: }
120: if (i == 0)
121: break;
122: }
123:
124: /*
125: * Try to set the keyboard in LK-401 mode.
126: * If we receive an error, this is an LK-201 keyboard.
127: */
128: lks->waitack = 1;
129: send(lks, LK_ENABLE_401);
130: for (i = 100; i != 0; i--) {
131: DELAY(1000);
132: if (lks->waitack == 0)
133: break;
134: }
135: if (lks->waitack != 0)
136: lks->kbdtype = KBD_NONE;
137: else {
138: if (lks->ackdata == LK_INPUT_ERROR)
139: lks->kbdtype = KBD_LK201;
140: else
141: lks->kbdtype = KBD_LK401;
142: }
143: lks->waitack = 0;
144:
145: printf("%s: %s\n", lks->device->dv_xname, lkkbd_descr[lks->kbdtype]);
146: }
147:
148: int
149: lk201_decode(struct lk201_state *lks, int active, int wantmulti, int datain,
150: u_int *type, int *dataout)
151: {
152: int i, freeslot;
153:
154: if (lks->waitack != 0) {
155: lks->ackdata = datain;
156: lks->waitack = 0;
157: return (LKD_NODATA);
158: }
159:
160: switch (datain) {
161: case LK_POWER_UP:
162: #ifdef DEBUG
163: printf("lk201_decode: powerup detected\n");
164: #endif
165: lk201_init(lks);
166: return (LKD_NODATA);
167: case LK_KDOWN_ERROR:
168: case LK_POWER_ERROR:
169: case LK_OUTPUT_ERROR:
170: case LK_INPUT_ERROR:
171: printf("lk201_decode: error %x\n", datain);
172: /* FALLTHROUGH */
173: case LK_KEY_REPEAT: /* autorepeat handled by wskbd */
174: case LK_MODE_CHANGE: /* ignore silently */
175: return (LKD_NODATA);
176: }
177:
178: if (active == 0)
179: return (LKD_NODATA); /* no need to decode */
180:
181: if (datain == LK_KEY_UP) {
182: if (wantmulti) {
183: for (i = 0; i < LK_KLL; i++)
184: if (lks->down_keys_list[i] != -1) {
185: *type = WSCONS_EVENT_KEY_UP;
186: *dataout = lks->down_keys_list[i] -
187: MIN_LK201_KEY;
188: lks->down_keys_list[i] = -1;
189: return (LKD_MORE);
190: }
191: return (LKD_NODATA);
192: } else {
193: for (i = 0; i < LK_KLL; i++)
194: lks->down_keys_list[i] = -1;
195: *type = WSCONS_EVENT_ALL_KEYS_UP;
196: return (LKD_COMPLETE);
197: }
198: } else if (datain < MIN_LK201_KEY || datain > MAX_LK201_KEY) {
199: #ifdef DEBUG
200: /* this can happen while hotplugging the keyboard */
201: printf("lk201_decode: %x\n", datain);
202: #endif
203: return (LKD_NODATA);
204: }
205:
206: /*
207: * The LK-201 keyboard has a compose key (to the left of the spacebar),
208: * but no alt/meta key at all. The LK-401 keyboard fixes this and has
209: * two compose keys and two alt keys.
210: *
211: * If the keyboard is an LK-201, translate the left compose key
212: * scancode to a specific key code, which will map as a left alt key,
213: * and compose key when shifted), so that the user can have both
214: * an alt and a compose key available.
215: */
216: if (lks->kbdtype == KBD_LK201 && datain == 177)
217: datain = 252;
218:
219: *dataout = datain - MIN_LK201_KEY;
220:
221: freeslot = -1;
222: for (i = 0; i < LK_KLL; i++) {
223: if (lks->down_keys_list[i] == datain) {
224: *type = WSCONS_EVENT_KEY_UP;
225: lks->down_keys_list[i] = -1;
226: return (LKD_COMPLETE);
227: }
228: if (lks->down_keys_list[i] == -1 && freeslot == -1)
229: freeslot = i;
230: }
231:
232: if (freeslot == -1) {
233: printf("lk201_decode: down(%d) no free slot\n", datain);
234: return (LKD_NODATA);
235: }
236:
237: *type = WSCONS_EVENT_KEY_DOWN;
238: lks->down_keys_list[freeslot] = datain;
239: return (LKD_COMPLETE);
240: }
241:
242: void
243: lk201_bell(struct lk201_state *lks, struct wskbd_bell_data *bell)
244: {
245: unsigned int vol;
246:
247: if (bell->which & WSKBD_BELL_DOVOLUME) {
248: vol = 8 - bell->volume * 8 / 100;
249: if (vol > 7)
250: vol = 7;
251: } else
252: vol = 3;
253:
254: if (vol != lks->bellvol) {
255: send(lks, LK_BELL_ENABLE);
256: send(lks, LK_PARAM_VOLUME(vol));
257: lks->bellvol = vol;
258: }
259: send(lks, LK_RING_BELL);
260: }
261:
262: int
263: lk201_get_leds(struct lk201_state *lks)
264: {
265: return (lks->leds_state);
266: }
267:
268: int
269: lk201_get_type(struct lk201_state *lks)
270: {
271: /*
272: * Note that we report LK201 even if no keyboard is
273: * plugged to avoid confusing wsconsctl.
274: */
275: if (lks->kbdtype == KBD_LK401)
276: return (WSKBD_TYPE_LK401);
277: else
278: return (WSKBD_TYPE_LK201);
279: }
280:
281: void
282: lk201_set_keyclick(struct lk201_state *lks, int vol)
283: {
284: unsigned int newvol;
285:
286: if (vol == 0)
287: send(lks, LK_CL_DISABLE);
288: else {
289: newvol = 8 - vol * 8 / 100;
290: if (newvol > 7)
291: newvol = 7;
292:
293: send(lks, LK_CL_ENABLE);
294: send(lks, LK_PARAM_VOLUME(newvol));
295: }
296:
297: lks->kcvol = vol;
298: }
299:
300: void
301: lk201_set_leds(struct lk201_state *lks, int leds)
302: {
303: int newleds;
304:
305: newleds = 0;
306: if (leds & WSKBD_LED_SCROLL)
307: newleds |= LK_LED_WAIT;
308: if (leds & WSKBD_LED_CAPS)
309: newleds |= LK_LED_LOCK;
310:
311: send(lks, LK_LED_DISABLE);
312: send(lks, (0x80 | (~newleds & 0x0f)));
313:
314: send(lks, LK_LED_ENABLE);
315: send(lks, (0x80 | (newleds & 0x0f)));
316:
317: lks->leds_state = leds;
318: }
CVSweb