1/* $NetBSD: keyboard.c,v 1.12 2021/09/22 14:15:29 mlelstv Exp $ */ 2 3/*- 4 * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/ioctl.h> 33#include <sys/time.h> 34 35#include <dev/wscons/wsksymdef.h> 36#include <dev/wscons/wsconsio.h> 37 38#include <err.h> 39#include <errno.h> 40#include <stdlib.h> 41#include <string.h> 42 43#include "wsconsctl.h" 44 45static int kbtype; 46static int keyclick; 47static struct wskbd_bell_data bell; 48static struct wskbd_bell_data dfbell; 49static struct wscons_keymap mapdata[KS_NUMKEYCODES]; 50struct wskbd_map_data kbmap = /* used in map_parse.y and in util.c */ 51 { KS_NUMKEYCODES, mapdata }; 52static struct wscons_keymap oldmapdata[KS_NUMKEYCODES]; 53static struct wskbd_map_data oldkbmap = 54 { KS_NUMKEYCODES, oldmapdata }; 55static struct wskbd_keyrepeat_data repeat; 56static struct wskbd_keyrepeat_data dfrepeat; 57static struct wskbd_scroll_data scroll; 58static int ledstate; 59static kbd_t kbdencoding; 60static int havescroll = 1; 61static int kbmode; 62 63struct field keyboard_field_tab[] = { 64 { "type", &kbtype, FMT_KBDTYPE, FLG_RDONLY }, 65 { "mode", &kbmode, FMT_UINT, FLG_MODIFY }, 66 { "bell.pitch", &bell.pitch, FMT_UINT, FLG_MODIFY }, 67 { "bell.period", &bell.period, FMT_UINT, FLG_MODIFY }, 68 { "bell.volume", &bell.volume, FMT_UINT, FLG_MODIFY }, 69 { "bell.pitch.default", &dfbell.pitch, FMT_UINT, FLG_MODIFY }, 70 { "bell.period.default", &dfbell.period, FMT_UINT, FLG_MODIFY }, 71 { "bell.volume.default", &dfbell.volume, FMT_UINT, FLG_MODIFY }, 72 { "map", &kbmap, FMT_KBMAP, FLG_MODIFY | 73 FLG_NOAUTO }, 74 { "repeat.del1", &repeat.del1, FMT_UINT, FLG_MODIFY }, 75 { "repeat.deln", &repeat.delN, FMT_UINT, FLG_MODIFY }, 76 { "repeat.del1.default", &dfrepeat.del1, FMT_UINT, FLG_MODIFY }, 77 { "repeat.deln.default", &dfrepeat.delN, FMT_UINT, FLG_MODIFY }, 78 { "ledstate", &ledstate, FMT_UINT, 0 }, 79 { "encoding", &kbdencoding, FMT_KBDENC, FLG_MODIFY }, 80 { "keyclick", &keyclick, FMT_UINT, FLG_MODIFY }, 81 { "scroll.mode", &scroll.mode, FMT_UINT, FLG_MODIFY }, 82 { "scroll.modifier", &scroll.modifier, FMT_UINT, FLG_MODIFY }, 83}; 84 85int keyboard_field_tab_len = sizeof(keyboard_field_tab) / 86 sizeof(keyboard_field_tab[0]); 87 88static void 89diff_kmap(struct wskbd_map_data *omap, struct wskbd_map_data *nmap) 90{ 91 unsigned int u; 92 struct wscons_keymap *op, *np; 93 94 for (u = 0; u < nmap->maplen; u++) { 95 op = omap->map + u; 96 np = nmap->map + u; 97 if (op->command == np->command && 98 op->group1[0] == np->group1[0] && 99 op->group1[1] == np->group1[1] && 100 op->group2[0] == np->group2[0] && 101 op->group2[1] == np->group2[1]) { 102 np->command = KS_voidSymbol; 103 np->group1[0] = KS_voidSymbol; 104 np->group1[1] = KS_voidSymbol; 105 np->group2[0] = KS_voidSymbol; 106 np->group2[1] = KS_voidSymbol; 107 } 108 } 109} 110 111void 112keyboard_get_values(int fd) 113{ 114 115 if (field_by_value(&kbtype)->flags & FLG_GET) 116 if (ioctl(fd, WSKBDIO_GTYPE, &kbtype) < 0) 117 err(EXIT_FAILURE, "WSKBDIO_GTYPE"); 118 119 if (field_by_value(&kbmode)->flags & FLG_GET) { 120 ioctl(fd, WSKBDIO_GETMODE, &kbmode); 121 /* Optional; don't complain. */ 122 } 123 124 bell.which = 0; 125 if (field_by_value(&bell.pitch)->flags & FLG_GET) 126 bell.which |= WSKBD_BELL_DOPITCH; 127 if (field_by_value(&bell.period)->flags & FLG_GET) 128 bell.which |= WSKBD_BELL_DOPERIOD; 129 if (field_by_value(&bell.volume)->flags & FLG_GET) 130 bell.which |= WSKBD_BELL_DOVOLUME; 131 if (bell.which != 0 && ioctl(fd, WSKBDIO_GETBELL, &bell) < 0) 132 err(EXIT_FAILURE, "WSKBDIO_GETBELL"); 133 134 dfbell.which = 0; 135 if (field_by_value(&dfbell.pitch)->flags & FLG_GET) 136 dfbell.which |= WSKBD_BELL_DOPITCH; 137 if (field_by_value(&dfbell.period)->flags & FLG_GET) 138 dfbell.which |= WSKBD_BELL_DOPERIOD; 139 if (field_by_value(&dfbell.volume)->flags & FLG_GET) 140 dfbell.which |= WSKBD_BELL_DOVOLUME; 141 if (dfbell.which != 0 && 142 ioctl(fd, WSKBDIO_GETDEFAULTBELL, &dfbell) < 0) 143 err(EXIT_FAILURE, "WSKBDIO_GETDEFAULTBELL"); 144 145 if (field_by_value(&kbmap)->flags & FLG_GET) { 146 kbmap.maplen = KS_NUMKEYCODES; 147 if (ioctl(fd, WSKBDIO_GETMAP, &kbmap) < 0) 148 err(EXIT_FAILURE, "WSKBDIO_GETMAP"); 149 memcpy(oldmapdata, mapdata, sizeof(oldmapdata)); 150 } 151 152 repeat.which = 0; 153 if (field_by_value(&repeat.del1)->flags & FLG_GET) 154 repeat.which |= WSKBD_KEYREPEAT_DODEL1; 155 if (field_by_value(&repeat.delN)->flags & FLG_GET) 156 repeat.which |= WSKBD_KEYREPEAT_DODELN; 157 if (repeat.which != 0 && 158 ioctl(fd, WSKBDIO_GETKEYREPEAT, &repeat) < 0) 159 err(EXIT_FAILURE, "WSKBDIO_GETKEYREPEAT"); 160 161 dfrepeat.which = 0; 162 if (field_by_value(&dfrepeat.del1)->flags & FLG_GET) 163 dfrepeat.which |= WSKBD_KEYREPEAT_DODEL1; 164 if (field_by_value(&dfrepeat.delN)->flags & FLG_GET) 165 dfrepeat.which |= WSKBD_KEYREPEAT_DODELN; 166 if (dfrepeat.which != 0 && 167 ioctl(fd, WSKBDIO_GETKEYREPEAT, &dfrepeat) < 0) 168 err(EXIT_FAILURE, "WSKBDIO_GETKEYREPEAT"); 169 170 if (field_by_value(&ledstate)->flags & FLG_GET) 171 if (ioctl(fd, WSKBDIO_GETLEDS, &ledstate) < 0) 172 err(EXIT_FAILURE, "WSKBDIO_GETLEDS"); 173 174 if (field_by_value(&kbdencoding)->flags & FLG_GET) 175 if (ioctl(fd, WSKBDIO_GETENCODING, &kbdencoding) < 0) 176 err(EXIT_FAILURE, "WSKBDIO_GETENCODING"); 177 178 if (field_by_value(&keyclick)->flags & FLG_GET) { 179 ioctl(fd, WSKBDIO_GETKEYCLICK, &keyclick); 180 /* Optional; don't complain. */ 181 } 182 183 scroll.which = 0; 184 if (field_by_value(&scroll.mode)->flags & FLG_GET) 185 scroll.which |= WSKBD_SCROLL_DOMODE; 186 if (field_by_value(&scroll.modifier)->flags & FLG_GET) 187 scroll.which |= WSKBD_SCROLL_DOMODIFIER; 188 if (scroll.which != 0) { 189 if (ioctl(fd, WSKBDIO_GETSCROLL, &scroll) == -1) { 190 if (errno != ENODEV) 191 err(EXIT_FAILURE, "WSKBDIO_GETSCROLL"); 192 else 193 havescroll = 0; 194 } 195 } 196} 197 198void 199keyboard_put_values(int fd) 200{ 201 202 if (field_by_value(&kbmode)->flags & FLG_SET) { 203 if (ioctl(fd, WSKBDIO_SETMODE, &kbmode) < 0) 204 err(EXIT_FAILURE, "WSKBDIO_SETMODE"); 205 pr_field(field_by_value(&kbmode), " -> "); 206 } 207 208 bell.which = 0; 209 if (field_by_value(&bell.pitch)->flags & FLG_SET) 210 bell.which |= WSKBD_BELL_DOPITCH; 211 if (field_by_value(&bell.period)->flags & FLG_SET) 212 bell.which |= WSKBD_BELL_DOPERIOD; 213 if (field_by_value(&bell.volume)->flags & FLG_SET) 214 bell.which |= WSKBD_BELL_DOVOLUME; 215 if (bell.which != 0 && ioctl(fd, WSKBDIO_SETBELL, &bell) < 0) 216 err(EXIT_FAILURE, "WSKBDIO_SETBELL"); 217 if (bell.which & WSKBD_BELL_DOPITCH) 218 pr_field(field_by_value(&bell.pitch), " -> "); 219 if (bell.which & WSKBD_BELL_DOPERIOD) 220 pr_field(field_by_value(&bell.period), " -> "); 221 if (bell.which & WSKBD_BELL_DOVOLUME) 222 pr_field(field_by_value(&bell.volume), " -> "); 223 224 dfbell.which = 0; 225 if (field_by_value(&dfbell.pitch)->flags & FLG_SET) 226 dfbell.which |= WSKBD_BELL_DOPITCH; 227 if (field_by_value(&dfbell.period)->flags & FLG_SET) 228 dfbell.which |= WSKBD_BELL_DOPERIOD; 229 if (field_by_value(&dfbell.volume)->flags & FLG_SET) 230 dfbell.which |= WSKBD_BELL_DOVOLUME; 231 if (dfbell.which != 0 && 232 ioctl(fd, WSKBDIO_SETDEFAULTBELL, &dfbell) < 0) 233 err(EXIT_FAILURE, "WSKBDIO_SETDEFAULTBELL"); 234 if (dfbell.which & WSKBD_BELL_DOPITCH) 235 pr_field(field_by_value(&dfbell.pitch), " -> "); 236 if (dfbell.which & WSKBD_BELL_DOPERIOD) 237 pr_field(field_by_value(&dfbell.period), " -> "); 238 if (dfbell.which & WSKBD_BELL_DOVOLUME) 239 pr_field(field_by_value(&dfbell.volume), " -> "); 240 241 if (field_by_value(&kbmap)->flags & FLG_SET) { 242 if (ioctl(fd, WSKBDIO_SETMAP, &kbmap) < 0) 243 err(EXIT_FAILURE, "WSKBDIO_SETMAP"); 244 if (field_by_value(&kbmap)->flags & FLG_MODIFIED) { 245 diff_kmap(&oldkbmap, &kbmap); 246 pr_field(field_by_value(&kbmap), " +> "); 247 } else 248 pr_field(field_by_value(&kbmap), " -> "); 249 } 250 251 repeat.which = 0; 252 if (field_by_value(&repeat.del1)->flags & FLG_SET) 253 repeat.which |= WSKBD_KEYREPEAT_DODEL1; 254 if (field_by_value(&repeat.delN)->flags & FLG_SET) 255 repeat.which |= WSKBD_KEYREPEAT_DODELN; 256 if (repeat.which != 0 && 257 ioctl(fd, WSKBDIO_SETKEYREPEAT, &repeat) < 0) 258 err(EXIT_FAILURE, "WSKBDIO_SETKEYREPEAT"); 259 if (repeat.which & WSKBD_KEYREPEAT_DODEL1) 260 pr_field(field_by_value(&repeat.del1), " -> "); 261 if (repeat.which & WSKBD_KEYREPEAT_DODELN) 262 pr_field(field_by_value(&repeat.delN), " -> "); 263 264 dfrepeat.which = 0; 265 if (field_by_value(&dfrepeat.del1)->flags & FLG_SET) 266 dfrepeat.which |= WSKBD_KEYREPEAT_DODEL1; 267 if (field_by_value(&dfrepeat.delN)->flags & FLG_SET) 268 dfrepeat.which |= WSKBD_KEYREPEAT_DODELN; 269 if (dfrepeat.which != 0 && 270 ioctl(fd, WSKBDIO_SETDEFAULTKEYREPEAT, &dfrepeat) < 0) 271 err(EXIT_FAILURE, "WSKBDIO_SETDEFAULTKEYREPEAT"); 272 if (dfrepeat.which &WSKBD_KEYREPEAT_DODEL1) 273 pr_field(field_by_value(&dfrepeat.del1), " -> "); 274 if (dfrepeat.which & WSKBD_KEYREPEAT_DODELN) 275 pr_field(field_by_value(&dfrepeat.delN), " -> "); 276 277 if (field_by_value(&ledstate)->flags & FLG_SET) { 278 if (ioctl(fd, WSKBDIO_SETLEDS, &ledstate) < 0) 279 err(EXIT_FAILURE, "WSKBDIO_SETLEDS"); 280 pr_field(field_by_value(&ledstate), " -> "); 281 } 282 283 if (field_by_value(&kbdencoding)->flags & FLG_SET) { 284 if (ioctl(fd, WSKBDIO_SETENCODING, &kbdencoding) < 0) 285 err(EXIT_FAILURE, "WSKBDIO_SETENCODING"); 286 pr_field(field_by_value(&kbdencoding), " -> "); 287 } 288 289 if (field_by_value(&keyclick)->flags & FLG_SET) { 290 if (ioctl(fd, WSKBDIO_SETKEYCLICK, &keyclick) < 0) 291 err(EXIT_FAILURE, "WSKBDIO_SETKEYCLICK"); 292 pr_field(field_by_value(&keyclick), " -> "); 293 } 294 295 296 if (havescroll == 0) 297 return; 298 299 scroll.which = 0; 300 if (field_by_value(&scroll.mode)->flags & FLG_SET) 301 scroll.which |= WSKBD_SCROLL_DOMODE; 302 if (field_by_value(&scroll.modifier)->flags & FLG_SET) 303 scroll.which |= WSKBD_SCROLL_DOMODIFIER; 304 305 if (scroll.which & WSKBD_SCROLL_DOMODE) 306 pr_field(field_by_value(&scroll.mode), " -> "); 307 if (scroll.which & WSKBD_SCROLL_DOMODIFIER) 308 pr_field(field_by_value(&scroll.modifier), " -> "); 309 if (scroll.which != 0) { 310 if (ioctl(fd, WSKBDIO_SETSCROLL, &scroll) == -1) { 311 if (errno != ENODEV) 312 err(EXIT_FAILURE, "WSKBDIO_SETSCROLL"); 313 else { 314 warnx("scrolling is not supported by this " 315 "kernel"); 316 havescroll = 0; 317 } 318 } 319 } 320} 321 322