| File: | dev/wscons/wskbd.c |
| Warning: | line 1821, column 30 Access to field 'sc_audiocookie' results in a dereference of a null pointer (loaded from variable 'sc') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: wskbd.c,v 1.117 2023/11/23 15:02:57 deraadt Exp $ */ | |||
| 2 | /* $NetBSD: wskbd.c,v 1.80 2005/05/04 01:52:16 augustss Exp $ */ | |||
| 3 | ||||
| 4 | /* | |||
| 5 | * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved. | |||
| 6 | * | |||
| 7 | * Keysym translator: | |||
| 8 | * Contributed to The NetBSD Foundation by Juergen Hannken-Illjes. | |||
| 9 | * | |||
| 10 | * Redistribution and use in source and binary forms, with or without | |||
| 11 | * modification, are permitted provided that the following conditions | |||
| 12 | * are met: | |||
| 13 | * 1. Redistributions of source code must retain the above copyright | |||
| 14 | * notice, this list of conditions and the following disclaimer. | |||
| 15 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 16 | * notice, this list of conditions and the following disclaimer in the | |||
| 17 | * documentation and/or other materials provided with the distribution. | |||
| 18 | * 3. All advertising materials mentioning features or use of this software | |||
| 19 | * must display the following acknowledgement: | |||
| 20 | * This product includes software developed by Christopher G. Demetriou | |||
| 21 | * for the NetBSD Project. | |||
| 22 | * 4. The name of the author may not be used to endorse or promote products | |||
| 23 | * derived from this software without specific prior written permission | |||
| 24 | * | |||
| 25 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |||
| 26 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
| 27 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||
| 28 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |||
| 29 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |||
| 30 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
| 31 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
| 32 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
| 33 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |||
| 34 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| 35 | */ | |||
| 36 | ||||
| 37 | /* | |||
| 38 | * Copyright (c) 1992, 1993 | |||
| 39 | * The Regents of the University of California. All rights reserved. | |||
| 40 | * | |||
| 41 | * This software was developed by the Computer Systems Engineering group | |||
| 42 | * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and | |||
| 43 | * contributed to Berkeley. | |||
| 44 | * | |||
| 45 | * All advertising materials mentioning features or use of this software | |||
| 46 | * must display the following acknowledgement: | |||
| 47 | * This product includes software developed by the University of | |||
| 48 | * California, Lawrence Berkeley Laboratory. | |||
| 49 | * | |||
| 50 | * Redistribution and use in source and binary forms, with or without | |||
| 51 | * modification, are permitted provided that the following conditions | |||
| 52 | * are met: | |||
| 53 | * 1. Redistributions of source code must retain the above copyright | |||
| 54 | * notice, this list of conditions and the following disclaimer. | |||
| 55 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 56 | * notice, this list of conditions and the following disclaimer in the | |||
| 57 | * documentation and/or other materials provided with the distribution. | |||
| 58 | * 3. Neither the name of the University nor the names of its contributors | |||
| 59 | * may be used to endorse or promote products derived from this software | |||
| 60 | * without specific prior written permission. | |||
| 61 | * | |||
| 62 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |||
| 63 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
| 64 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
| 65 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |||
| 66 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
| 67 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
| 68 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
| 69 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
| 70 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
| 71 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| 72 | * SUCH DAMAGE. | |||
| 73 | * | |||
| 74 | * @(#)kbd.c 8.2 (Berkeley) 10/30/93 | |||
| 75 | */ | |||
| 76 | ||||
| 77 | /* | |||
| 78 | * Keyboard driver (/dev/wskbd*). Translates incoming bytes to ASCII or | |||
| 79 | * to `wscons_events' and passes them up to the appropriate reader. | |||
| 80 | */ | |||
| 81 | ||||
| 82 | #include <sys/param.h> | |||
| 83 | #include <sys/conf.h> | |||
| 84 | #include <sys/device.h> | |||
| 85 | #include <sys/ioctl.h> | |||
| 86 | #include <sys/kernel.h> | |||
| 87 | #include <sys/proc.h> | |||
| 88 | #include <sys/syslog.h> | |||
| 89 | #include <sys/systm.h> | |||
| 90 | #include <sys/timeout.h> | |||
| 91 | #include <sys/malloc.h> | |||
| 92 | #include <sys/tty.h> | |||
| 93 | #include <sys/signalvar.h> | |||
| 94 | #include <sys/errno.h> | |||
| 95 | #include <sys/fcntl.h> | |||
| 96 | #include <sys/vnode.h> | |||
| 97 | #include <sys/task.h> | |||
| 98 | ||||
| 99 | #include <ddb/db_var.h> | |||
| 100 | ||||
| 101 | #include <dev/wscons/wscons_features.h> | |||
| 102 | #include <dev/wscons/wsconsio.h> | |||
| 103 | #include <dev/wscons/wskbdvar.h> | |||
| 104 | #include <dev/wscons/wsksymdef.h> | |||
| 105 | #include <dev/wscons/wsksymvar.h> | |||
| 106 | #include <dev/wscons/wsdisplayvar.h> | |||
| 107 | #include <dev/wscons/wseventvar.h> | |||
| 108 | #include <dev/wscons/wscons_callbacks.h> | |||
| 109 | ||||
| 110 | #include "audio.h" /* NAUDIO (mixer tuning) */ | |||
| 111 | #include "wsdisplay.h" | |||
| 112 | #include "wskbd.h" | |||
| 113 | #include "wsmux.h" | |||
| 114 | ||||
| 115 | #if NWSDISPLAY1 > 0 | |||
| 116 | #include <sys/atomic.h> | |||
| 117 | #endif | |||
| 118 | ||||
| 119 | #ifdef WSKBD_DEBUG | |||
| 120 | #define DPRINTF(x) if (wskbddebug) printf x | |||
| 121 | int wskbddebug = 0; | |||
| 122 | #else | |||
| 123 | #define DPRINTF(x) | |||
| 124 | #endif | |||
| 125 | ||||
| 126 | #include <dev/wscons/wsmuxvar.h> | |||
| 127 | ||||
| 128 | struct wskbd_internal { | |||
| 129 | const struct wskbd_consops *t_consops; | |||
| 130 | void *t_consaccesscookie; | |||
| 131 | ||||
| 132 | int t_modifiers; | |||
| 133 | int t_composelen; /* remaining entries in t_composebuf */ | |||
| 134 | keysym_t t_composebuf[2]; | |||
| 135 | ||||
| 136 | int t_flags; | |||
| 137 | #define WSKFL_METAESC1 1 | |||
| 138 | ||||
| 139 | #define MAXKEYSYMSPERKEY2 2 /* ESC <key> at max */ | |||
| 140 | keysym_t t_symbols[MAXKEYSYMSPERKEY2]; | |||
| 141 | ||||
| 142 | struct wskbd_softc *t_sc; /* back pointer */ | |||
| 143 | ||||
| 144 | struct wskbd_mapdata t_keymap; /* translation map table and | |||
| 145 | current layout */ | |||
| 146 | }; | |||
| 147 | ||||
| 148 | struct wskbd_softc { | |||
| 149 | struct wsevsrc sc_base; | |||
| 150 | ||||
| 151 | struct wskbd_internal *id; | |||
| 152 | ||||
| 153 | const struct wskbd_accessops *sc_accessops; | |||
| 154 | void *sc_accesscookie; | |||
| 155 | ||||
| 156 | int sc_ledstate; | |||
| 157 | ||||
| 158 | int sc_isconsole; | |||
| 159 | ||||
| 160 | struct wskbd_bell_data sc_bell_data; | |||
| 161 | struct wskbd_keyrepeat_data sc_keyrepeat_data; | |||
| 162 | ||||
| 163 | int sc_repeating; /* we've called timeout() */ | |||
| 164 | int sc_repkey; | |||
| 165 | struct timeout sc_repeat_ch; | |||
| 166 | u_int sc_repeat_type; | |||
| 167 | int sc_repeat_value; | |||
| 168 | ||||
| 169 | int sc_translating; /* xlate to chars for emulation */ | |||
| 170 | ||||
| 171 | int sc_maplen; /* number of entries in sc_map */ | |||
| 172 | struct wscons_keymap *sc_map; /* current translation map */ | |||
| 173 | ||||
| 174 | int sc_refcnt; | |||
| 175 | u_char sc_dying; /* device is being detached */ | |||
| 176 | ||||
| 177 | #if NAUDIO1 > 0 | |||
| 178 | void *sc_audiocookie; | |||
| 179 | #endif | |||
| 180 | struct task sc_kbd_backlight_task; | |||
| 181 | u_int sc_kbd_backlight_cmd; | |||
| 182 | #if NWSDISPLAY1 > 0 | |||
| 183 | struct task sc_brightness_task; | |||
| 184 | int sc_brightness_steps; | |||
| 185 | #endif | |||
| 186 | }; | |||
| 187 | ||||
| 188 | enum wskbd_kbd_backlight_cmds { | |||
| 189 | KBD_BACKLIGHT_NONE, | |||
| 190 | KBD_BACKLIGHT_UP, | |||
| 191 | KBD_BACKLIGHT_DOWN, | |||
| 192 | KBD_BACKLIGHT_TOGGLE, | |||
| 193 | }; | |||
| 194 | ||||
| 195 | #define MOD_SHIFT_L(1 << 0) (1 << 0) | |||
| 196 | #define MOD_SHIFT_R(1 << 1) (1 << 1) | |||
| 197 | #define MOD_SHIFTLOCK(1 << 2) (1 << 2) | |||
| 198 | #define MOD_CAPSLOCK(1 << 3) (1 << 3) | |||
| 199 | #define MOD_CONTROL_L(1 << 4) (1 << 4) | |||
| 200 | #define MOD_CONTROL_R(1 << 5) (1 << 5) | |||
| 201 | #define MOD_META_L(1 << 6) (1 << 6) | |||
| 202 | #define MOD_META_R(1 << 7) (1 << 7) | |||
| 203 | #define MOD_MODESHIFT(1 << 8) (1 << 8) | |||
| 204 | #define MOD_NUMLOCK(1 << 9) (1 << 9) | |||
| 205 | #define MOD_COMPOSE(1 << 10) (1 << 10) | |||
| 206 | #define MOD_HOLDSCREEN(1 << 11) (1 << 11) | |||
| 207 | #define MOD_COMMAND(1 << 12) (1 << 12) | |||
| 208 | #define MOD_COMMAND1(1 << 13) (1 << 13) | |||
| 209 | #define MOD_COMMAND2(1 << 14) (1 << 14) | |||
| 210 | #define MOD_MODELOCK(1 << 15) (1 << 15) | |||
| 211 | ||||
| 212 | #define MOD_ANYSHIFT((1 << 0) | (1 << 1) | (1 << 2)) (MOD_SHIFT_L(1 << 0) | MOD_SHIFT_R(1 << 1) | MOD_SHIFTLOCK(1 << 2)) | |||
| 213 | #define MOD_ANYCONTROL((1 << 4) | (1 << 5)) (MOD_CONTROL_L(1 << 4) | MOD_CONTROL_R(1 << 5)) | |||
| 214 | #define MOD_ANYMETA((1 << 6) | (1 << 7)) (MOD_META_L(1 << 6) | MOD_META_R(1 << 7)) | |||
| 215 | #define MOD_ANYLED((1 << 2) | (1 << 3) | (1 << 9) | (1 << 10) | (1 << 11)) (MOD_SHIFTLOCK(1 << 2) | MOD_CAPSLOCK(1 << 3) | MOD_NUMLOCK(1 << 9) | \ | |||
| 216 | MOD_COMPOSE(1 << 10) | MOD_HOLDSCREEN(1 << 11)) | |||
| 217 | ||||
| 218 | #define MOD_ONESET(id, mask)(((id)->t_modifiers & (mask)) != 0) (((id)->t_modifiers & (mask)) != 0) | |||
| 219 | #define MOD_ALLSET(id, mask)(((id)->t_modifiers & (mask)) == (mask)) (((id)->t_modifiers & (mask)) == (mask)) | |||
| 220 | ||||
| 221 | keysym_t ksym_upcase(keysym_t); | |||
| 222 | ||||
| 223 | int wskbd_match(struct device *, void *, void *); | |||
| 224 | void wskbd_attach(struct device *, struct device *, void *); | |||
| 225 | int wskbd_detach(struct device *, int); | |||
| 226 | int wskbd_activate(struct device *, int); | |||
| 227 | ||||
| 228 | int wskbd_displayioctl(struct device *, u_long, caddr_t, int, struct proc *); | |||
| 229 | int wskbd_displayioctl_sc(struct wskbd_softc *, u_long, caddr_t, int, | |||
| 230 | struct proc *, int); | |||
| 231 | ||||
| 232 | void update_leds(struct wskbd_internal *); | |||
| 233 | void update_modifier(struct wskbd_internal *, u_int, int, int); | |||
| 234 | int internal_command(struct wskbd_softc *, u_int *, keysym_t, keysym_t); | |||
| 235 | int wskbd_translate(struct wskbd_internal *, u_int, int); | |||
| 236 | int wskbd_enable(struct wskbd_softc *, int); | |||
| 237 | void wskbd_debugger(struct wskbd_softc *); | |||
| 238 | #if NWSDISPLAY1 > 0 | |||
| 239 | void change_displayparam(struct wskbd_softc *, int, int, int); | |||
| 240 | #endif | |||
| 241 | ||||
| 242 | int wskbd_do_ioctl_sc(struct wskbd_softc *, u_long, caddr_t, int, | |||
| 243 | struct proc *, int); | |||
| 244 | void wskbd_deliver_event(struct wskbd_softc *sc, u_int type, int value); | |||
| 245 | ||||
| 246 | #if NWSMUX1 > 0 | |||
| 247 | int wskbd_mux_open(struct wsevsrc *, struct wseventvar *); | |||
| 248 | int wskbd_mux_close(struct wsevsrc *); | |||
| 249 | #else | |||
| 250 | #define wskbd_mux_open NULL((void *)0) | |||
| 251 | #define wskbd_mux_close NULL((void *)0) | |||
| 252 | #endif | |||
| 253 | ||||
| 254 | int wskbd_do_open(struct wskbd_softc *, struct wseventvar *); | |||
| 255 | int wskbd_do_ioctl(struct device *, u_long, caddr_t, int, struct proc *); | |||
| 256 | ||||
| 257 | void wskbd_set_keymap(struct wskbd_softc *, struct wscons_keymap *, int); | |||
| 258 | ||||
| 259 | int (*wskbd_get_backlight)(struct wskbd_backlight *); | |||
| 260 | int (*wskbd_set_backlight)(struct wskbd_backlight *); | |||
| 261 | ||||
| 262 | void wskbd_kbd_backlight_task(void *); | |||
| 263 | #if NWSDISPLAY1 > 0 | |||
| 264 | void wskbd_brightness_task(void *); | |||
| 265 | #endif | |||
| 266 | ||||
| 267 | struct cfdriver wskbd_cd = { | |||
| 268 | NULL((void *)0), "wskbd", DV_TTY | |||
| 269 | }; | |||
| 270 | ||||
| 271 | const struct cfattach wskbd_ca = { | |||
| 272 | sizeof (struct wskbd_softc), wskbd_match, wskbd_attach, | |||
| 273 | wskbd_detach, wskbd_activate | |||
| 274 | }; | |||
| 275 | ||||
| 276 | #if defined(__i386__) || defined(__amd64__1) | |||
| 277 | extern int kbd_reset; | |||
| 278 | #endif | |||
| 279 | ||||
| 280 | #ifndef WSKBD_DEFAULT_BELL_PITCH400 | |||
| 281 | #define WSKBD_DEFAULT_BELL_PITCH400 400 /* 400Hz */ | |||
| 282 | #endif | |||
| 283 | #ifndef WSKBD_DEFAULT_BELL_PERIOD100 | |||
| 284 | #define WSKBD_DEFAULT_BELL_PERIOD100 100 /* 100ms */ | |||
| 285 | #endif | |||
| 286 | #ifndef WSKBD_DEFAULT_BELL_VOLUME50 | |||
| 287 | #define WSKBD_DEFAULT_BELL_VOLUME50 50 /* 50% volume */ | |||
| 288 | #endif | |||
| 289 | ||||
| 290 | struct wskbd_bell_data wskbd_default_bell_data = { | |||
| 291 | WSKBD_BELL_DOALL0x7, | |||
| 292 | WSKBD_DEFAULT_BELL_PITCH400, | |||
| 293 | WSKBD_DEFAULT_BELL_PERIOD100, | |||
| 294 | WSKBD_DEFAULT_BELL_VOLUME50, | |||
| 295 | }; | |||
| 296 | ||||
| 297 | #ifndef WSKBD_DEFAULT_KEYREPEAT_DEL1400 | |||
| 298 | #define WSKBD_DEFAULT_KEYREPEAT_DEL1400 400 /* 400ms to start repeating */ | |||
| 299 | #endif | |||
| 300 | #ifndef WSKBD_DEFAULT_KEYREPEAT_DELN100 | |||
| 301 | #define WSKBD_DEFAULT_KEYREPEAT_DELN100 100 /* 100ms to between repeats */ | |||
| 302 | #endif | |||
| 303 | ||||
| 304 | struct wskbd_keyrepeat_data wskbd_default_keyrepeat_data = { | |||
| 305 | WSKBD_KEYREPEAT_DOALL0x3, | |||
| 306 | WSKBD_DEFAULT_KEYREPEAT_DEL1400, | |||
| 307 | WSKBD_DEFAULT_KEYREPEAT_DELN100, | |||
| 308 | }; | |||
| 309 | ||||
| 310 | #if NWSMUX1 > 0 || NWSDISPLAY1 > 0 | |||
| 311 | struct wssrcops wskbd_srcops = { | |||
| 312 | .type = WSMUX_KBD2, | |||
| 313 | .dopen = wskbd_mux_open, | |||
| 314 | .dclose = wskbd_mux_close, | |||
| 315 | .dioctl = wskbd_do_ioctl, | |||
| 316 | .ddispioctl = wskbd_displayioctl, | |||
| 317 | #if NWSDISPLAY1 > 0 | |||
| 318 | .dsetdisplay = wskbd_set_display, | |||
| 319 | #else | |||
| 320 | .dsetdisplay = NULL((void *)0), | |||
| 321 | #endif | |||
| 322 | }; | |||
| 323 | #endif | |||
| 324 | ||||
| 325 | #if NWSDISPLAY1 > 0 | |||
| 326 | void wskbd_repeat(void *v); | |||
| 327 | #endif | |||
| 328 | ||||
| 329 | static int wskbd_console_initted; | |||
| 330 | static struct wskbd_softc *wskbd_console_device; | |||
| 331 | static struct wskbd_internal wskbd_console_data; | |||
| 332 | ||||
| 333 | void wskbd_update_layout(struct wskbd_internal *, kbd_t); | |||
| 334 | ||||
| 335 | #if NAUDIO1 > 0 | |||
| 336 | extern int wskbd_set_mixervolume_dev(void *, long, long); | |||
| 337 | #endif | |||
| 338 | ||||
| 339 | void | |||
| 340 | wskbd_update_layout(struct wskbd_internal *id, kbd_t enc) | |||
| 341 | { | |||
| 342 | if (enc & KB_METAESC0x00000020) | |||
| 343 | id->t_flags |= WSKFL_METAESC1; | |||
| 344 | else | |||
| 345 | id->t_flags &= ~WSKFL_METAESC1; | |||
| 346 | ||||
| 347 | id->t_keymap.layout = enc; | |||
| 348 | } | |||
| 349 | ||||
| 350 | /* | |||
| 351 | * Print function (for parent devices). | |||
| 352 | */ | |||
| 353 | int | |||
| 354 | wskbddevprint(void *aux, const char *pnp) | |||
| 355 | { | |||
| 356 | #if 0 | |||
| 357 | struct wskbddev_attach_args *ap = aux; | |||
| 358 | #endif | |||
| 359 | ||||
| 360 | if (pnp) | |||
| 361 | printf("wskbd at %s", pnp); | |||
| 362 | #if 0 | |||
| 363 | printf(" console %d", ap->console); | |||
| 364 | #endif | |||
| 365 | ||||
| 366 | return (UNCONF1); | |||
| 367 | } | |||
| 368 | ||||
| 369 | int | |||
| 370 | wskbd_match(struct device *parent, void *match, void *aux) | |||
| 371 | { | |||
| 372 | struct cfdata *cf = match; | |||
| 373 | struct wskbddev_attach_args *ap = aux; | |||
| 374 | ||||
| 375 | if (cf->wskbddevcf_consolecf_loc[0] != WSKBDDEVCF_CONSOLE_UNK-1) { | |||
| 376 | /* | |||
| 377 | * If console-ness of device specified, either match | |||
| 378 | * exactly (at high priority), or fail. | |||
| 379 | */ | |||
| 380 | if (cf->wskbddevcf_consolecf_loc[0] != 0 && ap->console != 0) | |||
| 381 | return (10); | |||
| 382 | else | |||
| 383 | return (0); | |||
| 384 | } | |||
| 385 | ||||
| 386 | /* If console-ness unspecified, it wins. */ | |||
| 387 | return (1); | |||
| 388 | } | |||
| 389 | ||||
| 390 | void | |||
| 391 | wskbd_attach(struct device *parent, struct device *self, void *aux) | |||
| 392 | { | |||
| 393 | struct wskbd_softc *sc = (struct wskbd_softc *)self; | |||
| 394 | struct wskbddev_attach_args *ap = aux; | |||
| 395 | kbd_t layout; | |||
| 396 | #if NWSMUX1 > 0 | |||
| 397 | struct wsmux_softc *wsmux_sc = NULL((void *)0); | |||
| 398 | int mux, error; | |||
| 399 | #endif | |||
| 400 | ||||
| 401 | sc->sc_isconsole = ap->console; | |||
| 402 | ||||
| 403 | #if NWSMUX1 > 0 || NWSDISPLAY1 > 0 | |||
| 404 | sc->sc_base.me_ops = &wskbd_srcops; | |||
| 405 | #endif | |||
| 406 | #if NWSMUX1 > 0 | |||
| 407 | mux = sc->sc_base.me_dv.dv_cfdata->wskbddevcf_muxcf_loc[1]; | |||
| 408 | if (mux >= 0) | |||
| 409 | wsmux_sc = wsmux_getmux(mux); | |||
| 410 | #endif /* NWSMUX > 0 */ | |||
| 411 | ||||
| 412 | if (ap->console) { | |||
| 413 | sc->id = &wskbd_console_data; | |||
| 414 | } else { | |||
| 415 | sc->id = malloc(sizeof(struct wskbd_internal), | |||
| 416 | M_DEVBUF2, M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 417 | bcopy(ap->keymap, &sc->id->t_keymap, sizeof(sc->id->t_keymap)); | |||
| 418 | } | |||
| 419 | ||||
| 420 | task_set(&sc->sc_kbd_backlight_task, wskbd_kbd_backlight_task, sc); | |||
| 421 | #if NWSDISPLAY1 > 0 | |||
| 422 | timeout_set(&sc->sc_repeat_ch, wskbd_repeat, sc); | |||
| 423 | task_set(&sc->sc_brightness_task, wskbd_brightness_task, sc); | |||
| 424 | #endif | |||
| 425 | ||||
| 426 | #if NAUDIO1 > 0 | |||
| 427 | sc->sc_audiocookie = ap->audiocookie; | |||
| 428 | #endif | |||
| 429 | ||||
| 430 | sc->id->t_sc = sc; | |||
| 431 | ||||
| 432 | sc->sc_accessops = ap->accessops; | |||
| 433 | sc->sc_accesscookie = ap->accesscookie; | |||
| 434 | sc->sc_repeating = 0; | |||
| 435 | sc->sc_translating = 1; | |||
| 436 | sc->sc_ledstate = -1; /* force update */ | |||
| 437 | ||||
| 438 | /* | |||
| 439 | * If this layout is the default choice of the driver (i.e. the | |||
| 440 | * driver doesn't know better), pick the existing layout of the | |||
| 441 | * current mux, if any. | |||
| 442 | */ | |||
| 443 | layout = sc->id->t_keymap.layout; | |||
| 444 | #if NWSMUX1 > 0 | |||
| 445 | if (layout & KB_DEFAULT0x80000000) { | |||
| 446 | if (wsmux_sc != NULL((void *)0) && wsmux_get_layout(wsmux_sc) != KB_NONE0x0000) | |||
| 447 | layout = wsmux_get_layout(wsmux_sc); | |||
| 448 | } | |||
| 449 | #endif | |||
| 450 | for (;;) { | |||
| 451 | struct wscons_keymap *map; | |||
| 452 | int maplen; | |||
| 453 | ||||
| 454 | if (wskbd_load_keymap(&sc->id->t_keymap, layout, &map, | |||
| 455 | &maplen) == 0) { | |||
| 456 | wskbd_set_keymap(sc, map, maplen); | |||
| 457 | break; | |||
| 458 | } | |||
| 459 | #if NWSMUX1 > 0 | |||
| 460 | if (layout == sc->id->t_keymap.layout) | |||
| 461 | panic("cannot load keymap"); | |||
| 462 | if (wsmux_sc != NULL((void *)0) && wsmux_get_layout(wsmux_sc) != KB_NONE0x0000) { | |||
| 463 | printf("\n%s: cannot load keymap, " | |||
| 464 | "falling back to default\n%s", | |||
| 465 | sc->sc_base.me_dv.dv_xname, | |||
| 466 | sc->sc_base.me_dv.dv_xname); | |||
| 467 | layout = wsmux_get_layout(wsmux_sc); | |||
| 468 | } else | |||
| 469 | #endif | |||
| 470 | panic("cannot load keymap"); | |||
| 471 | } | |||
| 472 | wskbd_update_layout(sc->id, layout); | |||
| 473 | ||||
| 474 | /* set default bell and key repeat data */ | |||
| 475 | sc->sc_bell_data = wskbd_default_bell_data; | |||
| 476 | sc->sc_keyrepeat_data = wskbd_default_keyrepeat_data; | |||
| 477 | ||||
| 478 | if (ap->console) { | |||
| 479 | KASSERT(wskbd_console_initted)((wskbd_console_initted) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/wscons/wskbd.c" , 479, "wskbd_console_initted")); | |||
| 480 | KASSERT(wskbd_console_device == NULL)((wskbd_console_device == ((void *)0)) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/dev/wscons/wskbd.c", 480, "wskbd_console_device == NULL" )); | |||
| 481 | ||||
| 482 | wskbd_console_device = sc; | |||
| 483 | ||||
| 484 | printf(": console keyboard"); | |||
| 485 | ||||
| 486 | #if NWSDISPLAY1 > 0 | |||
| 487 | wsdisplay_set_console_kbd(&sc->sc_base); /* sets sc_displaydv */ | |||
| 488 | if (sc->sc_displaydvsc_base.me_dispdv != NULL((void *)0)) | |||
| 489 | printf(", using %s", sc->sc_displaydvsc_base.me_dispdv->dv_xname); | |||
| 490 | #endif | |||
| 491 | } | |||
| 492 | ||||
| 493 | #if NWSMUX1 > 0 | |||
| 494 | /* Ignore mux for console; it always goes to the console mux. */ | |||
| 495 | if (wsmux_sc != NULL((void *)0) && ap->console == 0) { | |||
| 496 | printf(" mux %d\n", mux); | |||
| 497 | error = wsmux_attach_sc(wsmux_sc, &sc->sc_base); | |||
| 498 | if (error) | |||
| 499 | printf("%s: attach error=%d\n", | |||
| 500 | sc->sc_base.me_dv.dv_xname, error); | |||
| 501 | ||||
| 502 | /* | |||
| 503 | * Try and set this encoding as the mux default if it | |||
| 504 | * hasn't any yet, and if this is not a driver default | |||
| 505 | * layout (i.e. parent driver pretends to know better). | |||
| 506 | * Note that wsmux_set_layout() rejects layouts with | |||
| 507 | * KB_DEFAULT set. | |||
| 508 | */ | |||
| 509 | if (wsmux_get_layout(wsmux_sc) == KB_NONE0x0000) | |||
| 510 | wsmux_set_layout(wsmux_sc, layout); | |||
| 511 | } else | |||
| 512 | #endif | |||
| 513 | printf("\n"); | |||
| 514 | ||||
| 515 | #if NWSDISPLAY1 > 0 && NWSMUX1 == 0 | |||
| 516 | if (ap->console == 0) { | |||
| 517 | /* | |||
| 518 | * In the non-wsmux world, always connect wskbd0 and wsdisplay0 | |||
| 519 | * together. | |||
| 520 | */ | |||
| 521 | extern struct cfdriver wsdisplay_cd; | |||
| 522 | ||||
| 523 | if (wsdisplay_cd.cd_ndevs != 0 && self->dv_unit == 0) { | |||
| 524 | if (wskbd_set_display(self, | |||
| 525 | wsdisplay_cd.cd_devs[0]) == 0) | |||
| 526 | wsdisplay_set_kbd(wsdisplay_cd.cd_devs[0], | |||
| 527 | (struct wsevsrc *)sc); | |||
| 528 | } | |||
| 529 | } | |||
| 530 | #endif | |||
| 531 | } | |||
| 532 | ||||
| 533 | void | |||
| 534 | wskbd_cnattach(const struct wskbd_consops *consops, void *conscookie, | |||
| 535 | const struct wskbd_mapdata *mapdata) | |||
| 536 | { | |||
| 537 | ||||
| 538 | KASSERT(!wskbd_console_initted)((!wskbd_console_initted) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/wscons/wskbd.c", 538, "!wskbd_console_initted" )); | |||
| 539 | ||||
| 540 | bcopy(mapdata, &wskbd_console_data.t_keymap, sizeof(*mapdata)); | |||
| 541 | wskbd_update_layout(&wskbd_console_data, mapdata->layout); | |||
| 542 | ||||
| 543 | wskbd_console_data.t_consops = consops; | |||
| 544 | wskbd_console_data.t_consaccesscookie = conscookie; | |||
| 545 | ||||
| 546 | #if NWSDISPLAY1 > 0 | |||
| 547 | wsdisplay_set_cons_kbd(wskbd_cngetc, wskbd_cnpollc, wskbd_cnbell); | |||
| 548 | #endif | |||
| 549 | ||||
| 550 | wskbd_console_initted = 1; | |||
| 551 | } | |||
| 552 | ||||
| 553 | void | |||
| 554 | wskbd_cndetach(void) | |||
| 555 | { | |||
| 556 | KASSERT(wskbd_console_initted)((wskbd_console_initted) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/wscons/wskbd.c" , 556, "wskbd_console_initted")); | |||
| 557 | ||||
| 558 | wskbd_console_data.t_keymap.keydesc = NULL((void *)0); | |||
| 559 | wskbd_console_data.t_keymap.layout = KB_NONE0x0000; | |||
| 560 | ||||
| 561 | wskbd_console_data.t_consops = NULL((void *)0); | |||
| 562 | wskbd_console_data.t_consaccesscookie = NULL((void *)0); | |||
| 563 | ||||
| 564 | #if NWSDISPLAY1 > 0 | |||
| 565 | wsdisplay_unset_cons_kbd(); | |||
| 566 | #endif | |||
| 567 | ||||
| 568 | wskbd_console_device = NULL((void *)0); | |||
| 569 | wskbd_console_initted = 0; | |||
| 570 | } | |||
| 571 | ||||
| 572 | #if NWSDISPLAY1 > 0 | |||
| 573 | void | |||
| 574 | wskbd_repeat(void *v) | |||
| 575 | { | |||
| 576 | struct wskbd_softc *sc = (struct wskbd_softc *)v; | |||
| 577 | int s = spltty()splraise(0x9); | |||
| 578 | ||||
| 579 | if (sc->sc_repeating == 0) { | |||
| 580 | /* | |||
| 581 | * race condition: a "key up" event came in when wskbd_repeat() | |||
| 582 | * was already called but not yet spltty()'d | |||
| 583 | */ | |||
| 584 | splx(s)spllower(s); | |||
| 585 | return; | |||
| 586 | } | |||
| 587 | if (sc->sc_translating) { | |||
| 588 | /* deliver keys */ | |||
| 589 | if (sc->sc_displaydvsc_base.me_dispdv != NULL((void *)0)) | |||
| 590 | wsdisplay_kbdinput(sc->sc_displaydvsc_base.me_dispdv, | |||
| 591 | sc->id->t_keymap.layout, | |||
| 592 | sc->id->t_symbols, sc->sc_repeating); | |||
| 593 | } else { | |||
| 594 | /* queue event */ | |||
| 595 | wskbd_deliver_event(sc, sc->sc_repeat_type, | |||
| 596 | sc->sc_repeat_value); | |||
| 597 | } | |||
| 598 | if (sc->sc_keyrepeat_data.delN != 0) | |||
| 599 | timeout_add_msec(&sc->sc_repeat_ch, sc->sc_keyrepeat_data.delN); | |||
| 600 | splx(s)spllower(s); | |||
| 601 | } | |||
| 602 | #endif | |||
| 603 | ||||
| 604 | int | |||
| 605 | wskbd_activate(struct device *self, int act) | |||
| 606 | { | |||
| 607 | struct wskbd_softc *sc = (struct wskbd_softc *)self; | |||
| 608 | ||||
| 609 | if (act == DVACT_DEACTIVATE1) | |||
| 610 | sc->sc_dying = 1; | |||
| 611 | return (0); | |||
| 612 | } | |||
| 613 | ||||
| 614 | /* | |||
| 615 | * Detach a keyboard. To keep track of users of the softc we keep | |||
| 616 | * a reference count that's incremented while inside, e.g., read. | |||
| 617 | * If the keyboard is active and the reference count is > 0 (0 is the | |||
| 618 | * normal state) we post an event and then wait for the process | |||
| 619 | * that had the reference to wake us up again. Then we blow away the | |||
| 620 | * vnode and return (which will deallocate the softc). | |||
| 621 | */ | |||
| 622 | int | |||
| 623 | wskbd_detach(struct device *self, int flags) | |||
| 624 | { | |||
| 625 | struct wskbd_softc *sc = (struct wskbd_softc *)self; | |||
| 626 | struct wseventvar *evar; | |||
| 627 | int maj, mn; | |||
| 628 | int s; | |||
| 629 | ||||
| 630 | #if NWSMUX1 > 0 | |||
| 631 | /* Tell parent mux we're leaving. */ | |||
| 632 | if (sc->sc_base.me_parent != NULL((void *)0)) | |||
| 633 | wsmux_detach_sc(&sc->sc_base); | |||
| 634 | #endif | |||
| 635 | ||||
| 636 | #if NWSDISPLAY1 > 0 | |||
| 637 | if (sc->sc_repeating) { | |||
| 638 | sc->sc_repeating = 0; | |||
| 639 | timeout_del(&sc->sc_repeat_ch); | |||
| 640 | } | |||
| 641 | #endif | |||
| 642 | ||||
| 643 | if (sc->sc_isconsole) { | |||
| 644 | KASSERT(wskbd_console_device == sc)((wskbd_console_device == sc) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/dev/wscons/wskbd.c", 644, "wskbd_console_device == sc" )); | |||
| 645 | wskbd_cndetach(); | |||
| 646 | } | |||
| 647 | ||||
| 648 | evar = sc->sc_base.me_evp; | |||
| 649 | if (evar != NULL((void *)0)) { | |||
| 650 | s = spltty()splraise(0x9); | |||
| 651 | if (--sc->sc_refcnt >= 0) { | |||
| 652 | /* Wake everyone by generating a dummy event. */ | |||
| 653 | if (++evar->put >= WSEVENT_QSIZE256) | |||
| 654 | evar->put = 0; | |||
| 655 | WSEVENT_WAKEUP(evar){ selwakeup(&(evar)->sel); if ((evar)->wanted) { (evar )->wanted = 0; wakeup((caddr_t)(evar)); } if ((evar)->async ) pgsigio(&(evar)->sigio, 23, 0); }; | |||
| 656 | /* Wait for processes to go away. */ | |||
| 657 | if (tsleep_nsec(sc, PZERO22, "wskdet", SEC_TO_NSEC(60))) | |||
| 658 | printf("wskbd_detach: %s didn't detach\n", | |||
| 659 | sc->sc_base.me_dv.dv_xname); | |||
| 660 | } | |||
| 661 | splx(s)spllower(s); | |||
| 662 | } | |||
| 663 | ||||
| 664 | free(sc->sc_map, M_DEVBUF2, | |||
| 665 | sc->sc_maplen * sizeof(struct wscons_keymap)); | |||
| 666 | ||||
| 667 | /* locate the major number */ | |||
| 668 | for (maj = 0; maj < nchrdev; maj++) | |||
| 669 | if (cdevsw[maj].d_open == wskbdopen) | |||
| 670 | break; | |||
| 671 | ||||
| 672 | /* Nuke the vnodes for any open instances. */ | |||
| 673 | mn = self->dv_unit; | |||
| 674 | vdevgone(maj, mn, mn, VCHR); | |||
| 675 | ||||
| 676 | return (0); | |||
| 677 | } | |||
| 678 | ||||
| 679 | void | |||
| 680 | wskbd_input(struct device *dev, u_int type, int value) | |||
| 681 | { | |||
| 682 | struct wskbd_softc *sc = (struct wskbd_softc *)dev; | |||
| 683 | #if NWSDISPLAY1 > 0 | |||
| 684 | int num; | |||
| 685 | #endif | |||
| 686 | ||||
| 687 | #if NWSDISPLAY1 > 0 | |||
| 688 | if (sc->sc_repeating) { | |||
| 689 | sc->sc_repeating = 0; | |||
| 690 | timeout_del(&sc->sc_repeat_ch); | |||
| 691 | } | |||
| 692 | ||||
| 693 | /* | |||
| 694 | * If /dev/wskbdN is not connected in event mode translate and | |||
| 695 | * send upstream. | |||
| 696 | */ | |||
| 697 | if (sc->sc_translating) { | |||
| 698 | #ifdef HAVE_BURNER_SUPPORT | |||
| 699 | if (type == WSCONS_EVENT_KEY_DOWN2 && sc->sc_displaydvsc_base.me_dispdv != NULL((void *)0)) | |||
| 700 | wsdisplay_burn(sc->sc_displaydvsc_base.me_dispdv, WSDISPLAY_BURN_KBD0x0002); | |||
| 701 | #endif | |||
| 702 | num = wskbd_translate(sc->id, type, value); | |||
| 703 | if (num > 0) { | |||
| 704 | if (sc->sc_displaydvsc_base.me_dispdv != NULL((void *)0)) { | |||
| 705 | #ifdef HAVE_SCROLLBACK_SUPPORT | |||
| 706 | /* XXX - Shift_R+PGUP(release) emits PrtSc */ | |||
| 707 | if (sc->id->t_symbols[0] != KS_Print_Screen0xf3c2) { | |||
| 708 | wsscrollback(sc->sc_displaydvsc_base.me_dispdv, | |||
| 709 | WSDISPLAY_SCROLL_RESET2); | |||
| 710 | } | |||
| 711 | #endif | |||
| 712 | wsdisplay_kbdinput(sc->sc_displaydvsc_base.me_dispdv, | |||
| 713 | sc->id->t_keymap.layout, | |||
| 714 | sc->id->t_symbols, num); | |||
| 715 | } | |||
| 716 | ||||
| 717 | if (sc->sc_keyrepeat_data.del1 != 0) { | |||
| 718 | sc->sc_repeating = num; | |||
| 719 | timeout_add_msec(&sc->sc_repeat_ch, | |||
| 720 | sc->sc_keyrepeat_data.del1); | |||
| 721 | } | |||
| 722 | } | |||
| 723 | return; | |||
| 724 | } | |||
| 725 | #endif | |||
| 726 | ||||
| 727 | wskbd_deliver_event(sc, type, value); | |||
| 728 | ||||
| 729 | #if NWSDISPLAY1 > 0 | |||
| 730 | /* Repeat key presses if enabled. */ | |||
| 731 | if (type == WSCONS_EVENT_KEY_DOWN2 && sc->sc_keyrepeat_data.del1 != 0) { | |||
| 732 | sc->sc_repeat_type = type; | |||
| 733 | sc->sc_repeat_value = value; | |||
| 734 | sc->sc_repeating = 1; | |||
| 735 | timeout_add_msec(&sc->sc_repeat_ch, sc->sc_keyrepeat_data.del1); | |||
| 736 | } | |||
| 737 | #endif | |||
| 738 | } | |||
| 739 | ||||
| 740 | /* | |||
| 741 | * Keyboard is generating events. Turn this keystroke into an | |||
| 742 | * event and put it in the queue. If the queue is full, the | |||
| 743 | * keystroke is lost (sorry!). | |||
| 744 | */ | |||
| 745 | void | |||
| 746 | wskbd_deliver_event(struct wskbd_softc *sc, u_int type, int value) | |||
| 747 | { | |||
| 748 | struct wseventvar *evar; | |||
| 749 | struct wscons_event *ev; | |||
| 750 | int put; | |||
| 751 | ||||
| 752 | evar = sc->sc_base.me_evp; | |||
| 753 | ||||
| 754 | if (evar == NULL((void *)0)) { | |||
| 755 | DPRINTF(("%s: not open\n", __func__)); | |||
| 756 | return; | |||
| 757 | } | |||
| 758 | ||||
| 759 | #ifdef DIAGNOSTIC1 | |||
| 760 | if (evar->q == NULL((void *)0)) { | |||
| 761 | printf("wskbd_input: evar->q=NULL\n"); | |||
| 762 | return; | |||
| 763 | } | |||
| 764 | #endif | |||
| 765 | ||||
| 766 | put = evar->put; | |||
| 767 | ev = &evar->q[put]; | |||
| 768 | put = (put + 1) % WSEVENT_QSIZE256; | |||
| 769 | if (put == evar->get) { | |||
| 770 | log(LOG_WARNING4, "%s: event queue overflow\n", | |||
| 771 | sc->sc_base.me_dv.dv_xname); | |||
| 772 | return; | |||
| 773 | } | |||
| 774 | ev->type = type; | |||
| 775 | ev->value = value; | |||
| 776 | nanotime(&ev->time); | |||
| 777 | evar->put = put; | |||
| 778 | WSEVENT_WAKEUP(evar){ selwakeup(&(evar)->sel); if ((evar)->wanted) { (evar )->wanted = 0; wakeup((caddr_t)(evar)); } if ((evar)->async ) pgsigio(&(evar)->sigio, 23, 0); }; | |||
| 779 | } | |||
| 780 | ||||
| 781 | #ifdef WSDISPLAY_COMPAT_RAWKBD1 | |||
| 782 | void | |||
| 783 | wskbd_rawinput(struct device *dev, u_char *buf, int len) | |||
| 784 | { | |||
| 785 | #if NWSDISPLAY1 > 0 | |||
| 786 | struct wskbd_softc *sc = (struct wskbd_softc *)dev; | |||
| 787 | ||||
| 788 | if (sc->sc_displaydvsc_base.me_dispdv != NULL((void *)0)) | |||
| 789 | wsdisplay_rawkbdinput(sc->sc_displaydvsc_base.me_dispdv, buf, len); | |||
| 790 | #endif | |||
| 791 | } | |||
| 792 | #endif /* WSDISPLAY_COMPAT_RAWKBD */ | |||
| 793 | ||||
| 794 | int | |||
| 795 | wskbd_enable(struct wskbd_softc *sc, int on) | |||
| 796 | { | |||
| 797 | int error; | |||
| 798 | ||||
| 799 | #if NWSDISPLAY1 > 0 | |||
| 800 | if (sc->sc_displaydvsc_base.me_dispdv != NULL((void *)0)) | |||
| 801 | return (0); | |||
| 802 | ||||
| 803 | /* Always cancel auto repeat when fiddling with the kbd. */ | |||
| 804 | if (sc->sc_repeating) { | |||
| 805 | sc->sc_repeating = 0; | |||
| 806 | timeout_del(&sc->sc_repeat_ch); | |||
| 807 | } | |||
| 808 | #endif | |||
| 809 | ||||
| 810 | error = (*sc->sc_accessops->enable)(sc->sc_accesscookie, on); | |||
| 811 | DPRINTF(("%s: sc=%p on=%d res=%d\n", __func__, sc, on, error)); | |||
| 812 | return (error); | |||
| 813 | } | |||
| 814 | ||||
| 815 | #if NWSMUX1 > 0 | |||
| 816 | int | |||
| 817 | wskbd_mux_open(struct wsevsrc *me, struct wseventvar *evp) | |||
| 818 | { | |||
| 819 | struct wskbd_softc *sc = (struct wskbd_softc *)me; | |||
| 820 | ||||
| 821 | if (sc->sc_dying) | |||
| 822 | return (EIO5); | |||
| 823 | ||||
| 824 | return (wskbd_do_open(sc, evp)); | |||
| 825 | } | |||
| 826 | #endif | |||
| 827 | ||||
| 828 | int | |||
| 829 | wskbdopen(dev_t dev, int flags, int mode, struct proc *p) | |||
| 830 | { | |||
| 831 | struct wskbd_softc *sc; | |||
| 832 | struct wseventvar *evar; | |||
| 833 | int unit, error; | |||
| 834 | ||||
| 835 | unit = minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8)); | |||
| 836 | if (unit >= wskbd_cd.cd_ndevs || /* make sure it was attached */ | |||
| 837 | (sc = wskbd_cd.cd_devs[unit]) == NULL((void *)0)) | |||
| 838 | return (ENXIO6); | |||
| 839 | ||||
| 840 | #if NWSMUX1 > 0 | |||
| 841 | DPRINTF(("%s: %s mux=%p\n", __func__, sc->sc_base.me_dv.dv_xname, | |||
| 842 | sc->sc_base.me_parent)); | |||
| 843 | #endif | |||
| 844 | ||||
| 845 | if (sc->sc_dying) | |||
| 846 | return (EIO5); | |||
| 847 | ||||
| 848 | if ((flags & (FREAD0x0001 | FWRITE0x0002)) == FWRITE0x0002) { | |||
| 849 | /* Not opening for read, only ioctl is available. */ | |||
| 850 | return (0); | |||
| 851 | } | |||
| 852 | ||||
| 853 | #if NWSMUX1 > 0 | |||
| 854 | if (sc->sc_base.me_parent != NULL((void *)0)) { | |||
| 855 | /* Grab the keyboard out of the greedy hands of the mux. */ | |||
| 856 | DPRINTF(("%s: detach\n", __func__)); | |||
| 857 | wsmux_detach_sc(&sc->sc_base); | |||
| 858 | } | |||
| 859 | #endif | |||
| 860 | ||||
| 861 | if (sc->sc_base.me_evp != NULL((void *)0)) | |||
| 862 | return (EBUSY16); | |||
| 863 | ||||
| 864 | evar = &sc->sc_base.me_evar; | |||
| 865 | if (wsevent_init(evar)) | |||
| 866 | return (EBUSY16); | |||
| 867 | ||||
| 868 | error = wskbd_do_open(sc, evar); | |||
| 869 | if (error) | |||
| 870 | wsevent_fini(evar); | |||
| 871 | return (error); | |||
| 872 | } | |||
| 873 | ||||
| 874 | int | |||
| 875 | wskbd_do_open(struct wskbd_softc *sc, struct wseventvar *evp) | |||
| 876 | { | |||
| 877 | int error; | |||
| 878 | ||||
| 879 | /* The device could already be attached to a mux. */ | |||
| 880 | if (sc->sc_base.me_evp != NULL((void *)0)) | |||
| 881 | return (EBUSY16); | |||
| 882 | ||||
| 883 | sc->sc_base.me_evp = evp; | |||
| 884 | sc->sc_translating = 0; | |||
| 885 | ||||
| 886 | error = wskbd_enable(sc, 1); | |||
| 887 | if (error) | |||
| 888 | sc->sc_base.me_evp = NULL((void *)0); | |||
| 889 | return (error); | |||
| 890 | } | |||
| 891 | ||||
| 892 | int | |||
| 893 | wskbdclose(dev_t dev, int flags, int mode, struct proc *p) | |||
| 894 | { | |||
| 895 | struct wskbd_softc *sc = | |||
| 896 | (struct wskbd_softc *)wskbd_cd.cd_devs[minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8))]; | |||
| 897 | struct wseventvar *evar = sc->sc_base.me_evp; | |||
| 898 | ||||
| 899 | if ((flags & (FREAD0x0001 | FWRITE0x0002)) == FWRITE0x0002) { | |||
| 900 | /* not open for read */ | |||
| 901 | return (0); | |||
| 902 | } | |||
| 903 | ||||
| 904 | sc->sc_base.me_evp = NULL((void *)0); | |||
| 905 | sc->sc_translating = 1; | |||
| 906 | (void)wskbd_enable(sc, 0); | |||
| 907 | wsevent_fini(evar); | |||
| 908 | ||||
| 909 | #if NWSMUX1 > 0 | |||
| 910 | if (sc->sc_base.me_parent == NULL((void *)0)) { | |||
| 911 | int mux, error; | |||
| 912 | ||||
| 913 | DPRINTF(("%s: attach\n", __func__)); | |||
| 914 | mux = sc->sc_base.me_dv.dv_cfdata->wskbddevcf_muxcf_loc[1]; | |||
| 915 | if (mux >= 0) { | |||
| 916 | error = wsmux_attach_sc(wsmux_getmux(mux), &sc->sc_base); | |||
| 917 | if (error) | |||
| 918 | printf("%s: can't attach mux (error=%d)\n", | |||
| 919 | sc->sc_base.me_dv.dv_xname, error); | |||
| 920 | } | |||
| 921 | } | |||
| 922 | #endif | |||
| 923 | ||||
| 924 | return (0); | |||
| 925 | } | |||
| 926 | ||||
| 927 | #if NWSMUX1 > 0 | |||
| 928 | int | |||
| 929 | wskbd_mux_close(struct wsevsrc *me) | |||
| 930 | { | |||
| 931 | struct wskbd_softc *sc = (struct wskbd_softc *)me; | |||
| 932 | ||||
| 933 | (void)wskbd_enable(sc, 0); | |||
| 934 | sc->sc_translating = 1; | |||
| 935 | sc->sc_base.me_evp = NULL((void *)0); | |||
| 936 | ||||
| 937 | return (0); | |||
| 938 | } | |||
| 939 | #endif | |||
| 940 | ||||
| 941 | int | |||
| 942 | wskbdread(dev_t dev, struct uio *uio, int flags) | |||
| 943 | { | |||
| 944 | struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8))]; | |||
| 945 | int error; | |||
| 946 | ||||
| 947 | if (sc->sc_dying) | |||
| 948 | return (EIO5); | |||
| 949 | ||||
| 950 | #ifdef DIAGNOSTIC1 | |||
| 951 | if (sc->sc_base.me_evp == NULL((void *)0)) { | |||
| 952 | printf("wskbdread: evp == NULL\n"); | |||
| 953 | return (EINVAL22); | |||
| 954 | } | |||
| 955 | #endif | |||
| 956 | ||||
| 957 | sc->sc_refcnt++; | |||
| 958 | error = wsevent_read(&sc->sc_base.me_evar, uio, flags); | |||
| 959 | if (--sc->sc_refcnt < 0) { | |||
| 960 | wakeup(sc); | |||
| 961 | error = EIO5; | |||
| 962 | } | |||
| 963 | return (error); | |||
| 964 | } | |||
| 965 | ||||
| 966 | int | |||
| 967 | wskbdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) | |||
| 968 | { | |||
| 969 | struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8))]; | |||
| 970 | int error; | |||
| 971 | ||||
| 972 | sc->sc_refcnt++; | |||
| 973 | error = wskbd_do_ioctl_sc(sc, cmd, data, flag, p, 0); | |||
| 974 | if (--sc->sc_refcnt < 0) | |||
| 975 | wakeup(sc); | |||
| 976 | return (error); | |||
| 977 | } | |||
| 978 | ||||
| 979 | /* A wrapper around the ioctl() workhorse to make reference counting easy. */ | |||
| 980 | int | |||
| 981 | wskbd_do_ioctl(struct device *dv, u_long cmd, caddr_t data, int flag, | |||
| 982 | struct proc *p) | |||
| 983 | { | |||
| 984 | struct wskbd_softc *sc = (struct wskbd_softc *)dv; | |||
| 985 | int error; | |||
| 986 | ||||
| 987 | sc->sc_refcnt++; | |||
| 988 | error = wskbd_do_ioctl_sc(sc, cmd, data, flag, p, 1); | |||
| 989 | if (--sc->sc_refcnt < 0) | |||
| 990 | wakeup(sc); | |||
| 991 | return (error); | |||
| 992 | } | |||
| 993 | ||||
| 994 | int | |||
| 995 | wskbd_do_ioctl_sc(struct wskbd_softc *sc, u_long cmd, caddr_t data, int flag, | |||
| 996 | struct proc *p, int evsrc) | |||
| 997 | { | |||
| 998 | struct wseventvar *evar; | |||
| 999 | int error; | |||
| 1000 | ||||
| 1001 | /* | |||
| 1002 | * Try the generic ioctls that the wskbd interface supports. | |||
| 1003 | */ | |||
| 1004 | switch (cmd) { | |||
| 1005 | case FIONBIO((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) << 16) | ((('f')) << 8) | ((126))): /* we will remove this someday (soon???) */ | |||
| 1006 | return (0); | |||
| 1007 | ||||
| 1008 | case FIOASYNC((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) << 16) | ((('f')) << 8) | ((125))): | |||
| 1009 | if (sc->sc_base.me_evp == NULL((void *)0)) | |||
| 1010 | return (EINVAL22); | |||
| 1011 | sc->sc_base.me_evp->async = *(int *)data != 0; | |||
| 1012 | return (0); | |||
| 1013 | ||||
| 1014 | case FIOGETOWN((unsigned long)0x40000000 | ((sizeof(int) & 0x1fff) << 16) | ((('f')) << 8) | ((123))): | |||
| 1015 | case TIOCGPGRP((unsigned long)0x40000000 | ((sizeof(int) & 0x1fff) << 16) | ((('t')) << 8) | ((119))): | |||
| 1016 | evar = sc->sc_base.me_evp; | |||
| 1017 | if (evar == NULL((void *)0)) | |||
| 1018 | return (EINVAL22); | |||
| 1019 | sigio_getown(&evar->sigio, cmd, data); | |||
| 1020 | return (0); | |||
| 1021 | ||||
| 1022 | case FIOSETOWN((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) << 16) | ((('f')) << 8) | ((124))): | |||
| 1023 | case TIOCSPGRP((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) << 16) | ((('t')) << 8) | ((118))): | |||
| 1024 | evar = sc->sc_base.me_evp; | |||
| 1025 | if (evar == NULL((void *)0)) | |||
| 1026 | return (EINVAL22); | |||
| 1027 | return (sigio_setown(&evar->sigio, cmd, data)); | |||
| 1028 | } | |||
| 1029 | ||||
| 1030 | /* | |||
| 1031 | * Try the keyboard driver for WSKBDIO ioctls. It returns -1 | |||
| 1032 | * if it didn't recognize the request. | |||
| 1033 | */ | |||
| 1034 | error = wskbd_displayioctl_sc(sc, cmd, data, flag, p, evsrc); | |||
| 1035 | return (error != -1 ? error : ENOTTY25); | |||
| 1036 | } | |||
| 1037 | ||||
| 1038 | /* | |||
| 1039 | * WSKBDIO ioctls, handled in both emulation mode and in ``raw'' mode. | |||
| 1040 | * Some of these have no real effect in raw mode, however. | |||
| 1041 | */ | |||
| 1042 | int | |||
| 1043 | wskbd_displayioctl(struct device *dv, u_long cmd, caddr_t data, int flag, | |||
| 1044 | struct proc *p) | |||
| 1045 | { | |||
| 1046 | struct wskbd_softc *sc = (struct wskbd_softc *)dv; | |||
| 1047 | ||||
| 1048 | return (wskbd_displayioctl_sc(sc, cmd, data, flag, p, 1)); | |||
| 1049 | } | |||
| 1050 | ||||
| 1051 | int | |||
| 1052 | wskbd_displayioctl_sc(struct wskbd_softc *sc, u_long cmd, caddr_t data, | |||
| 1053 | int flag, struct proc *p, int evsrc) | |||
| 1054 | { | |||
| 1055 | struct wskbd_bell_data *ubdp, *kbdp; | |||
| 1056 | struct wskbd_keyrepeat_data *ukdp, *kkdp; | |||
| 1057 | struct wskbd_map_data *umdp; | |||
| 1058 | struct wskbd_encoding_data *uedp; | |||
| 1059 | kbd_t enc; | |||
| 1060 | void *buf; | |||
| 1061 | int len, error; | |||
| 1062 | int count, i; | |||
| 1063 | ||||
| 1064 | switch (cmd) { | |||
| 1065 | case WSKBDIO_BELL((unsigned long)0x20000000 | ((0 & 0x1fff) << 16) | ((('W')) << 8) | ((1))): | |||
| 1066 | case WSKBDIO_COMPLEXBELL((unsigned long)0x80000000 | ((sizeof(struct wskbd_bell_data) & 0x1fff) << 16) | ((('W')) << 8) | ((2))): | |||
| 1067 | case WSKBDIO_SETBELL((unsigned long)0x80000000 | ((sizeof(struct wskbd_bell_data) & 0x1fff) << 16) | ((('W')) << 8) | ((3))): | |||
| 1068 | case WSKBDIO_SETKEYREPEAT((unsigned long)0x80000000 | ((sizeof(struct wskbd_keyrepeat_data ) & 0x1fff) << 16) | ((('W')) << 8) | ((7))): | |||
| 1069 | case WSKBDIO_SETDEFAULTKEYREPEAT((unsigned long)0x80000000 | ((sizeof(struct wskbd_keyrepeat_data ) & 0x1fff) << 16) | ((('W')) << 8) | ((9))): | |||
| 1070 | case WSKBDIO_SETMAP((unsigned long)0x80000000 | ((sizeof(struct wskbd_map_data) & 0x1fff) << 16) | ((('W')) << 8) | ((14))): | |||
| 1071 | case WSKBDIO_SETENCODING((unsigned long)0x80000000 | ((sizeof(kbd_t) & 0x1fff) << 16) | ((('W')) << 8) | ((16))): | |||
| 1072 | case WSKBDIO_SETBACKLIGHT((unsigned long)0x80000000 | ((sizeof(struct wskbd_backlight) & 0x1fff) << 16) | ((('W')) << 8) | ((18))): | |||
| 1073 | if ((flag & FWRITE0x0002) == 0) | |||
| 1074 | return (EACCES13); | |||
| 1075 | } | |||
| 1076 | ||||
| 1077 | switch (cmd) { | |||
| 1078 | #define SETBELL(dstp, srcp, dfltp) \ | |||
| 1079 | do { \ | |||
| 1080 | (dstp)->pitch = ((srcp)->which & WSKBD_BELL_DOPITCH0x1) ? \ | |||
| 1081 | (srcp)->pitch : (dfltp)->pitch; \ | |||
| 1082 | (dstp)->period = ((srcp)->which & WSKBD_BELL_DOPERIOD0x2) ? \ | |||
| 1083 | (srcp)->period : (dfltp)->period; \ | |||
| 1084 | (dstp)->volume = ((srcp)->which & WSKBD_BELL_DOVOLUME0x4) ? \ | |||
| 1085 | (srcp)->volume : (dfltp)->volume; \ | |||
| 1086 | (dstp)->which = WSKBD_BELL_DOALL0x7; \ | |||
| 1087 | } while (0) | |||
| 1088 | ||||
| 1089 | case WSKBDIO_BELL((unsigned long)0x20000000 | ((0 & 0x1fff) << 16) | ((('W')) << 8) | ((1))): | |||
| 1090 | return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, | |||
| 1091 | WSKBDIO_COMPLEXBELL((unsigned long)0x80000000 | ((sizeof(struct wskbd_bell_data) & 0x1fff) << 16) | ((('W')) << 8) | ((2))), (caddr_t)&sc->sc_bell_data, flag, p)); | |||
| 1092 | ||||
| 1093 | case WSKBDIO_COMPLEXBELL((unsigned long)0x80000000 | ((sizeof(struct wskbd_bell_data) & 0x1fff) << 16) | ((('W')) << 8) | ((2))): | |||
| 1094 | ubdp = (struct wskbd_bell_data *)data; | |||
| 1095 | SETBELL(ubdp, ubdp, &sc->sc_bell_data); | |||
| 1096 | return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, | |||
| 1097 | WSKBDIO_COMPLEXBELL((unsigned long)0x80000000 | ((sizeof(struct wskbd_bell_data) & 0x1fff) << 16) | ((('W')) << 8) | ((2))), (caddr_t)ubdp, flag, p)); | |||
| 1098 | ||||
| 1099 | case WSKBDIO_SETBELL((unsigned long)0x80000000 | ((sizeof(struct wskbd_bell_data) & 0x1fff) << 16) | ((('W')) << 8) | ((3))): | |||
| 1100 | kbdp = &sc->sc_bell_data; | |||
| 1101 | setbell: | |||
| 1102 | ubdp = (struct wskbd_bell_data *)data; | |||
| 1103 | SETBELL(kbdp, ubdp, kbdp); | |||
| 1104 | return (0); | |||
| 1105 | ||||
| 1106 | case WSKBDIO_GETBELL((unsigned long)0x40000000 | ((sizeof(struct wskbd_bell_data) & 0x1fff) << 16) | ((('W')) << 8) | ((4))): | |||
| 1107 | kbdp = &sc->sc_bell_data; | |||
| 1108 | getbell: | |||
| 1109 | ubdp = (struct wskbd_bell_data *)data; | |||
| 1110 | SETBELL(ubdp, kbdp, kbdp); | |||
| 1111 | return (0); | |||
| 1112 | ||||
| 1113 | case WSKBDIO_SETDEFAULTBELL((unsigned long)0x80000000 | ((sizeof(struct wskbd_bell_data) & 0x1fff) << 16) | ((('W')) << 8) | ((5))): | |||
| 1114 | if ((error = suser(p)) != 0) | |||
| 1115 | return (error); | |||
| 1116 | kbdp = &wskbd_default_bell_data; | |||
| 1117 | goto setbell; | |||
| 1118 | ||||
| 1119 | ||||
| 1120 | case WSKBDIO_GETDEFAULTBELL((unsigned long)0x40000000 | ((sizeof(struct wskbd_bell_data) & 0x1fff) << 16) | ((('W')) << 8) | ((6))): | |||
| 1121 | kbdp = &wskbd_default_bell_data; | |||
| 1122 | goto getbell; | |||
| 1123 | ||||
| 1124 | #undef SETBELL | |||
| 1125 | ||||
| 1126 | #define SETKEYREPEAT(dstp, srcp, dfltp) \ | |||
| 1127 | do { \ | |||
| 1128 | (dstp)->del1 = ((srcp)->which & WSKBD_KEYREPEAT_DODEL10x1) ? \ | |||
| 1129 | (srcp)->del1 : (dfltp)->del1; \ | |||
| 1130 | (dstp)->delN = ((srcp)->which & WSKBD_KEYREPEAT_DODELN0x2) ? \ | |||
| 1131 | (srcp)->delN : (dfltp)->delN; \ | |||
| 1132 | (dstp)->which = WSKBD_KEYREPEAT_DOALL0x3; \ | |||
| 1133 | } while (0) | |||
| 1134 | ||||
| 1135 | case WSKBDIO_SETKEYREPEAT((unsigned long)0x80000000 | ((sizeof(struct wskbd_keyrepeat_data ) & 0x1fff) << 16) | ((('W')) << 8) | ((7))): | |||
| 1136 | kkdp = &sc->sc_keyrepeat_data; | |||
| 1137 | setkeyrepeat: | |||
| 1138 | ukdp = (struct wskbd_keyrepeat_data *)data; | |||
| 1139 | SETKEYREPEAT(kkdp, ukdp, kkdp); | |||
| 1140 | return (0); | |||
| 1141 | ||||
| 1142 | case WSKBDIO_GETKEYREPEAT((unsigned long)0x40000000 | ((sizeof(struct wskbd_keyrepeat_data ) & 0x1fff) << 16) | ((('W')) << 8) | ((8))): | |||
| 1143 | kkdp = &sc->sc_keyrepeat_data; | |||
| 1144 | getkeyrepeat: | |||
| 1145 | ukdp = (struct wskbd_keyrepeat_data *)data; | |||
| 1146 | SETKEYREPEAT(ukdp, kkdp, kkdp); | |||
| 1147 | return (0); | |||
| 1148 | ||||
| 1149 | case WSKBDIO_SETDEFAULTKEYREPEAT((unsigned long)0x80000000 | ((sizeof(struct wskbd_keyrepeat_data ) & 0x1fff) << 16) | ((('W')) << 8) | ((9))): | |||
| 1150 | if ((error = suser(p)) != 0) | |||
| 1151 | return (error); | |||
| 1152 | kkdp = &wskbd_default_keyrepeat_data; | |||
| 1153 | goto setkeyrepeat; | |||
| 1154 | ||||
| 1155 | ||||
| 1156 | case WSKBDIO_GETDEFAULTKEYREPEAT((unsigned long)0x40000000 | ((sizeof(struct wskbd_keyrepeat_data ) & 0x1fff) << 16) | ((('W')) << 8) | ((10))): | |||
| 1157 | kkdp = &wskbd_default_keyrepeat_data; | |||
| 1158 | goto getkeyrepeat; | |||
| 1159 | ||||
| 1160 | #undef SETKEYREPEAT | |||
| 1161 | ||||
| 1162 | case WSKBDIO_SETMAP((unsigned long)0x80000000 | ((sizeof(struct wskbd_map_data) & 0x1fff) << 16) | ((('W')) << 8) | ((14))): | |||
| 1163 | umdp = (struct wskbd_map_data *)data; | |||
| 1164 | if (umdp->maplen > WSKBDIO_MAXMAPLEN65536) | |||
| 1165 | return (EINVAL22); | |||
| 1166 | ||||
| 1167 | buf = mallocarray(umdp->maplen, sizeof(struct wscons_keymap), | |||
| 1168 | M_TEMP127, M_WAITOK0x0001); | |||
| 1169 | len = umdp->maplen * sizeof(struct wscons_keymap); | |||
| 1170 | ||||
| 1171 | error = copyin(umdp->map, buf, len); | |||
| 1172 | if (error == 0) { | |||
| 1173 | struct wscons_keymap *map; | |||
| 1174 | ||||
| 1175 | map = wskbd_init_keymap(umdp->maplen); | |||
| 1176 | memcpy(map, buf, len)__builtin_memcpy((map), (buf), (len)); | |||
| 1177 | wskbd_set_keymap(sc, map, umdp->maplen); | |||
| 1178 | /* drop the variant bits handled by the map */ | |||
| 1179 | enc = KB_USER0x0100 | (KB_VARIANT(sc->id->t_keymap.layout)((sc->id->t_keymap.layout) & 0xffff00ff) & | |||
| 1180 | KB_HANDLEDBYWSKBD(0x00000020 | 0x80000000 | 0x00000080)); | |||
| 1181 | wskbd_update_layout(sc->id, enc); | |||
| 1182 | } | |||
| 1183 | free(buf, M_TEMP127, len); | |||
| 1184 | return(error); | |||
| 1185 | ||||
| 1186 | case WSKBDIO_GETMAP(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct wskbd_map_data) & 0x1fff) << 16) | ((('W')) << 8) | ((13))): | |||
| 1187 | umdp = (struct wskbd_map_data *)data; | |||
| 1188 | if (umdp->maplen > sc->sc_maplen) | |||
| 1189 | umdp->maplen = sc->sc_maplen; | |||
| 1190 | error = copyout(sc->sc_map, umdp->map, | |||
| 1191 | umdp->maplen*sizeof(struct wscons_keymap)); | |||
| 1192 | return(error); | |||
| 1193 | ||||
| 1194 | case WSKBDIO_GETENCODING((unsigned long)0x40000000 | ((sizeof(kbd_t) & 0x1fff) << 16) | ((('W')) << 8) | ((15))): | |||
| 1195 | /* Do not advertise encoding to the parent mux. */ | |||
| 1196 | if (evsrc && (sc->id->t_keymap.layout & KB_NOENCODING0x00000080)) | |||
| 1197 | return (ENOTTY25); | |||
| 1198 | *((kbd_t *)data) = sc->id->t_keymap.layout & ~KB_DEFAULT0x80000000; | |||
| 1199 | return(0); | |||
| 1200 | ||||
| 1201 | case WSKBDIO_SETENCODING((unsigned long)0x80000000 | ((sizeof(kbd_t) & 0x1fff) << 16) | ((('W')) << 8) | ((16))): | |||
| 1202 | enc = *((kbd_t *)data); | |||
| 1203 | if (KB_ENCODING(enc)((enc) & 0x0000ff00) == KB_USER0x0100) { | |||
| 1204 | /* user map must already be loaded */ | |||
| 1205 | if (KB_ENCODING(sc->id->t_keymap.layout)((sc->id->t_keymap.layout) & 0x0000ff00) != KB_USER0x0100) | |||
| 1206 | return (EINVAL22); | |||
| 1207 | /* map variants make no sense */ | |||
| 1208 | if (KB_VARIANT(enc)((enc) & 0xffff00ff) & ~KB_HANDLEDBYWSKBD(0x00000020 | 0x80000000 | 0x00000080)) | |||
| 1209 | return (EINVAL22); | |||
| 1210 | } else if (sc->id->t_keymap.layout & KB_NOENCODING0x00000080) { | |||
| 1211 | return (0); | |||
| 1212 | } else { | |||
| 1213 | struct wscons_keymap *map; | |||
| 1214 | int maplen; | |||
| 1215 | ||||
| 1216 | error = wskbd_load_keymap(&sc->id->t_keymap, enc, | |||
| 1217 | &map, &maplen); | |||
| 1218 | if (error) | |||
| 1219 | return (error); | |||
| 1220 | wskbd_set_keymap(sc, map, maplen); | |||
| 1221 | } | |||
| 1222 | wskbd_update_layout(sc->id, enc); | |||
| 1223 | #if NWSMUX1 > 0 | |||
| 1224 | /* Update mux default layout */ | |||
| 1225 | if (sc->sc_base.me_parent != NULL((void *)0)) | |||
| 1226 | wsmux_set_layout(sc->sc_base.me_parent, enc); | |||
| 1227 | #endif | |||
| 1228 | return (0); | |||
| 1229 | ||||
| 1230 | case WSKBDIO_GETENCODINGS(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct wskbd_encoding_data) & 0x1fff) << 16) | ((( 'W')) << 8) | ((21))): | |||
| 1231 | uedp = (struct wskbd_encoding_data *)data; | |||
| 1232 | for (count = 0; sc->id->t_keymap.keydesc[count].name; count++) | |||
| 1233 | ; | |||
| 1234 | if (uedp->nencodings > count) | |||
| 1235 | uedp->nencodings = count; | |||
| 1236 | for (i = 0; i < uedp->nencodings; i++) { | |||
| 1237 | error = copyout(&sc->id->t_keymap.keydesc[i].name, | |||
| 1238 | &uedp->encodings[i], sizeof(kbd_t)); | |||
| 1239 | if (error) | |||
| 1240 | return (error); | |||
| 1241 | } | |||
| 1242 | return (0); | |||
| 1243 | ||||
| 1244 | case WSKBDIO_GETBACKLIGHT((unsigned long)0x40000000 | ((sizeof(struct wskbd_backlight) & 0x1fff) << 16) | ((('W')) << 8) | ((17))): | |||
| 1245 | if (wskbd_get_backlight != NULL((void *)0)) | |||
| 1246 | return (*wskbd_get_backlight)((struct wskbd_backlight *)data); | |||
| 1247 | break; | |||
| 1248 | ||||
| 1249 | case WSKBDIO_SETBACKLIGHT((unsigned long)0x80000000 | ((sizeof(struct wskbd_backlight) & 0x1fff) << 16) | ((('W')) << 8) | ((18))): | |||
| 1250 | if (wskbd_set_backlight != NULL((void *)0)) | |||
| 1251 | return (*wskbd_set_backlight)((struct wskbd_backlight *)data); | |||
| 1252 | break; | |||
| 1253 | } | |||
| 1254 | ||||
| 1255 | /* | |||
| 1256 | * Try the keyboard driver for WSKBDIO ioctls. It returns -1 | |||
| 1257 | * if it didn't recognize the request, and in turn we return | |||
| 1258 | * -1 if we didn't recognize the request. | |||
| 1259 | */ | |||
| 1260 | /* printf("kbdaccess\n"); */ | |||
| 1261 | error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data, | |||
| 1262 | flag, p); | |||
| 1263 | #ifdef WSDISPLAY_COMPAT_RAWKBD1 | |||
| 1264 | if (!error && cmd == WSKBDIO_SETMODE((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) << 16) | ((('W')) << 8) | ((19))) && *(int *)data == WSKBD_RAW1) { | |||
| 1265 | int s = spltty()splraise(0x9); | |||
| 1266 | sc->id->t_modifiers &= ~(MOD_SHIFT_L(1 << 0) | MOD_SHIFT_R(1 << 1) | |||
| 1267 | | MOD_CONTROL_L(1 << 4) | MOD_CONTROL_R(1 << 5) | |||
| 1268 | | MOD_META_L(1 << 6) | MOD_META_R(1 << 7) | |||
| 1269 | | MOD_COMMAND(1 << 12) | |||
| 1270 | | MOD_COMMAND1(1 << 13) | MOD_COMMAND2(1 << 14)); | |||
| 1271 | #if NWSDISPLAY1 > 0 | |||
| 1272 | if (sc->sc_repeating) { | |||
| 1273 | sc->sc_repeating = 0; | |||
| 1274 | timeout_del(&sc->sc_repeat_ch); | |||
| 1275 | } | |||
| 1276 | #endif | |||
| 1277 | splx(s)spllower(s); | |||
| 1278 | } | |||
| 1279 | #endif | |||
| 1280 | return (error); | |||
| 1281 | } | |||
| 1282 | ||||
| 1283 | int | |||
| 1284 | wskbdkqfilter(dev_t dev, struct knote *kn) | |||
| 1285 | { | |||
| 1286 | struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)((unsigned)((dev) & 0xff) | (((dev) & 0xffff0000) >> 8))]; | |||
| 1287 | ||||
| 1288 | if (sc->sc_base.me_evp == NULL((void *)0)) | |||
| 1289 | return (ENXIO6); | |||
| 1290 | return (wsevent_kqfilter(sc->sc_base.me_evp, kn)); | |||
| 1291 | } | |||
| 1292 | ||||
| 1293 | #if NWSDISPLAY1 > 0 | |||
| 1294 | ||||
| 1295 | int | |||
| 1296 | wskbd_pickfree(void) | |||
| 1297 | { | |||
| 1298 | int i; | |||
| 1299 | struct wskbd_softc *sc; | |||
| 1300 | ||||
| 1301 | for (i = 0; i < wskbd_cd.cd_ndevs; i++) { | |||
| 1302 | if ((sc = wskbd_cd.cd_devs[i]) == NULL((void *)0)) | |||
| 1303 | continue; | |||
| 1304 | if (sc->sc_displaydvsc_base.me_dispdv == NULL((void *)0)) | |||
| 1305 | return (i); | |||
| 1306 | } | |||
| 1307 | return (-1); | |||
| 1308 | } | |||
| 1309 | ||||
| 1310 | struct wsevsrc * | |||
| 1311 | wskbd_set_console_display(struct device *displaydv, struct wsevsrc *me) | |||
| 1312 | { | |||
| 1313 | struct wskbd_softc *sc = wskbd_console_device; | |||
| 1314 | ||||
| 1315 | if (sc == NULL((void *)0)) | |||
| 1316 | return (NULL((void *)0)); | |||
| 1317 | sc->sc_displaydvsc_base.me_dispdv = displaydv; | |||
| 1318 | #if NWSMUX1 > 0 | |||
| 1319 | (void)wsmux_attach_sc((struct wsmux_softc *)me, &sc->sc_base); | |||
| 1320 | #endif | |||
| 1321 | return (&sc->sc_base); | |||
| 1322 | } | |||
| 1323 | ||||
| 1324 | int | |||
| 1325 | wskbd_set_display(struct device *dv, struct device *displaydv) | |||
| 1326 | { | |||
| 1327 | struct wskbd_softc *sc = (struct wskbd_softc *)dv; | |||
| 1328 | struct device *odisplaydv; | |||
| 1329 | int error; | |||
| 1330 | ||||
| 1331 | DPRINTF(("%s: %s odisp=%p disp=%p cons=%d\n", __func__, | |||
| 1332 | dv->dv_xname, sc->sc_displaydv, displaydv, | |||
| 1333 | sc->sc_isconsole)); | |||
| 1334 | ||||
| 1335 | if (sc->sc_isconsole) | |||
| 1336 | return (EBUSY16); | |||
| 1337 | ||||
| 1338 | if (displaydv != NULL((void *)0)) { | |||
| 1339 | if (sc->sc_displaydvsc_base.me_dispdv != NULL((void *)0)) | |||
| 1340 | return (EBUSY16); | |||
| 1341 | } else { | |||
| 1342 | if (sc->sc_displaydvsc_base.me_dispdv == NULL((void *)0)) | |||
| 1343 | return (ENXIO6); | |||
| 1344 | } | |||
| 1345 | ||||
| 1346 | odisplaydv = sc->sc_displaydvsc_base.me_dispdv; | |||
| 1347 | sc->sc_displaydvsc_base.me_dispdv = NULL((void *)0); | |||
| 1348 | error = wskbd_enable(sc, displaydv != NULL((void *)0)); | |||
| 1349 | sc->sc_displaydvsc_base.me_dispdv = displaydv; | |||
| 1350 | if (error) { | |||
| 1351 | sc->sc_displaydvsc_base.me_dispdv = odisplaydv; | |||
| 1352 | return (error); | |||
| 1353 | } | |||
| 1354 | ||||
| 1355 | if (displaydv) | |||
| 1356 | printf("%s: connecting to %s\n", | |||
| 1357 | sc->sc_base.me_dv.dv_xname, displaydv->dv_xname); | |||
| 1358 | else | |||
| 1359 | printf("%s: disconnecting from %s\n", | |||
| 1360 | sc->sc_base.me_dv.dv_xname, odisplaydv->dv_xname); | |||
| 1361 | ||||
| 1362 | return (0); | |||
| 1363 | } | |||
| 1364 | ||||
| 1365 | #endif /* NWSDISPLAY > 0 */ | |||
| 1366 | ||||
| 1367 | #if NWSMUX1 > 0 | |||
| 1368 | int | |||
| 1369 | wskbd_add_mux(int unit, struct wsmux_softc *muxsc) | |||
| 1370 | { | |||
| 1371 | struct wskbd_softc *sc; | |||
| 1372 | ||||
| 1373 | if (unit < 0 || unit >= wskbd_cd.cd_ndevs || | |||
| 1374 | (sc = wskbd_cd.cd_devs[unit]) == NULL((void *)0)) | |||
| 1375 | return (ENXIO6); | |||
| 1376 | ||||
| 1377 | if (sc->sc_base.me_parent != NULL((void *)0) || sc->sc_base.me_evp != NULL((void *)0)) | |||
| 1378 | return (EBUSY16); | |||
| 1379 | ||||
| 1380 | return (wsmux_attach_sc(muxsc, &sc->sc_base)); | |||
| 1381 | } | |||
| 1382 | #endif | |||
| 1383 | ||||
| 1384 | /* | |||
| 1385 | * Console interface. | |||
| 1386 | */ | |||
| 1387 | int | |||
| 1388 | wskbd_cngetc(dev_t dev) | |||
| 1389 | { | |||
| 1390 | static int num = 0; | |||
| 1391 | static int pos; | |||
| 1392 | u_int type; | |||
| 1393 | int data; | |||
| 1394 | keysym_t ks; | |||
| 1395 | ||||
| 1396 | if (!wskbd_console_initted) | |||
| 1397 | return 0; | |||
| 1398 | ||||
| 1399 | if (wskbd_console_device != NULL((void *)0) && | |||
| 1400 | !wskbd_console_device->sc_translating) | |||
| 1401 | return 0; | |||
| 1402 | ||||
| 1403 | for(;;) { | |||
| 1404 | if (num-- > 0) { | |||
| 1405 | ks = wskbd_console_data.t_symbols[pos++]; | |||
| 1406 | if (KS_GROUP(ks)((ks) >= 0x0300 && (ks) < 0x0370 ? 0xf801 : ((( ks) & 0xf000) == 0xe000 ? 0xf803 : (((ks) & 0xf800) == 0xf000 ? ((ks) & 0xff00) : 0xf802))) == KS_GROUP_Ascii0xf802) | |||
| 1407 | return (KS_VALUE(ks)(((ks) & 0xf000) == 0xe000 ? ((ks) & 0x0fff) : (((ks) & 0xf800) == 0xf000 ? ((ks) & 0x00ff) : (ks)))); | |||
| 1408 | } else { | |||
| 1409 | (*wskbd_console_data.t_consops->getc) | |||
| 1410 | (wskbd_console_data.t_consaccesscookie, | |||
| 1411 | &type, &data); | |||
| 1412 | num = wskbd_translate(&wskbd_console_data, type, data); | |||
| 1413 | pos = 0; | |||
| 1414 | } | |||
| 1415 | } | |||
| 1416 | } | |||
| 1417 | ||||
| 1418 | void | |||
| 1419 | wskbd_cnpollc(dev_t dev, int poll) | |||
| 1420 | { | |||
| 1421 | if (!wskbd_console_initted) | |||
| 1422 | return; | |||
| 1423 | ||||
| 1424 | if (wskbd_console_device != NULL((void *)0) && | |||
| 1425 | !wskbd_console_device->sc_translating) | |||
| 1426 | return; | |||
| 1427 | ||||
| 1428 | (*wskbd_console_data.t_consops->pollc) | |||
| 1429 | (wskbd_console_data.t_consaccesscookie, poll); | |||
| 1430 | } | |||
| 1431 | ||||
| 1432 | void | |||
| 1433 | wskbd_cnbell(dev_t dev, u_int pitch, u_int period, u_int volume) | |||
| 1434 | { | |||
| 1435 | if (!wskbd_console_initted) | |||
| 1436 | return; | |||
| 1437 | ||||
| 1438 | if (wskbd_console_data.t_consops->bell != NULL((void *)0)) | |||
| 1439 | (*wskbd_console_data.t_consops->bell) | |||
| 1440 | (wskbd_console_data.t_consaccesscookie, pitch, period, | |||
| 1441 | volume); | |||
| 1442 | } | |||
| 1443 | ||||
| 1444 | void | |||
| 1445 | update_leds(struct wskbd_internal *id) | |||
| 1446 | { | |||
| 1447 | int new_state; | |||
| 1448 | ||||
| 1449 | new_state = 0; | |||
| 1450 | if (id->t_modifiers & (MOD_SHIFTLOCK(1 << 2) | MOD_CAPSLOCK(1 << 3))) | |||
| 1451 | new_state |= WSKBD_LED_CAPS0x01; | |||
| 1452 | if (id->t_modifiers & MOD_NUMLOCK(1 << 9)) | |||
| 1453 | new_state |= WSKBD_LED_NUM0x02; | |||
| 1454 | if (id->t_modifiers & MOD_COMPOSE(1 << 10)) | |||
| 1455 | new_state |= WSKBD_LED_COMPOSE0x08; | |||
| 1456 | if (id->t_modifiers & MOD_HOLDSCREEN(1 << 11)) | |||
| 1457 | new_state |= WSKBD_LED_SCROLL0x04; | |||
| 1458 | ||||
| 1459 | if (id->t_sc && new_state != id->t_sc->sc_ledstate) { | |||
| 1460 | (*id->t_sc->sc_accessops->set_leds) | |||
| 1461 | (id->t_sc->sc_accesscookie, new_state); | |||
| 1462 | id->t_sc->sc_ledstate = new_state; | |||
| 1463 | } | |||
| 1464 | } | |||
| 1465 | ||||
| 1466 | void | |||
| 1467 | update_modifier(struct wskbd_internal *id, u_int type, int toggle, int mask) | |||
| 1468 | { | |||
| 1469 | if (toggle) { | |||
| 1470 | if (type == WSCONS_EVENT_KEY_DOWN2) | |||
| 1471 | id->t_modifiers ^= mask; | |||
| 1472 | } else { | |||
| 1473 | if (type == WSCONS_EVENT_KEY_DOWN2) | |||
| 1474 | id->t_modifiers |= mask; | |||
| 1475 | else | |||
| 1476 | id->t_modifiers &= ~mask; | |||
| 1477 | } | |||
| 1478 | if (mask & MOD_ANYLED((1 << 2) | (1 << 3) | (1 << 9) | (1 << 10) | (1 << 11))) | |||
| 1479 | update_leds(id); | |||
| 1480 | } | |||
| 1481 | ||||
| 1482 | #if NWSDISPLAY1 > 0 | |||
| 1483 | void | |||
| 1484 | change_displayparam(struct wskbd_softc *sc, int param, int updown, | |||
| 1485 | int wraparound) | |||
| 1486 | { | |||
| 1487 | int res; | |||
| 1488 | struct wsdisplay_param dp; | |||
| 1489 | ||||
| 1490 | dp.param = param; | |||
| 1491 | res = wsdisplay_param(sc->sc_displaydvsc_base.me_dispdv, WSDISPLAYIO_GETPARAM(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct wsdisplay_param) & 0x1fff) << 16) | ((('W') ) << 8) | ((89))), &dp); | |||
| 1492 | ||||
| 1493 | if (res == EINVAL22) | |||
| 1494 | return; /* no such parameter */ | |||
| 1495 | ||||
| 1496 | dp.curval += updown; | |||
| 1497 | if (dp.max < dp.curval) | |||
| 1498 | dp.curval = wraparound ? dp.min : dp.max; | |||
| 1499 | else | |||
| 1500 | if (dp.curval < dp.min) | |||
| 1501 | dp.curval = wraparound ? dp.max : dp.min; | |||
| 1502 | wsdisplay_param(sc->sc_displaydvsc_base.me_dispdv, WSDISPLAYIO_SETPARAM(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct wsdisplay_param) & 0x1fff) << 16) | ((('W') ) << 8) | ((90))), &dp); | |||
| 1503 | } | |||
| 1504 | #endif | |||
| 1505 | ||||
| 1506 | int | |||
| 1507 | internal_command(struct wskbd_softc *sc, u_int *type, keysym_t ksym, | |||
| 1508 | keysym_t ksym2) | |||
| 1509 | { | |||
| 1510 | switch (ksym) { | |||
| 1511 | case KS_Cmd0xf10d: | |||
| 1512 | update_modifier(sc->id, *type, 0, MOD_COMMAND(1 << 12)); | |||
| 1513 | ksym = ksym2; | |||
| 1514 | break; | |||
| 1515 | ||||
| 1516 | case KS_Cmd10xf10e: | |||
| 1517 | update_modifier(sc->id, *type, 0, MOD_COMMAND1(1 << 13)); | |||
| 1518 | break; | |||
| 1519 | ||||
| 1520 | case KS_Cmd20xf10f: | |||
| 1521 | update_modifier(sc->id, *type, 0, MOD_COMMAND2(1 << 14)); | |||
| 1522 | break; | |||
| 1523 | } | |||
| 1524 | ||||
| 1525 | if (*type != WSCONS_EVENT_KEY_DOWN2) | |||
| 1526 | return (0); | |||
| 1527 | ||||
| 1528 | #ifdef SUSPEND1 | |||
| 1529 | if (ksym == KS_Cmd_Sleep0xf42f) { | |||
| 1530 | request_sleep(SLEEP_SUSPEND0x01); | |||
| 1531 | return (1); | |||
| 1532 | } | |||
| 1533 | #endif | |||
| 1534 | ||||
| 1535 | #ifdef HAVE_SCROLLBACK_SUPPORT | |||
| 1536 | #if NWSDISPLAY1 > 0 | |||
| 1537 | switch (ksym) { | |||
| 1538 | case KS_Cmd_ScrollBack0xf42c: | |||
| 1539 | if (MOD_ONESET(sc->id, MOD_ANYSHIFT)(((sc->id)->t_modifiers & (((1 << 0) | (1 << 1) | (1 << 2)))) != 0)) { | |||
| 1540 | if (sc->sc_displaydvsc_base.me_dispdv != NULL((void *)0)) | |||
| 1541 | wsscrollback(sc->sc_displaydvsc_base.me_dispdv, | |||
| 1542 | WSDISPLAY_SCROLL_BACKWARD0); | |||
| 1543 | return (1); | |||
| 1544 | } | |||
| 1545 | break; | |||
| 1546 | ||||
| 1547 | case KS_Cmd_ScrollFwd0xf42d: | |||
| 1548 | if (MOD_ONESET(sc->id, MOD_ANYSHIFT)(((sc->id)->t_modifiers & (((1 << 0) | (1 << 1) | (1 << 2)))) != 0)) { | |||
| 1549 | if (sc->sc_displaydvsc_base.me_dispdv != NULL((void *)0)) | |||
| 1550 | wsscrollback(sc->sc_displaydvsc_base.me_dispdv, | |||
| 1551 | WSDISPLAY_SCROLL_FORWARD1); | |||
| 1552 | return (1); | |||
| 1553 | } | |||
| 1554 | break; | |||
| 1555 | } | |||
| 1556 | #endif | |||
| 1557 | #endif | |||
| 1558 | ||||
| 1559 | switch (ksym) { | |||
| 1560 | case KS_Cmd_KbdBacklightUp0xf431: | |||
| 1561 | atomic_store_int(&sc->sc_kbd_backlight_cmd, KBD_BACKLIGHT_UP); | |||
| 1562 | task_add(systq, &sc->sc_kbd_backlight_task); | |||
| 1563 | return (1); | |||
| 1564 | case KS_Cmd_KbdBacklightDown0xf432: | |||
| 1565 | atomic_store_int(&sc->sc_kbd_backlight_cmd, KBD_BACKLIGHT_DOWN); | |||
| 1566 | task_add(systq, &sc->sc_kbd_backlight_task); | |||
| 1567 | return (1); | |||
| 1568 | case KS_Cmd_KbdBacklightToggle0xf430: | |||
| 1569 | atomic_store_int(&sc->sc_kbd_backlight_cmd, KBD_BACKLIGHT_TOGGLE); | |||
| 1570 | task_add(systq, &sc->sc_kbd_backlight_task); | |||
| 1571 | return (1); | |||
| 1572 | } | |||
| 1573 | ||||
| 1574 | #if NWSDISPLAY1 > 0 | |||
| 1575 | switch(ksym) { | |||
| 1576 | case KS_Cmd_BrightnessUp0xf426: | |||
| 1577 | atomic_add_int(&sc->sc_brightness_steps, 1)_atomic_add_int(&sc->sc_brightness_steps, 1); | |||
| 1578 | task_add(systq, &sc->sc_brightness_task); | |||
| 1579 | return (1); | |||
| 1580 | case KS_Cmd_BrightnessDown0xf427: | |||
| 1581 | atomic_sub_int(&sc->sc_brightness_steps, 1)_atomic_sub_int(&sc->sc_brightness_steps, 1); | |||
| 1582 | task_add(systq, &sc->sc_brightness_task); | |||
| 1583 | return (1); | |||
| 1584 | case KS_Cmd_BrightnessRotate0xf428: | |||
| 1585 | wsdisplay_brightness_cycle(sc->sc_displaydvsc_base.me_dispdv); | |||
| 1586 | return (1); | |||
| 1587 | } | |||
| 1588 | #endif | |||
| 1589 | ||||
| 1590 | if (!MOD_ONESET(sc->id, MOD_COMMAND)(((sc->id)->t_modifiers & ((1 << 12))) != 0) && | |||
| 1591 | !MOD_ALLSET(sc->id, MOD_COMMAND1 | MOD_COMMAND2)(((sc->id)->t_modifiers & ((1 << 13) | (1 << 14))) == ((1 << 13) | (1 << 14)))) | |||
| 1592 | return (0); | |||
| 1593 | ||||
| 1594 | #ifdef DDB1 | |||
| 1595 | if (ksym == KS_Cmd_Debugger0xf420) { | |||
| 1596 | wskbd_debugger(sc); | |||
| 1597 | /* discard this key (ddb discarded command modifiers) */ | |||
| 1598 | *type = WSCONS_EVENT_KEY_UP1; | |||
| 1599 | return (1); | |||
| 1600 | } | |||
| 1601 | #endif | |||
| 1602 | ||||
| 1603 | #if NWSDISPLAY1 > 0 | |||
| 1604 | if (sc->sc_displaydvsc_base.me_dispdv == NULL((void *)0)) | |||
| 1605 | return (0); | |||
| 1606 | ||||
| 1607 | switch (ksym) { | |||
| 1608 | case KS_Cmd_Screen00xf400: | |||
| 1609 | case KS_Cmd_Screen10xf401: | |||
| 1610 | case KS_Cmd_Screen20xf402: | |||
| 1611 | case KS_Cmd_Screen30xf403: | |||
| 1612 | case KS_Cmd_Screen40xf404: | |||
| 1613 | case KS_Cmd_Screen50xf405: | |||
| 1614 | case KS_Cmd_Screen60xf406: | |||
| 1615 | case KS_Cmd_Screen70xf407: | |||
| 1616 | case KS_Cmd_Screen80xf408: | |||
| 1617 | case KS_Cmd_Screen90xf409: | |||
| 1618 | case KS_Cmd_Screen100xf40a: | |||
| 1619 | case KS_Cmd_Screen110xf40b: | |||
| 1620 | wsdisplay_switch(sc->sc_displaydvsc_base.me_dispdv, ksym - KS_Cmd_Screen00xf400, 0); | |||
| 1621 | return (1); | |||
| 1622 | case KS_Cmd_ResetEmul0xf421: | |||
| 1623 | wsdisplay_reset(sc->sc_displaydvsc_base.me_dispdv, WSDISPLAY_RESETEMUL); | |||
| 1624 | return (1); | |||
| 1625 | case KS_Cmd_ResetClose0xf422: | |||
| 1626 | wsdisplay_reset(sc->sc_displaydvsc_base.me_dispdv, WSDISPLAY_RESETCLOSE); | |||
| 1627 | return (1); | |||
| 1628 | #if defined(__i386__) || defined(__amd64__1) | |||
| 1629 | case KS_Cmd_KbdReset0xf42e: | |||
| 1630 | switch (kbd_reset) { | |||
| 1631 | #ifdef DDB1 | |||
| 1632 | case 2: | |||
| 1633 | wskbd_debugger(sc); | |||
| 1634 | /* discard this key (ddb discarded command modifiers) */ | |||
| 1635 | *type = WSCONS_EVENT_KEY_UP1; | |||
| 1636 | break; | |||
| 1637 | #endif | |||
| 1638 | case 1: | |||
| 1639 | kbd_reset = 0; | |||
| 1640 | prsignal(initprocess, SIGUSR1)ptsignal((initprocess)->ps_mainproc, (30), SPROCESS); | |||
| 1641 | break; | |||
| 1642 | default: | |||
| 1643 | break; | |||
| 1644 | } | |||
| 1645 | return (1); | |||
| 1646 | #endif | |||
| 1647 | case KS_Cmd_BacklightOn0xf423: | |||
| 1648 | case KS_Cmd_BacklightOff0xf424: | |||
| 1649 | case KS_Cmd_BacklightToggle0xf425: | |||
| 1650 | change_displayparam(sc, WSDISPLAYIO_PARAM_BACKLIGHT1, | |||
| 1651 | ksym == KS_Cmd_BacklightOff0xf424 ? -1 : 1, | |||
| 1652 | ksym == KS_Cmd_BacklightToggle0xf425 ? 1 : 0); | |||
| 1653 | return (1); | |||
| 1654 | case KS_Cmd_ContrastUp0xf429: | |||
| 1655 | case KS_Cmd_ContrastDown0xf42a: | |||
| 1656 | case KS_Cmd_ContrastRotate0xf42b: | |||
| 1657 | change_displayparam(sc, WSDISPLAYIO_PARAM_CONTRAST3, | |||
| 1658 | ksym == KS_Cmd_ContrastDown0xf42a ? -1 : 1, | |||
| 1659 | ksym == KS_Cmd_ContrastRotate0xf42b ? 1 : 0); | |||
| 1660 | return (1); | |||
| 1661 | } | |||
| 1662 | #endif | |||
| 1663 | return (0); | |||
| 1664 | } | |||
| 1665 | ||||
| 1666 | int | |||
| 1667 | wskbd_translate(struct wskbd_internal *id, u_int type, int value) | |||
| 1668 | { | |||
| 1669 | struct wskbd_softc *sc = id->t_sc; | |||
| ||||
| 1670 | keysym_t ksym, res, *group; | |||
| 1671 | struct wscons_keymap kpbuf, *kp; | |||
| 1672 | int gindex, iscommand = 0; | |||
| 1673 | ||||
| 1674 | if (type == WSCONS_EVENT_ALL_KEYS_UP3) { | |||
| 1675 | #if NWSDISPLAY1 > 0 | |||
| 1676 | if (sc != NULL((void *)0) && sc->sc_repeating) { | |||
| 1677 | sc->sc_repeating = 0; | |||
| 1678 | timeout_del(&sc->sc_repeat_ch); | |||
| 1679 | } | |||
| 1680 | #endif | |||
| 1681 | id->t_modifiers &= ~(MOD_SHIFT_L(1 << 0) | MOD_SHIFT_R(1 << 1) | | |||
| 1682 | MOD_CONTROL_L(1 << 4) | MOD_CONTROL_R(1 << 5) | | |||
| 1683 | MOD_META_L(1 << 6) | MOD_META_R(1 << 7) | | |||
| 1684 | MOD_MODESHIFT(1 << 8) | MOD_MODELOCK(1 << 15) | | |||
| 1685 | MOD_COMMAND(1 << 12) | MOD_COMMAND1(1 << 13) | MOD_COMMAND2(1 << 14)); | |||
| 1686 | return (0); | |||
| 1687 | } | |||
| 1688 | ||||
| 1689 | if (sc != NULL((void *)0)) { | |||
| 1690 | if (value < 0 || value >= sc->sc_maplen) { | |||
| 1691 | #ifdef DEBUG | |||
| 1692 | printf("wskbd_translate: keycode %d out of range\n", | |||
| 1693 | value); | |||
| 1694 | #endif | |||
| 1695 | return (0); | |||
| 1696 | } | |||
| 1697 | kp = sc->sc_map + value; | |||
| 1698 | } else { | |||
| 1699 | kp = &kpbuf; | |||
| 1700 | wskbd_get_mapentry(&id->t_keymap, value, kp); | |||
| 1701 | } | |||
| 1702 | ||||
| 1703 | /* if this key has a command, process it first */ | |||
| 1704 | if (sc
| |||
| 1705 | iscommand = internal_command(sc, &type, kp->command, | |||
| 1706 | kp->group1[0]); | |||
| 1707 | ||||
| 1708 | /* Now update modifiers */ | |||
| 1709 | switch (kp->group1[0]) { | |||
| 1710 | case KS_Shift_L0xf101: | |||
| 1711 | update_modifier(id, type, 0, MOD_SHIFT_L(1 << 0)); | |||
| 1712 | break; | |||
| 1713 | ||||
| 1714 | case KS_Shift_R0xf102: | |||
| 1715 | update_modifier(id, type, 0, MOD_SHIFT_R(1 << 1)); | |||
| 1716 | break; | |||
| 1717 | ||||
| 1718 | case KS_Shift_Lock0xf106: | |||
| 1719 | update_modifier(id, type, 1, MOD_SHIFTLOCK(1 << 2)); | |||
| 1720 | break; | |||
| 1721 | ||||
| 1722 | case KS_Caps_Lock0xf105: | |||
| 1723 | update_modifier(id, type, 1, MOD_CAPSLOCK(1 << 3)); | |||
| 1724 | break; | |||
| 1725 | ||||
| 1726 | case KS_Control_L0xf103: | |||
| 1727 | update_modifier(id, type, 0, MOD_CONTROL_L(1 << 4)); | |||
| 1728 | break; | |||
| 1729 | ||||
| 1730 | case KS_Control_R0xf104: | |||
| 1731 | update_modifier(id, type, 0, MOD_CONTROL_R(1 << 5)); | |||
| 1732 | break; | |||
| 1733 | ||||
| 1734 | case KS_Alt_L0xf107: | |||
| 1735 | update_modifier(id, type, 0, MOD_META_L(1 << 6)); | |||
| 1736 | break; | |||
| 1737 | ||||
| 1738 | case KS_Alt_R0xf108: | |||
| 1739 | update_modifier(id, type, 0, MOD_META_R(1 << 7)); | |||
| 1740 | break; | |||
| 1741 | ||||
| 1742 | case KS_Mode_switch0xf10a: | |||
| 1743 | update_modifier(id, type, 0, MOD_MODESHIFT(1 << 8)); | |||
| 1744 | break; | |||
| 1745 | ||||
| 1746 | case KS_Mode_Lock0xf117: | |||
| 1747 | update_modifier(id, type, 1, MOD_MODELOCK(1 << 15)); | |||
| 1748 | break; | |||
| 1749 | ||||
| 1750 | case KS_Num_Lock0xf10b: | |||
| 1751 | update_modifier(id, type, 1, MOD_NUMLOCK(1 << 9)); | |||
| 1752 | break; | |||
| 1753 | ||||
| 1754 | #if NWSDISPLAY1 > 0 | |||
| 1755 | case KS_Hold_Screen0xf10c: | |||
| 1756 | if (sc != NULL((void *)0)) { | |||
| 1757 | update_modifier(id, type, 1, MOD_HOLDSCREEN(1 << 11)); | |||
| 1758 | if (sc->sc_displaydvsc_base.me_dispdv != NULL((void *)0)) | |||
| 1759 | wsdisplay_kbdholdscreen(sc->sc_displaydvsc_base.me_dispdv, | |||
| 1760 | id->t_modifiers & MOD_HOLDSCREEN(1 << 11)); | |||
| 1761 | } | |||
| 1762 | break; | |||
| 1763 | ||||
| 1764 | default: | |||
| 1765 | if (sc
| |||
| 1766 | ((type == WSCONS_EVENT_KEY_UP1 && value != sc->sc_repkey) || | |||
| 1767 | (type == WSCONS_EVENT_KEY_DOWN2 && value == sc->sc_repkey))) | |||
| 1768 | return (0); | |||
| 1769 | break; | |||
| 1770 | #endif | |||
| 1771 | } | |||
| 1772 | ||||
| 1773 | #if NWSDISPLAY1 > 0 | |||
| 1774 | if (sc
| |||
| 1775 | if (sc->sc_repeating) { | |||
| 1776 | sc->sc_repeating = 0; | |||
| 1777 | timeout_del(&sc->sc_repeat_ch); | |||
| 1778 | } | |||
| 1779 | sc->sc_repkey = value; | |||
| 1780 | } | |||
| 1781 | #endif | |||
| 1782 | ||||
| 1783 | /* If this is a key release or we are in command mode, we are done */ | |||
| 1784 | if (type != WSCONS_EVENT_KEY_DOWN2 || iscommand
| |||
| 1785 | return (0); | |||
| 1786 | ||||
| 1787 | /* Get the keysym */ | |||
| 1788 | if (id->t_modifiers & (MOD_MODESHIFT(1 << 8)|MOD_MODELOCK(1 << 15)) && | |||
| 1789 | !MOD_ONESET(id, MOD_ANYCONTROL)(((id)->t_modifiers & (((1 << 4) | (1 << 5 )))) != 0)) | |||
| 1790 | group = & kp->group2[0]; | |||
| 1791 | else | |||
| 1792 | group = & kp->group1[0]; | |||
| 1793 | ||||
| 1794 | if ((id->t_modifiers & MOD_NUMLOCK(1 << 9)) && | |||
| 1795 | KS_GROUP(group[1])((group[1]) >= 0x0300 && (group[1]) < 0x0370 ? 0xf801 : (((group[1]) & 0xf000) == 0xe000 ? 0xf803 : (((group[1 ]) & 0xf800) == 0xf000 ? ((group[1]) & 0xff00) : 0xf802 ))) == KS_GROUP_Keypad0xf200) { | |||
| 1796 | gindex = !MOD_ONESET(id, MOD_ANYSHIFT)(((id)->t_modifiers & (((1 << 0) | (1 << 1 ) | (1 << 2)))) != 0); | |||
| 1797 | ksym = group[gindex]; | |||
| 1798 | } else { | |||
| 1799 | /* CAPS alone should only affect letter keys */ | |||
| 1800 | if ((id->t_modifiers & (MOD_CAPSLOCK(1 << 3) | MOD_ANYSHIFT((1 << 0) | (1 << 1) | (1 << 2)))) == | |||
| 1801 | MOD_CAPSLOCK(1 << 3)) { | |||
| 1802 | gindex = 0; | |||
| 1803 | ksym = ksym_upcase(group[0]); | |||
| 1804 | } else { | |||
| 1805 | gindex = MOD_ONESET(id, MOD_ANYSHIFT)(((id)->t_modifiers & (((1 << 0) | (1 << 1 ) | (1 << 2)))) != 0); | |||
| 1806 | ksym = group[gindex]; | |||
| 1807 | } | |||
| 1808 | } | |||
| 1809 | ||||
| 1810 | /* Submit Audio keys for hotkey processing */ | |||
| 1811 | if (KS_GROUP(ksym)((ksym) >= 0x0300 && (ksym) < 0x0370 ? 0xf801 : (((ksym) & 0xf000) == 0xe000 ? 0xf803 : (((ksym) & 0xf800 ) == 0xf000 ? ((ksym) & 0xff00) : 0xf802))) == KS_GROUP_Function0xf300) { | |||
| 1812 | switch (ksym) { | |||
| 1813 | #if NAUDIO1 > 0 | |||
| 1814 | case KS_AudioMute0xf3d1: | |||
| 1815 | wskbd_set_mixervolume_dev(sc->sc_audiocookie, 0, 1); | |||
| 1816 | return (0); | |||
| 1817 | case KS_AudioLower0xf3d2: | |||
| 1818 | wskbd_set_mixervolume_dev(sc->sc_audiocookie, -1, 1); | |||
| 1819 | return (0); | |||
| 1820 | case KS_AudioRaise0xf3d3: | |||
| 1821 | wskbd_set_mixervolume_dev(sc->sc_audiocookie, 1, 1); | |||
| ||||
| 1822 | return (0); | |||
| 1823 | #endif | |||
| 1824 | default: | |||
| 1825 | break; | |||
| 1826 | } | |||
| 1827 | } | |||
| 1828 | ||||
| 1829 | /* Process compose sequence and dead accents */ | |||
| 1830 | res = KS_voidSymbol0xf500; | |||
| 1831 | ||||
| 1832 | switch (KS_GROUP(ksym)((ksym) >= 0x0300 && (ksym) < 0x0370 ? 0xf801 : (((ksym) & 0xf000) == 0xe000 ? 0xf803 : (((ksym) & 0xf800 ) == 0xf000 ? ((ksym) & 0xff00) : 0xf802)))) { | |||
| 1833 | case KS_GROUP_Ascii0xf802: | |||
| 1834 | case KS_GROUP_Keypad0xf200: | |||
| 1835 | case KS_GROUP_Function0xf300: | |||
| 1836 | res = ksym; | |||
| 1837 | break; | |||
| 1838 | ||||
| 1839 | case KS_GROUP_Mod0xf100: | |||
| 1840 | if (ksym == KS_Multi_key0xf109) { | |||
| 1841 | update_modifier(id, 1, 0, MOD_COMPOSE(1 << 10)); | |||
| 1842 | id->t_composelen = 2; | |||
| 1843 | } | |||
| 1844 | break; | |||
| 1845 | ||||
| 1846 | case KS_GROUP_Dead0xf801: | |||
| 1847 | if (id->t_composelen == 0) { | |||
| 1848 | update_modifier(id, 1, 0, MOD_COMPOSE(1 << 10)); | |||
| 1849 | id->t_composelen = 1; | |||
| 1850 | id->t_composebuf[0] = ksym; | |||
| 1851 | } else | |||
| 1852 | res = ksym; | |||
| 1853 | break; | |||
| 1854 | } | |||
| 1855 | ||||
| 1856 | if (res == KS_voidSymbol0xf500) | |||
| 1857 | return (0); | |||
| 1858 | ||||
| 1859 | if (id->t_composelen > 0) { | |||
| 1860 | /* | |||
| 1861 | * If the compose key also serves as AltGr (i.e. set to both | |||
| 1862 | * KS_Multi_key and KS_Mode_switch), and would provide a valid, | |||
| 1863 | * distinct combination as AltGr, leave compose mode. | |||
| 1864 | */ | |||
| 1865 | if (id->t_composelen == 2 && group == &kp->group2[0]) { | |||
| 1866 | if (kp->group1[gindex] != kp->group2[gindex]) | |||
| 1867 | id->t_composelen = 0; | |||
| 1868 | } | |||
| 1869 | ||||
| 1870 | if (id->t_composelen != 0) { | |||
| 1871 | id->t_composebuf[2 - id->t_composelen] = res; | |||
| 1872 | if (--id->t_composelen == 0) { | |||
| 1873 | res = wskbd_compose_value(id->t_composebuf); | |||
| 1874 | update_modifier(id, 0, 0, MOD_COMPOSE(1 << 10)); | |||
| 1875 | } else { | |||
| 1876 | return (0); | |||
| 1877 | } | |||
| 1878 | } | |||
| 1879 | } | |||
| 1880 | ||||
| 1881 | /* We are done, return the symbol */ | |||
| 1882 | if (KS_GROUP(res)((res) >= 0x0300 && (res) < 0x0370 ? 0xf801 : ( ((res) & 0xf000) == 0xe000 ? 0xf803 : (((res) & 0xf800 ) == 0xf000 ? ((res) & 0xff00) : 0xf802))) == KS_GROUP_Ascii0xf802) { | |||
| 1883 | if (MOD_ONESET(id, MOD_ANYCONTROL)(((id)->t_modifiers & (((1 << 4) | (1 << 5 )))) != 0)) { | |||
| 1884 | if ((res >= KS_at0x40 && res <= KS_z0x7a) || res == KS_space0x20) | |||
| 1885 | res = res & 0x1f; | |||
| 1886 | else if (res == KS_20x32) | |||
| 1887 | res = 0x00; | |||
| 1888 | else if (res >= KS_30x33 && res <= KS_70x37) | |||
| 1889 | res = KS_Escape0x1b + (res - KS_30x33); | |||
| 1890 | else if (res == KS_80x38) | |||
| 1891 | res = KS_Delete0x7f; | |||
| 1892 | } | |||
| 1893 | if (MOD_ONESET(id, MOD_ANYMETA)(((id)->t_modifiers & (((1 << 6) | (1 << 7 )))) != 0)) { | |||
| 1894 | if (id->t_flags & WSKFL_METAESC1) { | |||
| 1895 | id->t_symbols[0] = KS_Escape0x1b; | |||
| 1896 | id->t_symbols[1] = res; | |||
| 1897 | return (2); | |||
| 1898 | } else | |||
| 1899 | res |= 0x80; | |||
| 1900 | } | |||
| 1901 | } | |||
| 1902 | ||||
| 1903 | id->t_symbols[0] = res; | |||
| 1904 | return (1); | |||
| 1905 | } | |||
| 1906 | ||||
| 1907 | void | |||
| 1908 | wskbd_debugger(struct wskbd_softc *sc) | |||
| 1909 | { | |||
| 1910 | #ifdef DDB1 | |||
| 1911 | if (sc->sc_isconsole && db_console) { | |||
| 1912 | if (sc->id->t_consops->debugger != NULL((void *)0)) { | |||
| 1913 | (*sc->id->t_consops->debugger) | |||
| 1914 | (sc->id->t_consaccesscookie); | |||
| 1915 | } else | |||
| 1916 | db_enter(); | |||
| 1917 | } | |||
| 1918 | #endif | |||
| 1919 | } | |||
| 1920 | ||||
| 1921 | void | |||
| 1922 | wskbd_set_keymap(struct wskbd_softc *sc, struct wscons_keymap *map, int maplen) | |||
| 1923 | { | |||
| 1924 | free(sc->sc_map, M_DEVBUF2, sc->sc_maplen * sizeof(*sc->sc_map)); | |||
| 1925 | sc->sc_map = map; | |||
| 1926 | sc->sc_maplen = maplen; | |||
| 1927 | } | |||
| 1928 | ||||
| 1929 | void | |||
| 1930 | wskbd_kbd_backlight_task(void *arg) | |||
| 1931 | { | |||
| 1932 | struct wskbd_softc *sc = arg; | |||
| 1933 | struct wskbd_backlight data; | |||
| 1934 | int step, val; | |||
| 1935 | u_int cmd; | |||
| 1936 | ||||
| 1937 | if (wskbd_get_backlight == NULL((void *)0) || wskbd_set_backlight == NULL((void *)0)) | |||
| 1938 | return; | |||
| 1939 | ||||
| 1940 | cmd = atomic_swap_uint(&sc->sc_kbd_backlight_cmd, 0)_atomic_swap_uint((&sc->sc_kbd_backlight_cmd), (0)); | |||
| 1941 | if (cmd != KBD_BACKLIGHT_UP && | |||
| 1942 | cmd != KBD_BACKLIGHT_DOWN && | |||
| 1943 | cmd != KBD_BACKLIGHT_TOGGLE) | |||
| 1944 | return; | |||
| 1945 | ||||
| 1946 | (*wskbd_get_backlight)(&data); | |||
| 1947 | step = (data.max - data.min + 1) / 8; | |||
| 1948 | val = (cmd == KBD_BACKLIGHT_UP) ? data.curval + step : | |||
| 1949 | (cmd == KBD_BACKLIGHT_DOWN) ? data.curval - step : | |||
| 1950 | (data.curval) ? 0 : (data.max - data.min + 1) / 2; | |||
| 1951 | data.curval = (val > 0xff) ? 0xff : (val < 0) ? 0 : val; | |||
| 1952 | (*wskbd_set_backlight)(&data); | |||
| 1953 | } | |||
| 1954 | ||||
| 1955 | #if NWSDISPLAY1 > 0 | |||
| 1956 | void | |||
| 1957 | wskbd_brightness_task(void *arg) | |||
| 1958 | { | |||
| 1959 | struct wskbd_softc *sc = arg; | |||
| 1960 | int steps = atomic_swap_uint(&sc->sc_brightness_steps, 0)_atomic_swap_uint((&sc->sc_brightness_steps), (0)); | |||
| 1961 | int dir = 1; | |||
| 1962 | ||||
| 1963 | if (steps < 0) { | |||
| 1964 | steps = -steps; | |||
| 1965 | dir = -1; | |||
| 1966 | } | |||
| 1967 | while (steps--) | |||
| 1968 | wsdisplay_brightness_step(NULL((void *)0), dir); | |||
| 1969 | } | |||
| 1970 | #endif |