Annotation of sys/arch/hppa/gsc/gsckbd.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: gsckbd.c,v 1.7 2006/12/17 21:26:53 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: /*
30: * Derived from /sys/dev/pckbc/pckbd.c under the following terms:
31: * OpenBSD: pckbd.c,v 1.4 2002/03/14 01:27:00 millert Exp
32: * NetBSD: pckbd.c,v 1.24 2000/06/05 22:20:57 sommerfeld Exp
33: */
34: /*-
35: * Copyright (c) 1998 The NetBSD Foundation, Inc.
36: * All rights reserved.
37: *
38: * This code is derived from software contributed to The NetBSD Foundation
39: * by Charles M. Hannum.
40: *
41: * Redistribution and use in source and binary forms, with or without
42: * modification, are permitted provided that the following conditions
43: * are met:
44: * 1. Redistributions of source code must retain the above copyright
45: * notice, this list of conditions and the following disclaimer.
46: * 2. Redistributions in binary form must reproduce the above copyright
47: * notice, this list of conditions and the following disclaimer in the
48: * documentation and/or other materials provided with the distribution.
49: * 3. All advertising materials mentioning features or use of this software
50: * must display the following acknowledgement:
51: * This product includes software developed by the NetBSD
52: * Foundation, Inc. and its contributors.
53: * 4. Neither the name of The NetBSD Foundation nor the names of its
54: * contributors may be used to endorse or promote products derived
55: * from this software without specific prior written permission.
56: *
57: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
58: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
59: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
60: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
61: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
62: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
63: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
64: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
65: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
66: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
67: * POSSIBILITY OF SUCH DAMAGE.
68: */
69:
70: /*-
71: * Copyright (c) 1990 The Regents of the University of California.
72: * All rights reserved.
73: *
74: * This code is derived from software contributed to Berkeley by
75: * William Jolitz and Don Ahn.
76: *
77: * Redistribution and use in source and binary forms, with or without
78: * modification, are permitted provided that the following conditions
79: * are met:
80: * 1. Redistributions of source code must retain the above copyright
81: * notice, this list of conditions and the following disclaimer.
82: * 2. Redistributions in binary form must reproduce the above copyright
83: * notice, this list of conditions and the following disclaimer in the
84: * documentation and/or other materials provided with the distribution.
85: * 3. Neither the name of the University nor the names of its contributors
86: * may be used to endorse or promote products derived from this software
87: * without specific prior written permission.
88: *
89: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
90: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
91: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
92: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
93: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
94: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
95: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
96: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
97: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
98: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
99: * SUCH DAMAGE.
100: *
101: * @(#)pccons.c 5.11 (Berkeley) 5/21/91
102: */
103:
104: /*
105: * A pckbd-like driver for the GSC keyboards found on various HP workstations.
106: */
107:
108: #include <sys/param.h>
109: #include <sys/systm.h>
110: #include <sys/device.h>
111: #include <sys/malloc.h>
112: #include <sys/ioctl.h>
113:
114: #include <machine/bus.h>
115:
116: #include <dev/ic/pckbcvar.h>
117:
118: #include <dev/pckbc/pckbdreg.h>
119: #include <hppa/gsc/gsckbdvar.h>
120: #include <hppa/gsc/gsckbdmap.h>
121:
122: #include <dev/wscons/wsconsio.h>
123: #include <dev/wscons/wskbdvar.h>
124: #include <dev/wscons/wsksymdef.h>
125: #include <dev/wscons/wsksymvar.h>
126:
127: struct gsckbd_internal {
128: int t_isconsole;
129: pckbc_tag_t t_kbctag;
130: pckbc_slot_t t_kbcslot;
131:
132: int t_lastchar;
133: int t_extended;
134: int t_releasing;
135: int t_extended1;
136:
137: struct gsckbd_softc *t_sc; /* back pointer */
138: };
139:
140: struct gsckbd_softc {
141: struct device sc_dev;
142:
143: struct gsckbd_internal *id;
144: int sc_enabled;
145:
146: int sc_ledstate;
147:
148: struct device *sc_wskbddev;
149: #ifdef WSDISPLAY_COMPAT_RAWKBD
150: int rawkbd;
151: #endif
152: };
153:
154: int gsckbd_is_console(pckbc_tag_t, pckbc_slot_t);
155:
156: int gsckbdprobe(struct device *, void *, void *);
157: void gsckbdattach(struct device *, struct device *, void *);
158:
159: struct cfdriver gsckbd_cd = {
160: NULL, "gsckbd", DV_DULL
161: };
162:
163: struct cfattach gsckbd_ca = {
164: sizeof(struct gsckbd_softc), gsckbdprobe, gsckbdattach,
165: };
166:
167: int gsckbd_enable(void *, int);
168: void gsckbd_set_leds(void *, int);
169: int gsckbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
170:
171: const struct wskbd_accessops gsckbd_accessops = {
172: gsckbd_enable,
173: gsckbd_set_leds,
174: gsckbd_ioctl,
175: };
176:
177: void gsckbd_cngetc(void *, u_int *, int *);
178: void gsckbd_cnpollc(void *, int);
179:
180: const struct wskbd_consops gsckbd_consops = {
181: gsckbd_cngetc,
182: gsckbd_cnpollc,
183: NULL
184: };
185:
186: const struct wskbd_mapdata gsckbd_keymapdata = {
187: gsckbd_keydesctab, /* XXX */
188: #ifdef GSCKBD_LAYOUT
189: GSCKBD_LAYOUT,
190: #else
191: KB_US,
192: #endif
193: };
194:
195: int gsckbd_init(struct gsckbd_internal *, pckbc_tag_t, pckbc_slot_t,
196: int);
197: void gsckbd_input(void *, int);
198:
199: static int gsckbd_decode(struct gsckbd_internal *, int,
200: u_int *, int *);
201: static int gsckbd_led_encode(int);
202: static int gsckbd_led_decode(int);
203:
204: struct gsckbd_internal gsckbd_consdata;
205:
206: int
207: gsckbd_is_console(tag, slot)
208: pckbc_tag_t tag;
209: pckbc_slot_t slot;
210: {
211: return (gsckbd_consdata.t_isconsole &&
212: (tag == gsckbd_consdata.t_kbctag) &&
213: (slot == gsckbd_consdata.t_kbcslot));
214: }
215:
216: /*
217: * these are both EXTREMELY bad jokes
218: */
219: int
220: gsckbdprobe(parent, match, aux)
221: struct device *parent;
222: void *match;
223: void *aux;
224: {
225: struct cfdata *cf = match;
226: struct pckbc_attach_args *pa = aux;
227: u_char cmd[1], resp[1];
228: int res;
229:
230: /*
231: * XXX There are rumours that a keyboard can be connected
232: * to the aux port as well. For me, this didn't work.
233: * For further experiments, allow it if explicitly
234: * wired in the config file.
235: */
236: if ((pa->pa_slot != PCKBC_KBD_SLOT) &&
237: (cf->cf_loc[PCKBCCF_SLOT] == PCKBCCF_SLOT_DEFAULT))
238: return (0);
239:
240: /* Flush any garbage. */
241: pckbc_flush(pa->pa_tag, pa->pa_slot);
242:
243: /* Reset the keyboard. */
244: cmd[0] = KBC_RESET;
245: res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 1, resp, 1);
246: if (res) {
247: #ifdef DEBUG
248: printf("gsckbdprobe: reset error %d\n", res);
249: #endif
250: /*
251: * There is probably no keyboard connected.
252: * Let the probe succeed if the keyboard is used
253: * as console input - it can be connected later.
254: */
255: return (gsckbd_is_console(pa->pa_tag, pa->pa_slot) ? 1 : 0);
256: }
257: if (resp[0] != KBR_RSTDONE) {
258: printf("gsckbdprobe: reset response 0x%x\n", resp[0]);
259: return (0);
260: }
261:
262: /*
263: * Some keyboards seem to leave a second ack byte after the reset.
264: * This is kind of stupid, but we account for them anyway by just
265: * flushing the buffer.
266: */
267: pckbc_flush(pa->pa_tag, pa->pa_slot);
268:
269: return (2);
270: }
271:
272: void
273: gsckbdattach(parent, self, aux)
274: struct device *parent, *self;
275: void *aux;
276: {
277: struct gsckbd_softc *sc = (void *)self;
278: struct pckbc_attach_args *pa = aux;
279: int isconsole;
280: struct wskbddev_attach_args a;
281: u_char cmd[1];
282:
283: printf("\n");
284:
285: isconsole = gsckbd_is_console(pa->pa_tag, pa->pa_slot);
286:
287: if (isconsole) {
288: sc->id = &gsckbd_consdata;
289: /*
290: * Some keyboards are not enabled after a reset,
291: * so make sure it is enabled now.
292: */
293: cmd[0] = KBC_ENABLE;
294: (void) pckbc_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
295: cmd, 1, 0, 0, 0);
296: sc->sc_enabled = 1;
297: } else {
298: sc->id = malloc(sizeof(struct gsckbd_internal),
299: M_DEVBUF, M_WAITOK);
300: (void) gsckbd_init(sc->id, pa->pa_tag, pa->pa_slot, 0);
301:
302: /* no interrupts until enabled */
303: cmd[0] = KBC_DISABLE;
304: (void) pckbc_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
305: cmd, 1, 0, 0, 0);
306: sc->sc_enabled = 0;
307: }
308:
309: sc->id->t_sc = sc;
310:
311: pckbc_set_inputhandler(sc->id->t_kbctag, sc->id->t_kbcslot,
312: gsckbd_input, sc, sc->sc_dev.dv_xname);
313:
314: a.console = isconsole;
315:
316: a.keymap = &gsckbd_keymapdata;
317:
318: a.accessops = &gsckbd_accessops;
319: a.accesscookie = sc;
320:
321: /*
322: * Attach the wskbd, saving a handle to it.
323: * XXX XXX XXX
324: */
325: sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
326: }
327:
328: int
329: gsckbd_enable(v, on)
330: void *v;
331: int on;
332: {
333: struct gsckbd_softc *sc = v;
334: u_char cmd[1];
335: int res;
336:
337: if (on) {
338: if (sc->sc_enabled && !sc->id->t_isconsole)
339: return (EBUSY);
340:
341: pckbc_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 1);
342:
343: cmd[0] = KBC_ENABLE;
344: res = pckbc_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
345: cmd, 1, 0, NULL, 0);
346: if (res) {
347: printf("gsckbd_enable: command error\n");
348: return (res);
349: }
350:
351: sc->sc_enabled = 1;
352: } else {
353: if (sc->id->t_isconsole)
354: return (EBUSY);
355:
356: cmd[0] = KBC_DISABLE;
357: res = pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
358: cmd, 1, 0, 1, 0);
359: if (res) {
360: printf("gsckbd_disable: command error\n");
361: return (res);
362: }
363:
364: pckbc_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 0);
365:
366: sc->sc_enabled = 0;
367: }
368:
369: return (0);
370: }
371:
372: static int
373: gsckbd_decode(id, datain, type, dataout)
374: struct gsckbd_internal *id;
375: int datain;
376: u_int *type;
377: int *dataout;
378: {
379: int key;
380:
381: if (datain == KBR_BREAK) {
382: id->t_releasing = 1; /* next keycode is a release */
383: return 0;
384: }
385:
386: if (datain == KBR_EXTENDED0) {
387: id->t_extended = 0x80;
388: return 0;
389: } else if (datain == KBR_EXTENDED1) {
390: id->t_extended1 = 2;
391: return 0;
392: }
393:
394: /*
395: * Map extended keys to codes 128-254
396: * Note that we do not use (datain & 0x7f) because function key
397: * F7 produces non-extended 0x83 code. Sucker.
398: */
399: key = datain | id->t_extended;
400: id->t_extended = 0;
401:
402: /*
403: * process BREAK sequence (EXT1 14 77):
404: * map to (unused) code 7F
405: */
406: if (id->t_extended1 == 2 && datain == 0x14) {
407: id->t_extended1 = 1;
408: return 0;
409: } else if (id->t_extended1 == 1 && datain == 0x77) {
410: id->t_extended1 = 0;
411: key = 0x7f;
412: } else if (id->t_extended1 > 0) {
413: id->t_extended1 = 0;
414: }
415:
416: if (id->t_releasing) {
417: id->t_releasing = 0;
418: *type = WSCONS_EVENT_KEY_UP;
419: *dataout = key;
420: id->t_lastchar = 0;
421: } else {
422: /* Always ignore typematic keys */
423: if (key == id->t_lastchar)
424: return 0;
425: *dataout = id->t_lastchar = key;
426: *type = WSCONS_EVENT_KEY_DOWN;
427: }
428:
429: return 1;
430: }
431:
432: int
433: gsckbd_init(t, kbctag, kbcslot, console)
434: struct gsckbd_internal *t;
435: pckbc_tag_t kbctag;
436: pckbc_slot_t kbcslot;
437: int console;
438: {
439: bzero(t, sizeof(struct gsckbd_internal));
440:
441: t->t_isconsole = console;
442: t->t_kbctag = kbctag;
443: t->t_kbcslot = kbcslot;
444:
445: return (0);
446: }
447:
448: static int
449: gsckbd_led_encode(led)
450: int led;
451: {
452: int res;
453:
454: res = 0;
455:
456: if (led & WSKBD_LED_SCROLL)
457: res |= 0x01;
458: if (led & WSKBD_LED_NUM)
459: res |= 0x02;
460: if (led & WSKBD_LED_CAPS)
461: res |= 0x04;
462: return(res);
463: }
464:
465: static int
466: gsckbd_led_decode(led)
467: int led;
468: {
469: int res;
470:
471: res = 0;
472: if (led & 0x01)
473: res |= WSKBD_LED_SCROLL;
474: if (led & 0x02)
475: res |= WSKBD_LED_NUM;
476: if (led & 0x04)
477: res |= WSKBD_LED_CAPS;
478: return(res);
479: }
480:
481: void
482: gsckbd_set_leds(v, leds)
483: void *v;
484: int leds;
485: {
486: struct gsckbd_softc *sc = v;
487: u_char cmd[2];
488:
489: cmd[0] = KBC_MODEIND;
490: cmd[1] = gsckbd_led_encode(leds);
491: sc->sc_ledstate = cmd[1];
492:
493: pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
494: cmd, 2, 0, 0, 0);
495: }
496:
497: /*
498: * Got a console receive interrupt -
499: * the console processor wants to give us a character.
500: */
501: void
502: gsckbd_input(vsc, data)
503: void *vsc;
504: int data;
505: {
506: struct gsckbd_softc *sc = vsc;
507: int type, key;
508:
509: #ifdef WSDISPLAY_COMPAT_RAWKBD
510: if (sc->rawkbd) {
511: char d = data;
512: wskbd_rawinput(sc->sc_wskbddev, &d, 1);
513: return;
514: }
515: #endif
516: if (gsckbd_decode(sc->id, data, &type, &key))
517: wskbd_input(sc->sc_wskbddev, type, key);
518: }
519:
520: int
521: gsckbd_ioctl(v, cmd, data, flag, p)
522: void *v;
523: u_long cmd;
524: caddr_t data;
525: int flag;
526: struct proc *p;
527: {
528: struct gsckbd_softc *sc = v;
529:
530: switch (cmd) {
531: case WSKBDIO_GTYPE:
532: *(int *)data = WSKBD_TYPE_GSC;
533: return 0;
534: case WSKBDIO_SETLEDS:
535: {
536: char cmd[2];
537: int res;
538: cmd[0] = KBC_MODEIND;
539: cmd[1] = gsckbd_led_encode(*(int *)data);
540: sc->sc_ledstate = cmd[1];
541: res = pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
542: cmd, 2, 0, 1, 0);
543: return (res);
544: }
545: case WSKBDIO_GETLEDS:
546: *(int *)data = gsckbd_led_decode(sc->sc_ledstate);
547: return (0);
548: #ifdef WSDISPLAY_COMPAT_RAWKBD
549: case WSKBDIO_SETMODE:
550: sc->rawkbd = (*(int *)data == WSKBD_RAW);
551: return (0);
552: #endif
553: }
554: return -1;
555: }
556:
557: int
558: gsckbd_cnattach(kbctag, kbcslot)
559: pckbc_tag_t kbctag;
560: int kbcslot;
561: {
562: char cmd[1];
563: int res;
564:
565: res = gsckbd_init(&gsckbd_consdata, kbctag, kbcslot, 1);
566: #if 0 /* we allow the console to be attached if no keyboard is present */
567: if (res)
568: return (res);
569: #endif
570:
571: /* Just to be sure. */
572: cmd[0] = KBC_ENABLE;
573: res = pckbc_poll_cmd(kbctag, kbcslot, cmd, 1, 0, 0, 0);
574: #if 0
575: if (res)
576: return (res);
577: #endif
578:
579: wskbd_cnattach(&gsckbd_consops, &gsckbd_consdata, &gsckbd_keymapdata);
580:
581: return (0);
582: }
583:
584: /* ARGSUSED */
585: void
586: gsckbd_cngetc(v, type, data)
587: void *v;
588: u_int *type;
589: int *data;
590: {
591: struct gsckbd_internal *t = v;
592: int val;
593:
594: for (;;) {
595: val = pckbc_poll_data(t->t_kbctag, t->t_kbcslot);
596: if ((val != -1) && gsckbd_decode(t, val, type, data))
597: return;
598: }
599: }
600:
601: void
602: gsckbd_cnpollc(v, on)
603: void *v;
604: int on;
605: {
606: struct gsckbd_internal *t = v;
607:
608: pckbc_set_poll(t->t_kbctag, t->t_kbcslot, on);
609: }
CVSweb