Annotation of sys/arch/hp300/dev/dnkbd.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: dnkbd.c,v 1.15 2007/04/10 22:37:14 miod Exp $ */
2:
3: /*
4: * Copyright (c) 2005, Miodrag Vallat
5: * Copyright (c) 1997 Michael Smith. 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 AND CONTRIBUTORS ``AS IS'' AND
17: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26: * SUCH DAMAGE.
27: */
28:
29: /*
30: * Driver for the Apollo Domain keyboard and mouse.
31: */
32:
33: #include <sys/param.h>
34: #include <sys/systm.h>
35: #include <sys/device.h>
36: #include <sys/ioctl.h>
37: #include <sys/kernel.h>
38: #include <sys/timeout.h>
39:
40: #include <machine/autoconf.h>
41: #include <machine/bus.h>
42: #include <machine/cpu.h>
43:
44: #include <dev/cons.h>
45:
46: #include <dev/wscons/wsconsio.h>
47: #include <dev/wscons/wskbdvar.h>
48: #include <dev/wscons/wsksymdef.h>
49: #include <dev/wscons/wsksymvar.h>
50: #ifdef WSDISPLAY_COMPAT_RAWKBD
51: #include <dev/wscons/wskbdraw.h>
52: #endif
53: #include "wsmouse.h"
54: #if NWSMOUSE > 0
55: #include <dev/wscons/wsmousevar.h>
56: #endif
57:
58: #include <hp300/dev/apcireg.h>
59: #include <hp300/dev/apcivar.h>
60: #include <hp300/dev/dcareg.h>
61: #include <hp300/dev/dnkbdmap.h>
62: #include <hp300/dev/frodoreg.h>
63: #include <hp300/dev/frodovar.h>
64:
65: #include "hilkbd.h"
66:
67: /*
68: * Keyboard key codes
69: */
70:
71: #define DNKEY_CAPSLOCK 0x7e
72: #define DNKEY_REPEAT 0x7f
73: #define DNKEY_RELEASE 0x80
74: #define DNKEY_CHANNEL 0xff
75:
76: /*
77: * Channels
78: */
79:
80: #define DNCHANNEL_RESET 0x00
81: #define DNCHANNEL_KBD 0x01
82: #define DNCHANNEL_MOUSE 0x02
83:
84: /*
85: * Keyboard modes
86: */
87:
88: #define DNMODE_COOKED 0x00
89: #define DNMODE_RAW 0x01
90:
91: /*
92: * Keyboard commands
93: */
94:
95: #define DNCMD_PREFIX 0xff
96: #define DNCMD_COOKED DNMODE_COOKED
97: #define DNCMD_RAW DNMODE_RAW
98: #define DNCMD_IDENT_1 0x12
99: #define DNCMD_IDENT_2 0x21
100:
101: /*
102: * Bell commands
103: */
104:
105: #define DNCMD_BELL 0x21
106: #define DNCMD_BELL_ON 0x81
107: #define DNCMD_BELL_OFF 0x82
108:
109: /*
110: * Mouse status
111: */
112:
113: #define DNBUTTON_L 0x10
114: #define DNBUTTON_R 0x20
115: #define DNBUTTON_M 0x40
116:
117: struct dnkbd_softc {
118: struct device sc_dev;
119: struct isr sc_isr;
120: struct apciregs *sc_regs;
121:
122: int sc_flags;
123: #define SF_ENABLED 0x01 /* keyboard enabled */
124: #define SF_CONSOLE 0x02 /* keyboard is console */
125: #define SF_POLLING 0x04 /* polling mode */
126: #define SF_PLUGGED 0x08 /* keyboard has been seen plugged */
127: #define SF_ATTACHED 0x10 /* subdevices have been attached */
128: #define SF_MOUSE 0x20 /* mouse enabled */
129: #define SF_BELL 0x40 /* bell is active */
130: #define SF_BELL_TMO 0x80 /* bell stop timeout is scheduled */
131:
132: u_int sc_identlen;
133: #define MAX_IDENTLEN 32
134: char sc_ident[MAX_IDENTLEN];
135: kbd_t sc_layout;
136:
137: enum { STATE_KEYBOARD, STATE_MOUSE, STATE_CHANNEL, STATE_ECHO }
138: sc_state, sc_prevstate;
139: u_int sc_echolen;
140:
141: u_int8_t sc_mousepkt[3]; /* mouse packet being constructed */
142: u_int sc_mousepos; /* index in above */
143:
144: struct timeout sc_bellstop_tmo;
145:
146: struct device *sc_wskbddev;
147: #if NWSMOUSE > 0
148: struct device *sc_wsmousedev;
149: #endif
150:
151: #ifdef WSDISPLAY_COMPAT_RAWKBD
152: int sc_rawkbd;
153: int sc_nrep;
154: char sc_rep[2]; /* at most, one key */
155: struct timeout sc_rawrepeat_ch;
156: #define REP_DELAY1 400
157: #define REP_DELAYN 100
158: #endif
159: };
160:
161: int dnkbd_match(struct device *, void *, void *);
162: void dnkbd_attach(struct device *, struct device *, void *);
163:
164: struct cfdriver dnkbd_cd = {
165: NULL, "dnkbd", DV_DULL
166: };
167:
168: struct cfattach dnkbd_ca = {
169: sizeof(struct dnkbd_softc), dnkbd_match, dnkbd_attach
170: };
171:
172: int dnkbd_enable(void *, int);
173: void dnkbd_set_leds(void *, int);
174: int dnkbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
175:
176: const struct wskbd_accessops dnkbd_accessops = {
177: dnkbd_enable,
178: dnkbd_set_leds,
179: dnkbd_ioctl
180: };
181:
182: #if NWSMOUSE > 0
183: int dnmouse_enable(void *);
184: int dnmouse_ioctl(void *, u_long, caddr_t, int, struct proc *);
185: void dnmouse_disable(void *);
186:
187: const struct wsmouse_accessops dnmouse_accessops = {
188: dnmouse_enable,
189: dnmouse_ioctl,
190: dnmouse_disable
191: };
192: #endif
193:
194: void dnkbd_bell(void *, u_int, u_int, u_int);
195: void dnkbd_cngetc(void *, u_int *, int *);
196: void dnkbd_cnpollc(void *, int);
197:
198: const struct wskbd_consops dnkbd_consops = {
199: dnkbd_cngetc,
200: dnkbd_cnpollc,
201: dnkbd_bell
202: };
203:
204: struct wskbd_mapdata dnkbd_keymapdata = {
205: dnkbd_keydesctab,
206: #ifdef DNKBD_LAYOUT
207: DNKBD_LAYOUT
208: #else
209: KB_US
210: #endif
211: };
212:
213: typedef enum { EVENT_NONE, EVENT_KEYBOARD, EVENT_MOUSE } dnevent;
214:
215: void dnevent_kbd(struct dnkbd_softc *, int);
216: void dnevent_kbd_internal(struct dnkbd_softc *, int);
217: void dnevent_mouse(struct dnkbd_softc *, u_int8_t *);
218: void dnkbd_attach_subdevices(struct dnkbd_softc *);
219: void dnkbd_bellstop(void *);
220: void dnkbd_decode(int, u_int *, int *);
221: int dnkbd_init(struct apciregs *);
222: dnevent dnkbd_input(struct dnkbd_softc *, int);
223: int dnkbd_intr(void *);
224: int dnkbd_pollin(struct apciregs *, u_int);
225: int dnkbd_pollout(struct apciregs *, int);
226: int dnkbd_probe(struct dnkbd_softc *);
227: void dnkbd_rawrepeat(void *);
228: int dnkbd_send(struct apciregs *, const u_int8_t *, size_t);
229: int dnsubmatch_kbd(struct device *, void *, void *);
230: int dnsubmatch_mouse(struct device *, void *, void *);
231:
232: int
233: dnkbd_match(struct device *parent, void *match, void *aux)
234: {
235: struct frodo_attach_args *fa = aux;
236:
237: if (strcmp(fa->fa_name, dnkbd_cd.cd_name) != 0)
238: return (0);
239:
240: /* only attach to the first frodo port */
241: return (fa->fa_offset == FRODO_APCI_OFFSET(0));
242: }
243:
244: void
245: dnkbd_attach(struct device *parent, struct device *self, void *aux)
246: {
247: struct dnkbd_softc *sc = (struct dnkbd_softc *)self;
248: struct frodo_attach_args *fa = aux;
249:
250: printf(": ");
251:
252: sc->sc_regs = (struct apciregs *)IIOV(FRODO_BASE + fa->fa_offset);
253:
254: timeout_set(&sc->sc_bellstop_tmo, dnkbd_bellstop, sc);
255: #ifdef WSDISPLAY_COMPAT_RAWKBD
256: timeout_set(&sc->sc_rawrepeat_ch, dnkbd_rawrepeat, sc);
257: #endif
258:
259: /* reset the port */
260: apciinit(sc->sc_regs, 1200, CFCR_8BITS | CFCR_PEVEN | CFCR_PENAB);
261:
262: sc->sc_isr.isr_func = dnkbd_intr;
263: sc->sc_isr.isr_arg = sc;
264: sc->sc_isr.isr_priority = IPL_TTY;
265: frodo_intr_establish(parent, fa->fa_line, &sc->sc_isr, self->dv_xname);
266:
267: /* probe for keyboard */
268: if (dnkbd_probe(sc) != 0) {
269: printf("no keyboard\n");
270: return;
271: }
272:
273: dnkbd_attach_subdevices(sc);
274: }
275:
276: void
277: dnkbd_attach_subdevices(struct dnkbd_softc *sc)
278: {
279: struct wskbddev_attach_args ka;
280: #if NWSMOUSE > 0
281: struct wsmousedev_attach_args ma;
282: #endif
283: #if NHILKBD > 0
284: extern int hil_is_console;
285: #endif
286: extern struct consdev wsdisplay_cons;
287:
288: /*
289: * If both hilkbd and dnkbd are configured, prefer the Domain
290: * keyboard as console (if we are here, we know the keyboard is
291: * plugged), unless the console keyboard has been claimed already
292: * (i.e. late hotplug with hil keyboard plugged first).
293: */
294: if (cn_tab == &wsdisplay_cons) {
295: #if NHILKBD > 0
296: if (hil_is_console == -1) {
297: ka.console = 1;
298: hil_is_console = 0;
299: } else
300: ka.console = 0;
301: #else
302: ka.console = 1;
303: #endif
304: } else
305: ka.console = 0;
306:
307: ka.keymap = &dnkbd_keymapdata;
308: ka.accessops = &dnkbd_accessops;
309: ka.accesscookie = sc;
310: #ifndef DKKBD_LAYOUT
311: dnkbd_keymapdata.layout = sc->sc_layout;
312: #endif
313:
314: if (ka.console) {
315: sc->sc_flags = SF_PLUGGED | SF_CONSOLE | SF_ENABLED;
316: wskbd_cnattach(&dnkbd_consops, sc, &dnkbd_keymapdata);
317: } else {
318: sc->sc_flags = SF_PLUGGED;
319: }
320:
321: sc->sc_wskbddev = config_found_sm(&sc->sc_dev, &ka, wskbddevprint,
322: dnsubmatch_kbd);
323:
324: #if NWSMOUSE > 0
325: ma.accessops = &dnmouse_accessops;
326: ma.accesscookie = sc;
327:
328: sc->sc_wsmousedev = config_found_sm(&sc->sc_dev, &ma, wsmousedevprint,
329: dnsubmatch_mouse);
330: #endif
331:
332: SET(sc->sc_flags, SF_ATTACHED);
333: }
334:
335: int
336: dnsubmatch_kbd(struct device *parent, void *match, void *aux)
337: {
338: struct cfdata *cf = match;
339: extern struct cfdriver wskbd_cd;
340:
341: if (strcmp(cf->cf_driver->cd_name, wskbd_cd.cd_name) != 0)
342: return (0);
343:
344: return ((*cf->cf_attach->ca_match)(parent, cf, aux));
345: }
346:
347: #if NWSMOUSE > 0
348: int
349: dnsubmatch_mouse(struct device *parent, void *match, void *aux)
350: {
351: struct cfdata *cf = match;
352: extern struct cfdriver wsmouse_cd;
353:
354: if (strcmp(cf->cf_driver->cd_name, wsmouse_cd.cd_name) != 0)
355: return (0);
356:
357: return ((*cf->cf_attach->ca_match)(parent, cf, aux));
358: }
359: #endif
360:
361: int
362: dnkbd_probe(struct dnkbd_softc *sc)
363: {
364: int dat, rc, flags;
365: u_int8_t cmdbuf[2];
366: char rspbuf[MAX_IDENTLEN], *word, *end;
367: u_int i;
368: int s;
369:
370: s = spltty();
371: flags = sc->sc_flags;
372: SET(sc->sc_flags, SF_POLLING);
373: sc->sc_state = STATE_CHANNEL;
374: splx(s);
375:
376: /*
377: * Switch keyboard to raw mode.
378: */
379: cmdbuf[0] = DNCMD_RAW;
380: rc = dnkbd_send(sc->sc_regs, cmdbuf, 1);
381: if (rc != 0)
382: goto out;
383:
384: /*
385: * Send the identify command.
386: */
387: cmdbuf[0] = DNCMD_IDENT_1;
388: cmdbuf[1] = DNCMD_IDENT_2;
389: rc = dnkbd_send(sc->sc_regs, cmdbuf, 2);
390: if (rc != 0)
391: goto out;
392:
393: for (i = 0; ; i++) {
394: dat = dnkbd_pollin(sc->sc_regs, 10000);
395: if (dat == -1)
396: break;
397:
398: if (i < sizeof(rspbuf))
399: rspbuf[i] = dat;
400: }
401:
402: if (i > sizeof(rspbuf) || i == 0) {
403: printf("%s: unexpected identify string length %d\n",
404: sc->sc_dev.dv_xname, i);
405: rc = ENXIO;
406: goto out;
407: }
408:
409: /*
410: * Make sure the identification string is NULL terminated
411: * (overwriting the keyboard mode byte if necessary).
412: */
413: i--;
414: if (rspbuf[i] != 0)
415: rspbuf[i] = 0;
416:
417: /*
418: * Now display the identification strings, if they changed.
419: */
420: if (i != sc->sc_identlen || bcmp(rspbuf, sc->sc_ident, i) != 0) {
421: sc->sc_layout = KB_US;
422: sc->sc_identlen = i;
423: bcopy(rspbuf, sc->sc_ident, i);
424:
425: if (cold == 0)
426: printf("%s: ", sc->sc_dev.dv_xname);
427: printf("model ");
428: word = rspbuf;
429: for (i = 0; i < 3; i++) {
430: end = strchr(word, '\r');
431: if (end == NULL)
432: break;
433: *end++ = '\0';
434: printf("<%s> ", word);
435: /*
436: * Parse the layout code if applicable
437: */
438: if (i == 1 && *word++ == '3') {
439: if (*word == '-')
440: word++;
441: switch (*word) {
442: #if 0
443: default:
444: case ' ':
445: sc->sc_layout = KB_US;
446: break;
447: #endif
448: case 'a':
449: sc->sc_layout = KB_DE;
450: break;
451: case 'b':
452: sc->sc_layout = KB_FR;
453: break;
454: case 'c':
455: sc->sc_layout = KB_DK;
456: break;
457: case 'd':
458: sc->sc_layout = KB_SV;
459: break;
460: case 'e':
461: sc->sc_layout = KB_UK;
462: break;
463: case 'f':
464: sc->sc_layout = KB_JP;
465: break;
466: case 'g':
467: sc->sc_layout = KB_SG;
468: break;
469: }
470: }
471: word = end;
472: }
473: printf("\n");
474: }
475:
476: /*
477: * Ready to work, the default channel is the keyboard.
478: */
479: sc->sc_state = STATE_KEYBOARD;
480:
481: out:
482: s = spltty();
483: sc->sc_flags = flags;
484: splx(s);
485:
486: return (rc);
487: }
488:
489: /*
490: * State machine.
491: *
492: * In raw mode, the keyboard may feed us the following sequences:
493: * - on the keyboard channel:
494: * + a raw key code, in the range 0x01-0x7e, or'ed with 0x80 if key release.
495: * + the key repeat sequence 0x7f.
496: * - on the mouse channel:
497: * + a 3 byte mouse sequence (buttons state, dx move, dy move).
498: * - at any time:
499: * + a 2 byte channel sequence (0xff followed by the channel number) telling
500: * us which device the following input will come from.
501: * + if we get 0xff but an invalid channel number, this is a command echo.
502: * Currently we only handle this for bell commands, which size are known.
503: * Other commands are issued through dnkbd_send() which ``eats'' the echo.
504: *
505: * Older keyboards reset the channel to the keyboard (by sending ff 01) after
506: * every mouse packet.
507: */
508:
509: dnevent
510: dnkbd_input(struct dnkbd_softc *sc, int dat)
511: {
512: dnevent event = EVENT_NONE;
513:
514: switch (sc->sc_state) {
515: case STATE_KEYBOARD:
516: switch (dat) {
517: case DNKEY_REPEAT:
518: /*
519: * We ignore event repeats, as wskbd does its own
520: * soft repeat processing.
521: */
522: break;
523: case DNKEY_CHANNEL:
524: sc->sc_prevstate = sc->sc_state;
525: sc->sc_state = STATE_CHANNEL;
526: break;
527: default:
528: event = EVENT_KEYBOARD;
529: break;
530: }
531: break;
532:
533: case STATE_MOUSE:
534: if (dat == DNKEY_CHANNEL && sc->sc_mousepos == 0) {
535: sc->sc_prevstate = sc->sc_state;
536: sc->sc_state = STATE_CHANNEL;
537: } else {
538: sc->sc_mousepkt[sc->sc_mousepos++] = dat;
539: if (sc->sc_mousepos == sizeof(sc->sc_mousepkt)) {
540: sc->sc_mousepos = 0;
541: event = EVENT_MOUSE;
542: }
543: }
544: break;
545:
546: case STATE_CHANNEL:
547: switch (dat) {
548: case DNKEY_CHANNEL:
549: /*
550: * During hotplug, we might get spurious 0xff bytes.
551: * Ignore them.
552: */
553: break;
554: case DNCHANNEL_RESET:
555: /*
556: * Identify the keyboard again. This will switch it to
557: * raw mode again. If this fails, we'll consider the
558: * keyboard as unplugged (to ignore further events until
559: * a successfull reset).
560: */
561: if (dnkbd_probe(sc) == 0) {
562: /*
563: * We need to attach wskbd and wsmouse children
564: * if this is a live first plug.
565: */
566: if (!ISSET(sc->sc_flags, SF_ATTACHED))
567: dnkbd_attach_subdevices(sc);
568: SET(sc->sc_flags, SF_PLUGGED);
569: } else {
570: CLR(sc->sc_flags, SF_PLUGGED);
571: }
572:
573: sc->sc_state = STATE_KEYBOARD;
574: break;
575: case DNCHANNEL_KBD:
576: sc->sc_state = STATE_KEYBOARD;
577: break;
578: case DNCHANNEL_MOUSE:
579: sc->sc_state = STATE_MOUSE;
580: sc->sc_mousepos = 0; /* just in case */
581: break;
582: case DNCMD_BELL:
583: /*
584: * We are getting a bell command echoed to us.
585: * Ignore it.
586: */
587: sc->sc_state = STATE_ECHO;
588: sc->sc_echolen = 1; /* one byte to follow */
589: break;
590: default:
591: printf("%s: unexpected channel byte %02x\n",
592: sc->sc_dev.dv_xname, dat);
593: break;
594: }
595: break;
596:
597: case STATE_ECHO:
598: if (--sc->sc_echolen == 0) {
599: /* get back to the state we were in before the echo */
600: sc->sc_state = sc->sc_prevstate;
601: }
602: break;
603: }
604:
605: return (event);
606: }
607:
608: /*
609: * Event breakers.
610: */
611:
612: void
613: dnkbd_decode(int keycode, u_int *type, int *key)
614: {
615: *type = (keycode & DNKEY_RELEASE) ?
616: WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
617: *key = (keycode & ~DNKEY_RELEASE);
618: }
619:
620: void
621: dnevent_kbd(struct dnkbd_softc *sc, int dat)
622: {
623: if (!ISSET(sc->sc_flags, SF_PLUGGED))
624: return;
625:
626: if (sc->sc_wskbddev == NULL)
627: return;
628:
629: if (!ISSET(sc->sc_flags, SF_ENABLED))
630: return;
631:
632: /*
633: * Even in raw mode, the caps lock key is treated specially:
634: * first key press causes event 0x7e, release causes no event;
635: * then a new key press causes nothing, and release causes
636: * event 0xfe. Moreover, while kept down, it does not produce
637: * repeat events.
638: *
639: * So the best we can do is fake the missed events, but this
640: * will not allow the capslock key to be remapped as a control
641: * key since it will not be possible to chord it with anything.
642: */
643: dnevent_kbd_internal(sc, dat);
644: if ((dat & ~DNKEY_RELEASE) == DNKEY_CAPSLOCK)
645: dnevent_kbd_internal(sc, dat ^ DNKEY_RELEASE);
646: }
647:
648: void
649: dnevent_kbd_internal(struct dnkbd_softc *sc, int dat)
650: {
651: u_int type;
652: int key;
653: int s;
654:
655: dnkbd_decode(dat, &type, &key);
656:
657: #ifdef WSDISPLAY_COMPAT_RAWKBD
658: if (sc->sc_rawkbd) {
659: u_char cbuf[2];
660: int c, j = 0;
661:
662: c = dnkbd_raw[key];
663: if (c != RAWKEY_Null) {
664: /* fake extended scancode if necessary */
665: if (c & 0x80)
666: cbuf[j++] = 0xe0;
667: cbuf[j] = c & 0x7f;
668: if (type == WSCONS_EVENT_KEY_UP)
669: cbuf[j] |= 0x80;
670: else {
671: /* remember pressed key for autorepeat */
672: bcopy(cbuf, sc->sc_rep, sizeof(sc->sc_rep));
673: }
674: j++;
675: }
676:
677: if (j != 0) {
678: s = spltty();
679: wskbd_rawinput(sc->sc_wskbddev, cbuf, j);
680: splx(s);
681: timeout_del(&sc->sc_rawrepeat_ch);
682: sc->sc_nrep = j;
683: timeout_add(&sc->sc_rawrepeat_ch,
684: (hz * REP_DELAY1) / 1000);
685: }
686: } else
687: #endif
688: {
689: s = spltty();
690: wskbd_input(sc->sc_wskbddev, type, key);
691: splx(s);
692: }
693: }
694:
695: #ifdef WSDISPLAY_COMPAT_RAWKBD
696: void
697: dnkbd_rawrepeat(void *v)
698: {
699: struct dnkbd_softc *sc = v;
700: int s;
701:
702: s = spltty();
703: wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep);
704: splx(s);
705:
706: timeout_add(&sc->sc_rawrepeat_ch, (hz * REP_DELAYN) / 1000);
707: }
708: #endif
709:
710: #if NWSMOUSE > 0
711: void
712: dnevent_mouse(struct dnkbd_softc *sc, u_int8_t *dat)
713: {
714: if (!ISSET(sc->sc_flags, SF_PLUGGED))
715: return;
716:
717: if (sc->sc_wsmousedev == NULL)
718: return;
719:
720: if (!ISSET(sc->sc_flags, SF_MOUSE))
721: return;
722:
723: /*
724: * First byte is button status. It has the 0x80 bit always set, and
725: * the next 3 bits are *cleared* when the mouse buttons are pressed.
726: */
727: #ifdef DEBUG
728: if (!ISSET(*dat, 0x80)) {
729: printf("%s: incorrect mouse packet %02x %02x %02x\n",
730: sc->sc_dev.dv_xname, dat[0], dat[1], dat[2]);
731: return;
732: }
733: #endif
734:
735: wsmouse_input(sc->sc_wsmousedev,
736: (~dat[0] & (DNBUTTON_L | DNBUTTON_M | DNBUTTON_R)) >> 4,
737: (int8_t)dat[1], (int8_t)dat[2], 0, 0, WSMOUSE_INPUT_DELTA);
738: }
739: #endif
740:
741: /*
742: * Low-level communication routines.
743: */
744:
745: int
746: dnkbd_pollin(struct apciregs *apci, u_int tries)
747: {
748: u_int cnt;
749:
750: for (cnt = tries; cnt != 0; cnt--) {
751: if (apci->ap_lsr & LSR_RXRDY)
752: break;
753: DELAY(10);
754: }
755:
756: if (cnt == 0)
757: return (-1);
758: else
759: return ((int)apci->ap_data);
760: }
761:
762: int
763: dnkbd_pollout(struct apciregs *apci, int dat)
764: {
765: u_int cnt;
766:
767: for (cnt = 10000; cnt != 0; cnt--) {
768: if (apci->ap_lsr & LSR_TXRDY)
769: break;
770: DELAY(10);
771: }
772: if (cnt == 0)
773: return (EBUSY);
774: else {
775: apci->ap_data = dat;
776: return (0);
777: }
778: }
779:
780: int
781: dnkbd_send(struct apciregs *apci, const u_int8_t *cmdbuf, size_t cmdlen)
782: {
783: int cnt, rc, dat;
784: u_int cmdpos;
785:
786: /* drain rxfifo */
787: for (cnt = 10; cnt != 0; cnt--) {
788: if (dnkbd_pollin(apci, 10) == -1)
789: break;
790: }
791: if (cnt == 0)
792: return (EBUSY);
793:
794: /* send command escape */
795: if ((rc = dnkbd_pollout(apci, DNCMD_PREFIX)) != 0)
796: return (rc);
797:
798: /* send command buffer */
799: for (cmdpos = 0; cmdpos < cmdlen; cmdpos++) {
800: if ((rc = dnkbd_pollout(apci, cmdbuf[cmdpos])) != 0)
801: return (rc);
802: }
803:
804: /* wait for command echo */
805: do {
806: dat = dnkbd_pollin(apci, 10000);
807: if (dat == -1)
808: return (EIO);
809: } while (dat != DNCMD_PREFIX);
810:
811: for (cmdpos = 0; cmdpos < cmdlen; cmdpos++) {
812: dat = dnkbd_pollin(apci, 10000);
813: if (dat != cmdbuf[cmdpos])
814: return (EIO);
815: }
816:
817: return (0);
818: }
819:
820: int
821: dnkbd_intr(void *v)
822: {
823: struct dnkbd_softc *sc = v;
824: struct apciregs *apci = sc->sc_regs;
825: u_int8_t iir, lsr, c;
826: int claimed = 0;
827:
828: for (;;) {
829: iir = apci->ap_iir;
830:
831: switch (iir & IIR_IMASK) {
832: case IIR_RLS:
833: /*
834: * Line status change. This should never happen,
835: * so silently ack the interrupt.
836: */
837: c = apci->ap_lsr;
838: break;
839:
840: case IIR_RXRDY:
841: case IIR_RXTOUT:
842: /*
843: * Data available. We process it byte by byte,
844: * unless we are doing polling work...
845: */
846: if (ISSET(sc->sc_flags, SF_POLLING)) {
847: return (1);
848: }
849:
850: for (;;) {
851: c = apci->ap_data;
852: switch (dnkbd_input(sc, c)) {
853: case EVENT_KEYBOARD:
854: dnevent_kbd(sc, c);
855: break;
856: #if NWSMOUSE > 0
857: case EVENT_MOUSE:
858: dnevent_mouse(sc, sc->sc_mousepkt);
859: break;
860: #endif
861: default: /* appease gcc */
862: break;
863: }
864: lsr = apci->ap_lsr & LSR_RCV_MASK;
865: if (lsr == 0)
866: break;
867: else if (lsr != LSR_RXRDY) {
868: /* ignore error */
869: break;
870: }
871: }
872: break;
873:
874: case IIR_TXRDY:
875: /*
876: * Transmit available. Since we do all our commands
877: * in polling mode, we do not need to do anything here.
878: */
879: break;
880:
881: default:
882: if (iir & IIR_NOPEND)
883: return (claimed);
884: /* FALLTHROUGH */
885:
886: case IIR_MLSC:
887: /*
888: * Modem status change. This should never happen,
889: * so silently ack the interrupt.
890: */
891: c = apci->ap_msr;
892: break;
893: }
894:
895: claimed = 1;
896: }
897: }
898:
899: /*
900: * Wskbd callbacks
901: */
902:
903: int
904: dnkbd_enable(void *v, int on)
905: {
906: struct dnkbd_softc *sc = v;
907:
908: if (on) {
909: if (ISSET(sc->sc_flags, SF_ENABLED))
910: return (EBUSY);
911: SET(sc->sc_flags, SF_ENABLED);
912: } else {
913: if (ISSET(sc->sc_flags, SF_CONSOLE))
914: return (EBUSY);
915: CLR(sc->sc_flags, SF_ENABLED);
916: }
917:
918: return (0);
919: }
920:
921: void
922: dnkbd_set_leds(void *v, int leds)
923: {
924: /*
925: * Not supported. There is only one LED on this keyboard, and
926: * is hardware tied to the caps lock key.
927: */
928: }
929:
930: int
931: dnkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
932: {
933: #ifdef WSDISPLAY_COMPAT_RAWKBD
934: struct dnkbd_softc *sc = v;
935: #endif
936:
937: switch (cmd) {
938: case WSKBDIO_GTYPE:
939: *(int *)data = WSKBD_TYPE_DOMAIN;
940: return (0);
941: case WSKBDIO_SETLEDS:
942: return (ENXIO);
943: case WSKBDIO_GETLEDS:
944: *(int *)data = 0;
945: return (0);
946: case WSKBDIO_COMPLEXBELL:
947: #define d ((struct wskbd_bell_data *)data)
948: dnkbd_bell(v, d->period, d->pitch, d->volume);
949: #undef d
950: return (0);
951: #ifdef WSDISPLAY_COMPAT_RAWKBD
952: case WSKBDIO_SETMODE:
953: sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
954: timeout_del(&sc->sc_rawrepeat_ch);
955: return (0);
956: #endif
957: }
958:
959: return (-1);
960: }
961:
962: #if NWSMOUSE > 0
963: /*
964: * Wsmouse callbacks
965: */
966:
967: int
968: dnmouse_enable(void *v)
969: {
970: struct dnkbd_softc *sc = v;
971:
972: if (ISSET(sc->sc_flags, SF_MOUSE))
973: return (EBUSY);
974: SET(sc->sc_flags, SF_MOUSE);
975:
976: return (0);
977: }
978:
979: int
980: dnmouse_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
981: {
982: #if 0
983: struct dnkbd_softc *sc = v;
984: #endif
985:
986: switch (cmd) {
987: case WSMOUSEIO_GTYPE:
988: *(int *)data = WSMOUSE_TYPE_DOMAIN;
989: return (0);
990: }
991:
992: return (-1);
993: }
994:
995: void
996: dnmouse_disable(void *v)
997: {
998: struct dnkbd_softc *sc = v;
999:
1000: CLR(sc->sc_flags, SF_MOUSE);
1001: }
1002: #endif
1003:
1004: /*
1005: * Console support
1006: */
1007:
1008: void
1009: dnkbd_cngetc(void *v, u_int *type, int *data)
1010: {
1011: static int lastdat = 0;
1012: struct dnkbd_softc *sc = v;
1013: int s;
1014: int dat;
1015:
1016: /* Take care of caps lock */
1017: if ((lastdat & ~DNKEY_RELEASE) == DNKEY_CAPSLOCK) {
1018: dat = lastdat ^ DNKEY_RELEASE;
1019: lastdat = 0;
1020: } else {
1021: for (;;) {
1022: s = splhigh();
1023: dat = dnkbd_pollin(sc->sc_regs, 10000);
1024: if (dat != -1) {
1025: if (dnkbd_input(sc, dat) == EVENT_KEYBOARD) {
1026: splx(s);
1027: break;
1028: }
1029: }
1030: splx(s);
1031: }
1032: lastdat = dat;
1033: }
1034:
1035: dnkbd_decode(dat, type, data);
1036: }
1037:
1038: void
1039: dnkbd_cnpollc(void *v, int on)
1040: {
1041: struct dnkbd_softc *sc = v;
1042:
1043: if (on)
1044: SET(sc->sc_flags, SF_POLLING);
1045: else
1046: CLR(sc->sc_flags, SF_POLLING);
1047: }
1048:
1049: /*
1050: * Bell routines.
1051: */
1052: void
1053: dnkbd_bell(void *v, u_int period, u_int pitch, u_int volume)
1054: {
1055: struct dnkbd_softc *sc = v;
1056: int ticks, s;
1057:
1058: s = spltty();
1059:
1060: if (pitch == 0 || period == 0 || volume == 0) {
1061: if (ISSET(sc->sc_flags, SF_BELL_TMO)) {
1062: timeout_del(&sc->sc_bellstop_tmo);
1063: dnkbd_bellstop(v);
1064: }
1065: } else {
1066: ticks = (period * hz) / 1000;
1067: if (ticks <= 0)
1068: ticks = 1;
1069:
1070: if (!ISSET(sc->sc_flags, SF_BELL)) {
1071: dnkbd_pollout(sc->sc_regs, DNCMD_PREFIX);
1072: dnkbd_pollout(sc->sc_regs, DNCMD_BELL);
1073: dnkbd_pollout(sc->sc_regs, DNCMD_BELL_ON);
1074: SET(sc->sc_flags, SF_BELL);
1075: }
1076:
1077: if (ISSET(sc->sc_flags, SF_BELL_TMO))
1078: timeout_del(&sc->sc_bellstop_tmo);
1079: timeout_add(&sc->sc_bellstop_tmo, ticks);
1080: SET(sc->sc_flags, SF_BELL_TMO);
1081: }
1082:
1083: splx(s);
1084: }
1085:
1086: void
1087: dnkbd_bellstop(void *v)
1088: {
1089: struct dnkbd_softc *sc = v;
1090: int s;
1091:
1092: s = spltty();
1093:
1094: dnkbd_pollout(sc->sc_regs, DNCMD_PREFIX);
1095: dnkbd_pollout(sc->sc_regs, DNCMD_BELL);
1096: dnkbd_pollout(sc->sc_regs, DNCMD_BELL_OFF);
1097: CLR(sc->sc_flags, SF_BELL);
1098: CLR(sc->sc_flags, SF_BELL_TMO);
1099:
1100: splx(s);
1101: }
CVSweb