File: | dev/wscons/wskbd.c |
Warning: | line 1818, 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 |