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