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