Annotation of sys/dev/hil/hilkbd.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: hilkbd.c,v 1.13 2006/08/10 23:43:45 miod Exp $ */
2: /*
3: * Copyright (c) 2003, Miodrag Vallat.
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: *
15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25: * POSSIBILITY OF SUCH DAMAGE.
26: *
27: */
28:
29: #include <sys/param.h>
30: #include <sys/systm.h>
31: #include <sys/device.h>
32: #include <sys/ioctl.h>
33: #include <sys/kernel.h>
34: #include <sys/timeout.h>
35:
36: #include <machine/autoconf.h>
37: #include <machine/bus.h>
38: #include <machine/cpu.h>
39:
40: #include <dev/hil/hilreg.h>
41: #include <dev/hil/hilvar.h>
42: #include <dev/hil/hildevs.h>
43:
44: #include <dev/wscons/wsconsio.h>
45: #include <dev/wscons/wskbdvar.h>
46: #include <dev/wscons/wsksymdef.h>
47: #include <dev/wscons/wsksymvar.h>
48: #ifdef WSDISPLAY_COMPAT_RAWKBD
49: #include <dev/wscons/wskbdraw.h>
50: #endif
51:
52: #include <dev/hil/hilkbdmap.h>
53:
54: struct hilkbd_softc {
55: struct hildev_softc sc_hildev;
56:
57: int sc_numleds;
58: int sc_ledstate;
59: int sc_enabled;
60: int sc_console;
61: int sc_lastarrow;
62:
63: struct device *sc_wskbddev;
64:
65: #ifdef WSDISPLAY_COMPAT_RAWKBD
66: int sc_rawkbd;
67: int sc_nrep;
68: char sc_rep[HILBUFSIZE * 2];
69: struct timeout sc_rawrepeat_ch;
70: #define REP_DELAY1 400
71: #define REP_DELAYN 100
72: #endif
73: };
74:
75: int hilkbdprobe(struct device *, void *, void *);
76: void hilkbdattach(struct device *, struct device *, void *);
77: int hilkbddetach(struct device *, int);
78:
79: struct cfdriver hilkbd_cd = {
80: NULL, "hilkbd", DV_DULL
81: };
82:
83: struct cfattach hilkbd_ca = {
84: sizeof(struct hilkbd_softc), hilkbdprobe, hilkbdattach, hilkbddetach,
85: };
86:
87: int hilkbd_enable(void *, int);
88: void hilkbd_set_leds(void *, int);
89: int hilkbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
90:
91: const struct wskbd_accessops hilkbd_accessops = {
92: hilkbd_enable,
93: hilkbd_set_leds,
94: hilkbd_ioctl,
95: };
96:
97: void hilkbd_cngetc(void *, u_int *, int *);
98: void hilkbd_cnpollc(void *, int);
99: void hilkbd_cnbell(void *, u_int, u_int, u_int);
100:
101: const struct wskbd_consops hilkbd_consops = {
102: hilkbd_cngetc,
103: hilkbd_cnpollc,
104: hilkbd_cnbell,
105: };
106:
107: struct wskbd_mapdata hilkbd_keymapdata = {
108: hilkbd_keydesctab,
109: #ifdef HILKBD_LAYOUT
110: HILKBD_LAYOUT,
111: #else
112: KB_US,
113: #endif
114: };
115:
116: struct wskbd_mapdata hilkbd_keymapdata_ps2 = {
117: hilkbd_keydesctab_ps2,
118: #ifdef HILKBD_LAYOUT
119: HILKBD_LAYOUT,
120: #else
121: KB_US,
122: #endif
123: };
124:
125: void hilkbd_bell(struct hil_softc *, u_int, u_int, u_int);
126: void hilkbd_callback(struct hildev_softc *, u_int, u_int8_t *);
127: void hilkbd_decode(struct hilkbd_softc *, u_int8_t, u_int *, int *, int);
128: int hilkbd_is_console(int);
129: void hilkbd_rawrepeat(void *);
130:
131: int seen_hilkbd_console;
132:
133: int
134: hilkbdprobe(struct device *parent, void *match, void *aux)
135: {
136: struct hil_attach_args *ha = aux;
137:
138: if (ha->ha_type != HIL_DEVICE_KEYBOARD &&
139: ha->ha_type != HIL_DEVICE_BUTTONBOX)
140: return (0);
141:
142: return (1);
143: }
144:
145: void
146: hilkbdattach(struct device *parent, struct device *self, void *aux)
147: {
148: struct hilkbd_softc *sc = (void *)self;
149: struct hil_attach_args *ha = aux;
150: struct wskbddev_attach_args a;
151: u_int8_t layoutcode;
152: int ps2;
153:
154: sc->hd_code = ha->ha_code;
155: sc->hd_type = ha->ha_type;
156: sc->hd_infolen = ha->ha_infolen;
157: bcopy(ha->ha_info, sc->hd_info, ha->ha_infolen);
158: sc->hd_fn = hilkbd_callback;
159:
160: if (ha->ha_type == HIL_DEVICE_KEYBOARD) {
161: /*
162: * Determine the keyboard language configuration, but don't
163: * override a user-specified setting.
164: */
165: layoutcode = ha->ha_id & (MAXHILKBDLAYOUT - 1);
166: #ifndef HILKBD_LAYOUT
167: if (layoutcode < MAXHILKBDLAYOUT &&
168: hilkbd_layouts[layoutcode] != -1)
169: hilkbd_keymapdata.layout =
170: hilkbd_keymapdata_ps2.layout =
171: hilkbd_layouts[layoutcode];
172: #endif
173:
174: printf(", layout %x", layoutcode);
175: }
176:
177: /*
178: * Interpret the identification bytes, if any
179: */
180: if (ha->ha_infolen > 2 && (ha->ha_info[1] & HIL_IOB) != 0) {
181: /* HILIOB_PROMPT is not always reported... */
182: sc->sc_numleds = (ha->ha_info[2] & HILIOB_PMASK) >> 4;
183: if (sc->sc_numleds != 0)
184: printf(", %d leds", sc->sc_numleds);
185: }
186:
187: printf("\n");
188:
189: /*
190: * Red lettered keyboards come in two flavours, the old one
191: * with only one control key, to the left of the escape key,
192: * and the modern one which has a PS/2 like layout, and leds.
193: *
194: * Unfortunately for us, they use the same device ID range.
195: * We'll differentiate them by looking at the leds property.
196: */
197: ps2 = (sc->sc_numleds != 0);
198:
199: #ifdef WSDISPLAY_COMPAT_RAWKBD
200: timeout_set(&sc->sc_rawrepeat_ch, hilkbd_rawrepeat, sc);
201: #endif
202:
203: /* Do not consider button boxes as console devices. */
204: if (ha->ha_type == HIL_DEVICE_BUTTONBOX)
205: a.console = 0;
206: else
207: a.console = hilkbd_is_console(ha->ha_console);
208: a.keymap = ps2 ? &hilkbd_keymapdata_ps2 : &hilkbd_keymapdata;
209: a.accessops = &hilkbd_accessops;
210: a.accesscookie = sc;
211:
212: if (a.console) {
213: sc->sc_console = sc->sc_enabled = 1;
214: wskbd_cnattach(&hilkbd_consops, sc, a.keymap);
215: } else {
216: sc->sc_console = sc->sc_enabled = 0;
217: }
218:
219: sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
220:
221: /*
222: * If this is an old keyboard with a numeric pad but no ``num lock''
223: * key, simulate it being pressed so that the keyboard runs in
224: * numeric mode.
225: */
226: if (!ps2 && sc->sc_wskbddev != NULL) {
227: wskbd_input(sc->sc_wskbddev, WSCONS_EVENT_KEY_DOWN, 80);
228: wskbd_input(sc->sc_wskbddev, WSCONS_EVENT_KEY_UP, 80);
229: }
230: }
231:
232: int
233: hilkbddetach(struct device *self, int flags)
234: {
235: struct hilkbd_softc *sc = (void *)self;
236:
237: /*
238: * Handle console keyboard for the best. It should have been set
239: * as the first device in the loop anyways.
240: */
241: if (sc->sc_console) {
242: wskbd_cndetach();
243: seen_hilkbd_console = 0;
244: }
245:
246: if (sc->sc_wskbddev != NULL)
247: return config_detach(sc->sc_wskbddev, flags);
248:
249: return (0);
250: }
251:
252: int
253: hilkbd_enable(void *v, int on)
254: {
255: struct hilkbd_softc *sc = v;
256:
257: if (on) {
258: if (sc->sc_enabled)
259: return (EBUSY);
260: } else {
261: if (sc->sc_console)
262: return (EBUSY);
263: }
264:
265: sc->sc_enabled = on;
266:
267: return (0);
268: }
269:
270: void
271: hilkbd_set_leds(void *v, int leds)
272: {
273: struct hilkbd_softc *sc = v;
274: int changemask;
275:
276: if (sc->sc_numleds == 0)
277: return;
278:
279: changemask = leds ^ sc->sc_ledstate;
280: if (changemask == 0)
281: return;
282:
283: /* We do not handle more than 3 leds here */
284: if (changemask & WSKBD_LED_SCROLL)
285: send_hildev_cmd((struct hildev_softc *)sc,
286: (leds & WSKBD_LED_SCROLL) ? HIL_PROMPT1 : HIL_ACK1,
287: NULL, NULL);
288: if (changemask & WSKBD_LED_NUM)
289: send_hildev_cmd((struct hildev_softc *)sc,
290: (leds & WSKBD_LED_NUM) ? HIL_PROMPT2 : HIL_ACK2,
291: NULL, NULL);
292: if (changemask & WSKBD_LED_CAPS)
293: send_hildev_cmd((struct hildev_softc *)sc,
294: (leds & WSKBD_LED_CAPS) ? HIL_PROMPT3 : HIL_ACK3,
295: NULL, NULL);
296:
297: sc->sc_ledstate = leds;
298: }
299:
300: int
301: hilkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
302: {
303: struct hilkbd_softc *sc = v;
304:
305: switch (cmd) {
306: case WSKBDIO_GTYPE:
307: *(int *)data = WSKBD_TYPE_HIL;
308: return 0;
309: case WSKBDIO_SETLEDS:
310: hilkbd_set_leds(v, *(int *)data);
311: return 0;
312: case WSKBDIO_GETLEDS:
313: *(int *)data = sc->sc_ledstate;
314: return 0;
315: #ifdef WSDISPLAY_COMPAT_RAWKBD
316: case WSKBDIO_SETMODE:
317: sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
318: timeout_del(&sc->sc_rawrepeat_ch);
319: return 0;
320: #endif
321: case WSKBDIO_COMPLEXBELL:
322: #define d ((struct wskbd_bell_data *)data)
323: hilkbd_bell((struct hil_softc *)sc->hd_parent,
324: d->pitch, d->period, d->volume);
325: #undef d
326: return 0;
327: }
328:
329: return -1;
330: }
331:
332: void
333: hilkbd_cngetc(void *v, u_int *type, int *data)
334: {
335: struct hilkbd_softc *sc = v;
336: u_int8_t c, stat;
337:
338: for (;;) {
339: while (hil_poll_data((struct hildev_softc *)sc, &stat, &c) != 0)
340: ;
341:
342: /*
343: * Disregard keyboard data packet header.
344: * Note that no key generates it, so we're safe.
345: */
346: if (c != HIL_KBDBUTTON)
347: break;
348: }
349:
350: hilkbd_decode(sc, c, type, data, HIL_KBDBUTTON);
351: }
352:
353: void
354: hilkbd_cnpollc(void *v, int on)
355: {
356: struct hilkbd_softc *sc = v;
357:
358: hil_set_poll((struct hil_softc *)sc->hd_parent, on);
359: }
360:
361: void
362: hilkbd_cnbell(void *v, u_int pitch, u_int period, u_int volume)
363: {
364: struct hilkbd_softc *sc = v;
365:
366: hilkbd_bell((struct hil_softc *)sc->hd_parent,
367: pitch, period, volume);
368: }
369:
370: void
371: hilkbd_bell(struct hil_softc *sc, u_int pitch, u_int period, u_int volume)
372: {
373: u_int8_t buf[2];
374:
375: /* XXX there could be at least a pitch -> HIL pitch conversion here */
376: #define BELLDUR 80 /* tone duration in msec (10-2560) */
377: #define BELLFREQ 8 /* tone frequency (0-63) */
378: buf[0] = ar_format(period - 10);
379: buf[1] = BELLFREQ;
380: send_hil_cmd(sc, HIL_SETTONE, buf, 2, NULL);
381: }
382:
383: void
384: hilkbd_callback(struct hildev_softc *dev, u_int buflen, u_int8_t *buf)
385: {
386: struct hilkbd_softc *sc = (struct hilkbd_softc *)dev;
387: u_int type;
388: int kbdtype, key;
389: int i, s;
390:
391: /*
392: * Ignore packet if we don't need it
393: */
394: if (sc->sc_enabled == 0)
395: return;
396:
397: if (buflen == 0)
398: return;
399: switch ((kbdtype = *buf & HIL_KBDDATA)) {
400: case HIL_BUTTONBOX:
401: case HIL_KBDBUTTON:
402: break;
403: default:
404: return;
405: }
406:
407: #ifdef WSDISPLAY_COMPAT_RAWKBD
408: if (sc->sc_rawkbd) {
409: u_char cbuf[HILBUFSIZE * 2];
410: int c, j, npress;
411:
412: npress = j = 0;
413: for (i = 1, buf++; i < buflen; i++) {
414: hilkbd_decode(sc, *buf++, &type, &key, kbdtype);
415: c = hilkbd_raw[key];
416: if (c == RAWKEY_Null)
417: continue;
418: /* fake extended scancode if necessary */
419: if (c & 0x80)
420: cbuf[j++] = 0xe0;
421: cbuf[j] = c & 0x7f;
422: if (type == WSCONS_EVENT_KEY_UP)
423: cbuf[j] |= 0x80;
424: else {
425: /* remember pressed keys for autorepeat */
426: if (c & 0x80)
427: sc->sc_rep[npress++] = 0xe0;
428: sc->sc_rep[npress++] = c & 0x7f;
429: }
430: j++;
431: }
432:
433: s = spltty();
434: wskbd_rawinput(sc->sc_wskbddev, cbuf, j);
435: splx(s);
436: timeout_del(&sc->sc_rawrepeat_ch);
437: sc->sc_nrep = npress;
438: if (npress != 0) {
439: timeout_add(&sc->sc_rawrepeat_ch,
440: (hz * REP_DELAY1) / 1000);
441: }
442: } else
443: #endif
444: {
445: s = spltty();
446: for (i = 1, buf++; i < buflen; i++) {
447: hilkbd_decode(sc, *buf++, &type, &key, kbdtype);
448: if (sc->sc_wskbddev != NULL)
449: wskbd_input(sc->sc_wskbddev, type, key);
450: }
451: splx(s);
452: }
453: }
454:
455: void
456: hilkbd_decode(struct hilkbd_softc *sc, u_int8_t data, u_int *type, int *key,
457: int kbdtype)
458: {
459: if (kbdtype == HIL_BUTTONBOX) {
460: if (data == 0x02) /* repeat arrow */
461: data = sc->sc_lastarrow;
462: else if (data >= 0xf8)
463: sc->sc_lastarrow = data;
464: }
465:
466: *type = (data & 1) ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
467: *key = data >> 1;
468: }
469:
470: int
471: hilkbd_is_console(int hil_is_console)
472: {
473: /* if not first hil keyboard, then not the console */
474: if (seen_hilkbd_console)
475: return (0);
476:
477: /* if PDC console does not match hil bus path, then not the console */
478: if (hil_is_console == 0)
479: return (0);
480:
481: seen_hilkbd_console = 1;
482: return (1);
483: }
484:
485: #ifdef WSDISPLAY_COMPAT_RAWKBD
486: void
487: hilkbd_rawrepeat(void *v)
488: {
489: struct hilkbd_softc *sc = v;
490: int s;
491:
492: s = spltty();
493: wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep);
494: splx(s);
495: timeout_add(&sc->sc_rawrepeat_ch, (hz * REP_DELAYN) / 1000);
496: }
497: #endif
CVSweb