1/* $OpenBSD: kbd_wscons.c,v 1.36 2022/05/05 16:12:42 bluhm Exp $ */ 2 3/* 4 * Copyright (c) 2001 Mats O Jansson. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <sys/ioctl.h> 28#include <sys/time.h> 29#include <dev/wscons/wsconsio.h> 30#include <dev/wscons/wsksymdef.h> 31 32#include <err.h> 33#include <errno.h> 34#include <fcntl.h> 35#include <limits.h> 36#include <stdio.h> 37#include <stdlib.h> 38#include <string.h> 39#include <unistd.h> 40 41#define NUM_KBD 10 42 43char *kbtype_tab[] = { 44 "pc-xt/pc-at", 45 "usb", 46 "adb", 47 "lk201", 48 "sun", 49 "sun5", 50 "hil", 51 "gsc", 52 "sgi" 53}; 54enum { SA_PCKBD, 55 SA_UKBD, 56 SA_AKBD, 57 SA_LKKBD, 58 SA_SUNKBD, 59 SA_SUN5KBD, 60 SA_HILKBD, 61 SA_GSCKBD, 62 SA_SGIKBD, 63 64 SA_MAX 65}; 66 67struct nameint { 68 int value; 69 char *name; 70}; 71 72struct nameint kbdenc_tab[] = { 73 KB_ENCTAB 74 , 75 { 0, NULL } 76}; 77 78struct nameint kbdvar_tab[] = { 79 KB_VARTAB 80 , 81 { 0, NULL } 82}; 83 84extern char *__progname; 85 86void kbd_show_enc(struct wskbd_encoding_data *encs, int idx); 87void kbd_get_encs(int fd, struct wskbd_encoding_data *encs); 88void kbd_list(void); 89void kbd_set(char *name, int verbose); 90 91void 92kbd_show_enc(struct wskbd_encoding_data *encs, int idx) 93{ 94 int found; 95 kbd_t encoding, variant; 96 struct nameint *n; 97 int i; 98 99 printf("tables available for %s keyboard:\nencoding\n\n", 100 kbtype_tab[idx]); 101 102 for (i = 0; i < encs->nencodings; i++) { 103 found = 0; 104 encoding = encs->encodings[i]; 105 for (n = &kbdenc_tab[0]; n->value; n++) { 106 if (n->value == KB_ENCODING(encoding)) { 107 printf("%s", n->name); 108 found++; 109 } 110 } 111 if (found == 0) 112 printf("<encoding 0x%04x>", KB_ENCODING(encoding)); 113 found = 0; 114 variant = KB_VARIANT(encoding); 115 for (n = &kbdvar_tab[0]; n->value; n++) { 116 if ((n->value & KB_VARIANT(encoding)) == n->value) { 117 printf(".%s", n->name); 118 variant &= ~n->value; 119 } 120 } 121 if (variant != 0) 122 printf(".<variant 0x%08x>", variant); 123 printf("\n"); 124 } 125 printf("\n"); 126} 127 128void 129kbd_get_encs(int fd, struct wskbd_encoding_data *encs) 130{ 131 int nencodings = 64; 132 133 encs->nencodings = nencodings; 134 while (encs->nencodings == nencodings) { 135 encs->encodings = reallocarray(encs->encodings, 136 encs->nencodings, sizeof(kbd_t)); 137 if (encs->encodings == NULL) 138 err(1, NULL); 139 if (ioctl(fd, WSKBDIO_GETENCODINGS, encs) == -1) 140 err(1, "WSKBDIO_GETENCODINGS"); 141 if (encs->nencodings == nencodings) { 142 nencodings *= 2; 143 encs->nencodings = nencodings; 144 } 145 } 146} 147 148void 149kbd_list(void) 150{ 151 int kbds[SA_MAX]; 152 struct wskbd_encoding_data encs[SA_MAX]; 153 int fd, i, kbtype, t, error = 0; 154 char device[PATH_MAX]; 155 156 memset(kbds, 0, sizeof(kbds)); 157 memset(encs, 0, sizeof(encs)); 158 159 /* Go through all keyboards. */ 160 for (i = 0; i < NUM_KBD; i++) { 161 (void) snprintf(device, sizeof device, "/dev/wskbd%d", i); 162 fd = open(device, O_WRONLY); 163 if (fd == -1) 164 fd = open(device, O_RDONLY); 165 if (fd == -1) { 166 /* remember the first error number */ 167 if (error == 0) 168 error = errno; 169 } else { 170 /* at least one success, do not print error */ 171 error = -1; 172 173 if (ioctl(fd, WSKBDIO_GTYPE, &kbtype) == -1) 174 err(1, "WSKBDIO_GTYPE %s", device); 175 switch (kbtype) { 176 case WSKBD_TYPE_PC_XT: 177 case WSKBD_TYPE_PC_AT: 178 t = SA_PCKBD; 179 break; 180 case WSKBD_TYPE_USB: 181 t = SA_UKBD; 182 break; 183 case WSKBD_TYPE_ADB: 184 t = SA_AKBD; 185 break; 186 case WSKBD_TYPE_LK201: 187 case WSKBD_TYPE_LK401: 188 t = SA_LKKBD; 189 break; 190 case WSKBD_TYPE_SUN: 191 t = SA_SUNKBD; 192 break; 193 case WSKBD_TYPE_SUN5: 194 t = SA_SUN5KBD; 195 break; 196 case WSKBD_TYPE_HIL: 197 t = SA_HILKBD; 198 break; 199 case WSKBD_TYPE_GSC: 200 t = SA_GSCKBD; 201 break; 202 case WSKBD_TYPE_SGI: 203 t = SA_SGIKBD; 204 break; 205 default: 206 t = SA_MAX; 207 break; 208 } 209 210 if (t != SA_MAX) { 211 kbds[t]++; 212 if (encs[t].encodings == NULL) 213 kbd_get_encs(fd, &encs[t]); 214 } 215 close(fd); 216 } 217 } 218 if (error > 0) { 219 errno = error; 220 err(1, "/dev/wskbd0"); 221 } 222 223 for (i = 0; i < SA_MAX; i++) 224 if (kbds[i] != 0) 225 kbd_show_enc(&encs[i], i); 226 227 for (i = 0; i < SA_MAX; i++) 228 free(encs[i].encodings); 229} 230 231void 232kbd_set(char *name, int verbose) 233{ 234 char buf[LINE_MAX], *c, *b, device[sizeof "/dev/wskbd00"]; 235 int map = 0, v, i, fd, error = 0; 236 struct nameint *n; 237 238 c = name; 239 b = buf; 240 while (*c != '.' && *c != '\0' && b < buf + sizeof(buf) - 1) 241 *b++ = *c++; 242 *b = '\0'; 243 n = &kbdenc_tab[0]; 244 while (n->value) { 245 if (strcmp(n->name, buf) == 0) 246 map = n->value; 247 n++; 248 } 249 if (map == 0) 250 errx(1, "unknown encoding %s", buf); 251 while (*c == '.') { 252 b = buf; 253 c++; 254 while (*c != '.' && *c != '\0' && b < buf + sizeof(buf) - 1) 255 *b++ = *c++; 256 *b = '\0'; 257 v = 0; 258 for (n = &kbdvar_tab[0]; n->value; n++) { 259 if (strcmp(n->name, buf) == 0) 260 v = n->value; 261 } 262 if (v == 0) 263 errx(1, "unknown variant %s", buf); 264 map |= v; 265 } 266 267 /* Go through all keyboards. */ 268 v = 0; 269 for (i = 0; i < NUM_KBD; i++) { 270 (void) snprintf(device, sizeof device, "/dev/wskbd%d", i); 271 fd = open(device, O_WRONLY); 272 if (fd == -1) 273 fd = open(device, O_RDONLY); 274 if (fd == -1) { 275 /* remember the first error number */ 276 if (error == 0) 277 error = errno; 278 } else { 279 /* at least one success, do not print error */ 280 error = -1; 281 282 if (ioctl(fd, WSKBDIO_SETENCODING, &map) == -1) { 283 if (errno != EINVAL) 284 err(1, "WSKBDIO_SETENCODING %s", 285 device); 286 fprintf(stderr, 287 "%s: unsupported encoding %s on %s\n", 288 __progname, name, device); 289 } else 290 v++; 291 close(fd); 292 } 293 } 294 if (error > 0) { 295 errno = error; 296 err(1, "/dev/wskbd0"); 297 } 298 299 if (verbose && v > 0) 300 fprintf(stderr, "kbd: keyboard mapping set to %s\n", name); 301} 302