dnkbd.c revision 1.12 1 /* $NetBSD: dnkbd.c,v 1.12 2021/04/24 23:36:37 thorpej 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 dnkbd_enable,
212 dnkbd_set_leds,
213 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 dnkbd_cngetc,
234 dnkbd_cnpollc,
235 dnkbd_bell
236 };
237
238 static struct wskbd_mapdata dnkbd_keymapdata = {
239 dnkbd_keydesctab,
240 #ifdef DNKBD_LAYOUT
241 DNKBD_LAYOUT
242 #else
243 KB_US
244 #endif
245 };
246
247 typedef enum { EVENT_NONE, EVENT_KEYBOARD, EVENT_MOUSE } dnevent;
248
249 #define APCIBRD(x) (500000 / (x))
250
251 static void dnevent_kbd(struct dnkbd_softc *, int);
252 static void dnevent_kbd_internal(struct dnkbd_softc *, int);
253 static void dnevent_mouse(struct dnkbd_softc *, uint8_t *);
254 static void dnkbd_attach_subdevices(struct dnkbd_softc *);
255 static void dnkbd_bellstop(void *);
256 static void dnkbd_decode(int, u_int *, int *);
257 static dnevent dnkbd_input(struct dnkbd_softc *, int);
258 static int dnkbd_intr(void *);
259 static int dnkbd_pollin(struct dnkbd_softc *, u_int);
260 static int dnkbd_pollout(struct dnkbd_softc *, int);
261 static int dnkbd_probe(struct dnkbd_softc *);
262 static int dnkbd_send(struct dnkbd_softc *, const uint8_t *, size_t);
263 static void dnkbd_break(struct dnkbd_softc *, int);
264
265 int
266 dnkbd_match(device_t parent, cfdata_t cf, void *aux)
267 {
268 struct frodo_attach_args *fa = aux;
269
270 if (strcmp(fa->fa_name, dnkbd_cd.cd_name) != 0)
271 return 0;
272
273 if (machineid == HP_382) {
274 /* 382 has frodo but no Domain keyboard connector. */
275 return 0;
276 }
277
278 /* only attach to the first frodo port */
279 return fa->fa_offset == FRODO_APCI_OFFSET(0);
280 }
281
282 void
283 dnkbd_attach(device_t parent, device_t self, void *aux)
284 {
285 struct dnkbd_softc *sc = device_private(self);
286 struct frodo_attach_args *fa = aux;
287
288 aprint_normal(": ");
289
290 sc->sc_dev = self;
291 sc->sc_bst = fa->fa_bst;
292 if (bus_space_map(sc->sc_bst, fa->fa_base + fa->fa_offset,
293 FRODO_APCISPACE, 0, &sc->sc_bsh) != 0) {
294 aprint_error(": can't map i/o space\n");
295 return;
296 }
297
298 callout_init(&sc->sc_bellstop_tmo, 0);
299 callout_setfunc(&sc->sc_bellstop_tmo, dnkbd_bellstop, sc);
300
301 /* reset the port */
302 dnkbd_init(sc, 1200, LCR_8BITS | LCR_PEVEN | LCR_PENAB);
303
304 frodo_intr_establish(parent, dnkbd_intr, sc, fa->fa_line, IPL_VM);
305
306 /* send break to reset keyboard state */
307 dnkbd_break(sc, 1);
308 delay(10 * 1000); /* 10ms for 12 space bits */
309 dnkbd_break(sc, 0);
310 delay(10 * 1000);
311
312 /* probe for keyboard */
313 if (dnkbd_probe(sc) != 0) {
314 aprint_normal("no keyboard\n");
315 return;
316 }
317
318 dnkbd_attach_subdevices(sc);
319 }
320
321 void
322 dnkbd_init(struct dnkbd_softc *sc, uint16_t rate, uint16_t lctl)
323 {
324 bus_space_tag_t bst;
325 bus_space_handle_t bsh;
326 u_int divisor;
327
328 bst = sc->sc_bst;
329 bsh = sc->sc_bsh;
330
331 divisor = APCIBRD(rate);
332 bus_space_write_1(bst, bsh, com_lctl, LCR_DLAB);
333 bus_space_write_1(bst, bsh, com_dlbl, divisor & 0xff);
334 bus_space_write_1(bst, bsh, com_dlbh, (divisor >> 8) & 0xff);
335 bus_space_write_1(bst, bsh, com_lctl, lctl);
336 bus_space_write_1(bst, bsh, com_ier, IER_ERXRDY | IER_ETXRDY);
337 bus_space_write_1(bst, bsh, com_fifo,
338 FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_1);
339 bus_space_write_1(bst, bsh, com_mcr, MCR_DTR | MCR_RTS);
340
341 delay(100);
342 (void)bus_space_read_1(bst, bsh, com_iir);
343 }
344
345 void
346 dnkbd_attach_subdevices(struct dnkbd_softc *sc)
347 {
348 struct wskbddev_attach_args ka;
349 #if NWSMOUSE > 0
350 struct wsmousedev_attach_args ma;
351 #endif
352 #if NHILKBD > 0
353 extern int hil_is_console;
354 #endif
355
356 /*
357 * If both hilkbd and dnkbd are configured, prefer the Domain
358 * keyboard as console (if we are here, we know the keyboard is
359 * plugged), unless the console keyboard has been claimed already
360 * (i.e. late hotplug with hil keyboard plugged first).
361 */
362 #if NWSDISPLAY > 0
363 if (cn_tab->cn_putc == wsdisplay_cnputc) {
364 #if NHILKBD > 0
365 if (hil_is_console == -1) {
366 ka.console = 1;
367 hil_is_console = 0;
368 } else
369 ka.console = 0;
370 #else
371 ka.console = 1;
372 #endif
373 } else
374 #endif
375 {
376 ka.console = 0;
377 }
378
379 ka.keymap = &dnkbd_keymapdata;
380 ka.accessops = &dnkbd_accessops;
381 ka.accesscookie = sc;
382 #ifndef DKKBD_LAYOUT
383 dnkbd_keymapdata.layout = sc->sc_layout;
384 #endif
385
386 if (ka.console) {
387 sc->sc_flags = SF_PLUGGED | SF_CONSOLE | SF_ENABLED;
388 wskbd_cnattach(&dnkbd_consops, sc, &dnkbd_keymapdata);
389 } else {
390 sc->sc_flags = SF_PLUGGED;
391 }
392
393 sc->sc_wskbddev = config_found(sc->sc_dev, &ka, wskbddevprint,
394 CFARG_IATTR, "wskbddev",
395 CFARG_EOL);
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 CFARG_IATTR, "wsmousedev",
403 CFARG_EOL);
404 #endif
405
406 SET(sc->sc_flags, SF_ATTACHED);
407 }
408
409 int
410 dnkbd_probe(struct dnkbd_softc *sc)
411 {
412 int dat, rc, flags;
413 uint8_t cmdbuf[2];
414 char rspbuf[MAX_IDENTLEN], *word, *end;
415 u_int i;
416 int s;
417
418 s = spltty();
419 flags = sc->sc_flags;
420 SET(sc->sc_flags, SF_POLLING);
421 sc->sc_state = STATE_CHANNEL;
422 splx(s);
423
424 /*
425 * Switch keyboard to raw mode.
426 */
427 cmdbuf[0] = DNCMD_RAW;
428 rc = dnkbd_send(sc, cmdbuf, 1);
429 if (rc != 0)
430 goto out;
431
432 /*
433 * Send the identify command.
434 */
435 cmdbuf[0] = DNCMD_IDENT_1;
436 cmdbuf[1] = DNCMD_IDENT_2;
437 rc = dnkbd_send(sc, cmdbuf, 2);
438 if (rc != 0)
439 goto out;
440
441 for (i = 0; ; i++) {
442 dat = dnkbd_pollin(sc, 10000);
443 if (dat == -1)
444 break;
445
446 if (i < sizeof(rspbuf))
447 rspbuf[i] = dat;
448 }
449
450 if (i > sizeof(rspbuf) || i == 0) {
451 aprint_error_dev(sc->sc_dev,
452 "unexpected identify string length %d\n", i);
453 rc = ENXIO;
454 goto out;
455 }
456
457 /*
458 * Make sure the identification string is NULL terminated
459 * (overwriting the keyboard mode byte if necessary).
460 */
461 i--;
462 if (rspbuf[i] != 0)
463 rspbuf[i] = 0;
464
465 /*
466 * Now display the identification strings, if they changed.
467 */
468 if (i != sc->sc_identlen || memcmp(rspbuf, sc->sc_ident, i) != 0) {
469 sc->sc_layout = KB_US;
470 sc->sc_identlen = i;
471 memcpy(sc->sc_ident, rspbuf, i);
472
473 if (cold == 0)
474 aprint_normal_dev(sc->sc_dev, "");
475 aprint_normal("model ");
476 word = rspbuf;
477 for (i = 0; i < 3; i++) {
478 end = strchr(word, '\r');
479 if (end == NULL)
480 break;
481 *end++ = '\0';
482 aprint_normal("<%s> ", word);
483 /*
484 * Parse the layout code if applicable
485 */
486 if (i == 1 && *word++ == '3') {
487 if (*word == '-')
488 word++;
489 switch (*word) {
490 #if 0
491 default:
492 case ' ':
493 sc->sc_layout = KB_US;
494 break;
495 #endif
496 case 'a':
497 sc->sc_layout = KB_DE;
498 break;
499 case 'b':
500 sc->sc_layout = KB_FR;
501 break;
502 case 'c':
503 sc->sc_layout = KB_DK;
504 break;
505 case 'd':
506 sc->sc_layout = KB_SV;
507 break;
508 case 'e':
509 sc->sc_layout = KB_UK;
510 break;
511 case 'f':
512 sc->sc_layout = KB_JP;
513 break;
514 case 'g':
515 sc->sc_layout = KB_SG;
516 break;
517 }
518 }
519 word = end;
520 }
521 aprint_normal("\n");
522 }
523
524 /*
525 * Ready to work, the default channel is the keyboard.
526 */
527 sc->sc_state = STATE_KEYBOARD;
528
529 out:
530 s = spltty();
531 sc->sc_flags = flags;
532 splx(s);
533
534 return rc;
535 }
536
537 /*
538 * State machine.
539 *
540 * In raw mode, the keyboard may feed us the following sequences:
541 * - on the keyboard channel:
542 * + a raw key code, in the range 0x01-0x7e, or'ed with 0x80 if key release.
543 * + the key repeat sequence 0x7f.
544 * - on the mouse channel:
545 * + a 3 byte mouse sequence (buttons state, dx move, dy move).
546 * - at any time:
547 * + a 2 byte channel sequence (0xff followed by the channel number) telling
548 * us which device the following input will come from.
549 * + if we get 0xff but an invalid channel number, this is a command echo.
550 * Currently we only handle this for bell commands, which size are known.
551 * Other commands are issued through dnkbd_send() which ``eats'' the echo.
552 *
553 * Older keyboards reset the channel to the keyboard (by sending ff 01) after
554 * every mouse packet.
555 */
556
557 dnevent
558 dnkbd_input(struct dnkbd_softc *sc, int dat)
559 {
560 dnevent event = EVENT_NONE;
561
562 switch (sc->sc_state) {
563 case STATE_KEYBOARD:
564 switch (dat) {
565 case DNKEY_REPEAT:
566 /*
567 * We ignore event repeats, as wskbd does its own
568 * soft repeat processing.
569 */
570 break;
571 case DNKEY_CHANNEL:
572 sc->sc_prevstate = sc->sc_state;
573 sc->sc_state = STATE_CHANNEL;
574 break;
575 default:
576 event = EVENT_KEYBOARD;
577 break;
578 }
579 break;
580
581 case STATE_MOUSE:
582 if (dat == DNKEY_CHANNEL && sc->sc_mousepos == 0) {
583 sc->sc_prevstate = sc->sc_state;
584 sc->sc_state = STATE_CHANNEL;
585 } else {
586 sc->sc_mousepkt[sc->sc_mousepos++] = dat;
587 if (sc->sc_mousepos == sizeof(sc->sc_mousepkt)) {
588 sc->sc_mousepos = 0;
589 event = EVENT_MOUSE;
590 }
591 }
592 break;
593
594 case STATE_CHANNEL:
595 switch (dat) {
596 case DNKEY_CHANNEL:
597 /*
598 * During hotplug, we might get spurious 0xff bytes.
599 * Ignore them.
600 */
601 break;
602 case DNCHANNEL_RESET:
603 /*
604 * Identify the keyboard again. This will switch it to
605 * raw mode again. If this fails, we'll consider the
606 * keyboard as unplugged (to ignore further events until
607 * a successful reset).
608 */
609 if (dnkbd_probe(sc) == 0) {
610 /*
611 * We need to attach wskbd and wsmouse children
612 * if this is a live first plug.
613 */
614 if (!ISSET(sc->sc_flags, SF_ATTACHED))
615 dnkbd_attach_subdevices(sc);
616 SET(sc->sc_flags, SF_PLUGGED);
617 } else {
618 CLR(sc->sc_flags, SF_PLUGGED);
619 }
620
621 sc->sc_state = STATE_KEYBOARD;
622 break;
623 case DNCHANNEL_KBD:
624 sc->sc_state = STATE_KEYBOARD;
625 break;
626 case DNCHANNEL_MOUSE:
627 sc->sc_state = STATE_MOUSE;
628 sc->sc_mousepos = 0; /* just in case */
629 break;
630 case DNCMD_BELL:
631 /*
632 * We are getting a bell command echoed to us.
633 * Ignore it.
634 */
635 sc->sc_state = STATE_ECHO;
636 sc->sc_echolen = 1; /* one byte to follow */
637 break;
638 default:
639 printf("%s: unexpected channel byte %02x\n",
640 device_xname(sc->sc_dev), dat);
641 break;
642 }
643 break;
644
645 case STATE_ECHO:
646 if (--sc->sc_echolen == 0) {
647 /* get back to the state we were in before the echo */
648 sc->sc_state = sc->sc_prevstate;
649 }
650 break;
651 }
652
653 return event;
654 }
655
656 /*
657 * Event breakers.
658 */
659
660 void
661 dnkbd_decode(int keycode, u_int *type, int *key)
662 {
663 *type = (keycode & DNKEY_RELEASE) ?
664 WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
665 *key = (keycode & ~DNKEY_RELEASE);
666 }
667
668 void
669 dnevent_kbd(struct dnkbd_softc *sc, int dat)
670 {
671 if (!ISSET(sc->sc_flags, SF_PLUGGED))
672 return;
673
674 if (sc->sc_wskbddev == NULL)
675 return;
676
677 if (!ISSET(sc->sc_flags, SF_ENABLED))
678 return;
679
680 /*
681 * Even in raw mode, the caps lock key is treated specially:
682 * first key press causes event 0x7e, release causes no event;
683 * then a new key press causes nothing, and release causes
684 * event 0xfe. Moreover, while kept down, it does not produce
685 * repeat events.
686 *
687 * So the best we can do is fake the missed events, but this
688 * will not allow the capslock key to be remapped as a control
689 * key since it will not be possible to chord it with anything.
690 */
691 dnevent_kbd_internal(sc, dat);
692 if ((dat & ~DNKEY_RELEASE) == DNKEY_CAPSLOCK)
693 dnevent_kbd_internal(sc, dat ^ DNKEY_RELEASE);
694 }
695
696 void
697 dnevent_kbd_internal(struct dnkbd_softc *sc, int dat)
698 {
699 u_int type;
700 int key;
701 int s;
702
703 dnkbd_decode(dat, &type, &key);
704
705 #ifdef WSDISPLAY_COMPAT_RAWKBD
706 if (sc->sc_rawkbd) {
707 u_char cbuf[2];
708 int c, j;
709
710 j = 0;
711 c = dnkbd_raw[key];
712 if (c != 0) {
713 /* fake extended scancode if necessary */
714 if (c & 0x80)
715 cbuf[j++] = 0xe0;
716 cbuf[j] = c & 0x7f;
717 if (type == WSCONS_EVENT_KEY_UP)
718 cbuf[j] |= 0x80;
719 j++;
720 }
721
722 if (j != 0) {
723 s = spltty();
724 wskbd_rawinput(sc->sc_wskbddev, cbuf, j);
725 splx(s);
726 }
727 } else
728 #endif
729 {
730 s = spltty();
731 wskbd_input(sc->sc_wskbddev, type, key);
732 splx(s);
733 }
734 }
735
736 #if NWSMOUSE > 0
737 void
738 dnevent_mouse(struct dnkbd_softc *sc, uint8_t *dat)
739 {
740 if (!ISSET(sc->sc_flags, SF_PLUGGED))
741 return;
742
743 if (sc->sc_wsmousedev == NULL)
744 return;
745
746 if (!ISSET(sc->sc_flags, SF_MOUSE))
747 return;
748
749 /*
750 * First byte is button status. It has the 0x80 bit always set, and
751 * the next 3 bits are *cleared* when the mouse buttons are pressed.
752 */
753 #ifdef DEBUG
754 if (!ISSET(*dat, 0x80)) {
755 printf("%s: incorrect mouse packet %02x %02x %02x\n",
756 device_xname(sc->sc_dev), dat[0], dat[1], dat[2]);
757 return;
758 }
759 #endif
760
761 wsmouse_input(sc->sc_wsmousedev,
762 (~dat[0] & (DNBUTTON_L | DNBUTTON_M | DNBUTTON_R)) >> 4,
763 (int8_t)dat[1], (int8_t)dat[2], 0, 0, WSMOUSE_INPUT_DELTA);
764 }
765 #endif
766
767 /*
768 * Low-level communication routines.
769 */
770
771 int
772 dnkbd_pollin(struct dnkbd_softc *sc, u_int tries)
773 {
774 bus_space_tag_t bst;
775 bus_space_handle_t bsh;
776 u_int cnt;
777
778 bst = sc->sc_bst;
779 bsh = sc->sc_bsh;
780
781 for (cnt = tries; cnt != 0; cnt--) {
782 if (bus_space_read_1(bst, bsh, com_lsr) & LSR_RXRDY)
783 break;
784 DELAY(10);
785 }
786
787 if (cnt == 0)
788 return -1;
789 else
790 return (int)bus_space_read_1(bst, bsh, com_data);
791 }
792
793 int
794 dnkbd_pollout(struct dnkbd_softc *sc, int dat)
795 {
796 bus_space_tag_t bst;
797 bus_space_handle_t bsh;
798 u_int cnt;
799
800 bst = sc->sc_bst;
801 bsh = sc->sc_bsh;
802
803 for (cnt = 10000; cnt != 0; cnt--) {
804 if (bus_space_read_1(bst, bsh, com_lsr) & LSR_TXRDY)
805 break;
806 DELAY(10);
807 }
808 if (cnt == 0)
809 return EBUSY;
810 else {
811 bus_space_write_1(bst, bsh, com_data, dat);
812 return 0;
813 }
814 }
815
816 int
817 dnkbd_send(struct dnkbd_softc *sc, const uint8_t *cmdbuf, size_t cmdlen)
818 {
819 int cnt, rc, dat;
820 u_int cmdpos;
821
822 /* drain rxfifo */
823 for (cnt = 10; cnt != 0; cnt--) {
824 if (dnkbd_pollin(sc, 10) == -1)
825 break;
826 }
827 if (cnt == 0)
828 return EBUSY;
829
830 /* send command escape */
831 if ((rc = dnkbd_pollout(sc, DNCMD_PREFIX)) != 0)
832 return rc;
833
834 /* send command buffer */
835 for (cmdpos = 0; cmdpos < cmdlen; cmdpos++) {
836 if ((rc = dnkbd_pollout(sc, cmdbuf[cmdpos])) != 0)
837 return rc;
838 }
839
840 /* wait for command echo */
841 do {
842 dat = dnkbd_pollin(sc, 10000);
843 if (dat == -1)
844 return EIO;
845 } while (dat != DNCMD_PREFIX);
846
847 for (cmdpos = 0; cmdpos < cmdlen; cmdpos++) {
848 dat = dnkbd_pollin(sc, 10000);
849 if (dat != cmdbuf[cmdpos])
850 return EIO;
851 }
852
853 return 0;
854 }
855
856 void
857 dnkbd_break(struct dnkbd_softc *sc, int onoff)
858 {
859 bus_space_tag_t bst;
860 bus_space_handle_t bsh;
861 uint8_t reg;
862
863 bst = sc->sc_bst;
864 bsh = sc->sc_bsh;
865
866 reg = bus_space_read_1(bst, bsh, com_lctl);
867 if (onoff)
868 reg |= LCR_SBREAK;
869 else
870 reg &= ~LCR_SBREAK;
871 bus_space_write_1(bst, bsh, com_lctl, reg);
872 }
873
874 int
875 dnkbd_intr(void *v)
876 {
877 struct dnkbd_softc *sc = v;
878 bus_space_tag_t bst;
879 bus_space_handle_t bsh;
880 uint8_t iir, lsr, c;
881 int claimed = 0;
882
883 bst = sc->sc_bst;
884 bsh = sc->sc_bsh;
885
886 for (;;) {
887 iir = bus_space_read_1(bst, bsh, com_iir);
888
889 switch (iir & IIR_IMASK) {
890 case IIR_RLS:
891 /*
892 * Line status change. This should never happen,
893 * so silently ack the interrupt.
894 */
895 c = bus_space_read_1(bst, bsh, com_lsr);
896 break;
897
898 case IIR_RXRDY:
899 case IIR_RXTOUT:
900 /*
901 * Data available. We process it byte by byte,
902 * unless we are doing polling work...
903 */
904 if (ISSET(sc->sc_flags, SF_POLLING)) {
905 return 1;
906 }
907
908 for (;;) {
909 c = bus_space_read_1(bst, bsh, com_data);
910 switch (dnkbd_input(sc, c)) {
911 case EVENT_KEYBOARD:
912 dnevent_kbd(sc, c);
913 break;
914 #if NWSMOUSE > 0
915 case EVENT_MOUSE:
916 dnevent_mouse(sc, sc->sc_mousepkt);
917 break;
918 #endif
919 default: /* appease gcc */
920 break;
921 }
922 lsr = bus_space_read_1(bst, bsh, com_lsr) &
923 LSR_RCV_MASK;
924 if (lsr == 0)
925 break;
926 else if (lsr != LSR_RXRDY) {
927 /* ignore error */
928 break;
929 }
930 }
931 break;
932
933 case IIR_TXRDY:
934 /*
935 * Transmit available. Since we do all our commands
936 * in polling mode, we do not need to do anything here.
937 */
938 break;
939
940 default:
941 if (iir & IIR_NOPEND)
942 return claimed;
943 /* FALLTHROUGH */
944
945 case IIR_MLSC:
946 /*
947 * Modem status change. This should never happen,
948 * so silently ack the interrupt.
949 */
950 c = bus_space_read_1(bst, bsh, com_msr);
951 break;
952 }
953
954 claimed = 1;
955 }
956 }
957
958 /*
959 * Wskbd callbacks
960 */
961
962 int
963 dnkbd_enable(void *v, int on)
964 {
965 struct dnkbd_softc *sc = v;
966
967 if (on) {
968 if (ISSET(sc->sc_flags, SF_ENABLED))
969 return EBUSY;
970 SET(sc->sc_flags, SF_ENABLED);
971 } else {
972 if (ISSET(sc->sc_flags, SF_CONSOLE))
973 return EBUSY;
974 CLR(sc->sc_flags, SF_ENABLED);
975 }
976
977 return 0;
978 }
979
980 void
981 dnkbd_set_leds(void *v, int leds)
982 {
983 /*
984 * Not supported. There is only one LED on this keyboard, and
985 * is hardware tied to the caps lock key.
986 */
987 }
988
989 int
990 dnkbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
991 {
992 #ifdef WSDISPLAY_COMPAT_RAWKBD
993 struct dnkbd_softc *sc = v;
994 #endif
995
996 #define WSKBD_TYPE_UNKNOWN 0
997
998 switch (cmd) {
999 case WSKBDIO_GTYPE:
1000 *(int *)data = WSKBD_TYPE_UNKNOWN; /* XXX */
1001 return 0;
1002 case WSKBDIO_SETLEDS:
1003 return ENXIO;
1004 case WSKBDIO_GETLEDS:
1005 *(int *)data = 0;
1006 return 0;
1007 case WSKBDIO_COMPLEXBELL:
1008 #define d ((struct wskbd_bell_data *)data)
1009 dnkbd_bell(v, d->period, d->pitch, d->volume);
1010 #undef d
1011 return 0;
1012 #ifdef WSDISPLAY_COMPAT_RAWKBD
1013 case WSKBDIO_SETMODE:
1014 sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
1015 return 0;
1016 #endif
1017 }
1018
1019 return EPASSTHROUGH;
1020 }
1021
1022 #if NWSMOUSE > 0
1023 /*
1024 * Wsmouse callbacks
1025 */
1026
1027 int
1028 dnmouse_enable(void *v)
1029 {
1030 struct dnkbd_softc *sc = v;
1031
1032 if (ISSET(sc->sc_flags, SF_MOUSE))
1033 return EBUSY;
1034 SET(sc->sc_flags, SF_MOUSE);
1035
1036 return 0;
1037 }
1038
1039 int
1040 dnmouse_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
1041 {
1042 #if 0
1043 struct dnkbd_softc *sc = v;
1044 #endif
1045
1046 #define WSMOUSE_TYPE_UNKNOWN 0
1047
1048 switch (cmd) {
1049 case WSMOUSEIO_GTYPE:
1050 *(int *)data = WSMOUSE_TYPE_UNKNOWN; /* XXX */
1051 return 0;
1052 }
1053
1054 return -1;
1055 }
1056
1057 void
1058 dnmouse_disable(void *v)
1059 {
1060 struct dnkbd_softc *sc = v;
1061
1062 CLR(sc->sc_flags, SF_MOUSE);
1063 }
1064 #endif
1065
1066 /*
1067 * Console support
1068 */
1069
1070 void
1071 dnkbd_cngetc(void *v, u_int *type, int *data)
1072 {
1073 static int lastdat = 0;
1074 struct dnkbd_softc *sc = v;
1075 int s;
1076 int dat;
1077
1078 /* Take care of caps lock */
1079 if ((lastdat & ~DNKEY_RELEASE) == DNKEY_CAPSLOCK) {
1080 dat = lastdat ^ DNKEY_RELEASE;
1081 lastdat = 0;
1082 } else {
1083 for (;;) {
1084 s = splhigh();
1085 dat = dnkbd_pollin(sc, 10000);
1086 if (dat != -1) {
1087 if (dnkbd_input(sc, dat) == EVENT_KEYBOARD) {
1088 splx(s);
1089 break;
1090 }
1091 }
1092 splx(s);
1093 }
1094 lastdat = dat;
1095 }
1096
1097 dnkbd_decode(dat, type, data);
1098 }
1099
1100 void
1101 dnkbd_cnpollc(void *v, int on)
1102 {
1103 struct dnkbd_softc *sc = v;
1104
1105 if (on)
1106 SET(sc->sc_flags, SF_POLLING);
1107 else
1108 CLR(sc->sc_flags, SF_POLLING);
1109 }
1110
1111 /*
1112 * Bell routines.
1113 */
1114 void
1115 dnkbd_bell(void *v, u_int period, u_int pitch, u_int volume)
1116 {
1117 struct dnkbd_softc *sc = v;
1118 int s;
1119
1120 s = spltty();
1121
1122 if (pitch == 0 || period == 0 || volume == 0) {
1123 if (ISSET(sc->sc_flags, SF_BELL_TMO)) {
1124 callout_stop(&sc->sc_bellstop_tmo);
1125 dnkbd_bellstop(v);
1126 }
1127 } else {
1128
1129 if (!ISSET(sc->sc_flags, SF_BELL)) {
1130 dnkbd_pollout(sc, DNCMD_PREFIX);
1131 dnkbd_pollout(sc, DNCMD_BELL);
1132 dnkbd_pollout(sc, DNCMD_BELL_ON);
1133 SET(sc->sc_flags, SF_BELL);
1134 }
1135
1136 if (ISSET(sc->sc_flags, SF_BELL_TMO))
1137 callout_stop(&sc->sc_bellstop_tmo);
1138 callout_schedule(&sc->sc_bellstop_tmo, period);
1139 SET(sc->sc_flags, SF_BELL_TMO);
1140 }
1141
1142 splx(s);
1143 }
1144
1145 void
1146 dnkbd_bellstop(void *v)
1147 {
1148 struct dnkbd_softc *sc = v;
1149 int s;
1150
1151 s = spltty();
1152
1153 dnkbd_pollout(sc, DNCMD_PREFIX);
1154 dnkbd_pollout(sc, DNCMD_BELL);
1155 dnkbd_pollout(sc, DNCMD_BELL_OFF);
1156 CLR(sc->sc_flags, SF_BELL);
1157 CLR(sc->sc_flags, SF_BELL_TMO);
1158
1159 splx(s);
1160 }
1161