kbd_wscons.c revision 1.16
1/* $OpenBSD: kbd_wscons.c,v 1.16 2004/05/09 03:21:52 deraadt 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/param.h> 28#include <sys/ioctl.h> 29#include <sys/time.h> 30#include <dev/wscons/wsconsio.h> 31#include <dev/wscons/wsksymdef.h> 32 33#include <err.h> 34#include <errno.h> 35#include <kvm.h> 36#include <fcntl.h> 37#include <limits.h> 38#include <nlist.h> 39#include <stdio.h> 40#include <string.h> 41#include <unistd.h> 42 43#define NUM_KBD 10 44 45#define SA_PCKBD 0 46#define SA_UKBD 1 47#define SA_AKBD 2 48#define SA_ZSKBD 3 49#define SA_SUNKBD 4 50#define SA_SUN5KBD 5 51#define SA_HILKBD 6 52#define SA_GSCKBD 7 53 54struct nlist nl[] = { 55 { "_pckbd_keydesctab" }, 56 { "_ukbd_keydesctab" }, 57 { "_akbd_keydesctab" }, 58 { "_zskbd_keydesctab" }, 59 { "_sunkbd_keydesctab" }, 60 { "_sunkbd5_keydesctab" }, 61 { "_hilkbd_keydesctab" }, 62 { "_gsckbd_keydesctab" }, 63 { NULL }, 64}; 65 66char *kbtype_tab[] = { 67 "pc-xt/pc-at", 68 "usb", 69 "adb", 70 "lk201", 71 "sun", 72 "sun5", 73 "hil", 74 "gsc", 75}; 76 77struct nameint { 78 int value; 79 char *name; 80}; 81 82struct nameint kbdenc_tab[] = { 83 KB_ENCTAB 84 , 85 { 0, 0 } 86}; 87 88struct nameint kbdvar_tab[] = { 89 KB_VARTAB 90 , 91 { 0, 0 } 92}; 93 94extern char *__progname; 95int rebuild = 0; 96 97void kbd_show_enc(kvm_t *kd, int idx); 98void kbd_list(void); 99void kbd_set(char *name, int verbose); 100 101#ifndef NOKVM 102void 103kbd_show_enc(kvm_t *kd, int idx) 104{ 105 struct wscons_keydesc r; 106 unsigned long p; 107 struct nameint *n; 108 int found; 109 u_int32_t variant; 110 111 printf("tables available for %s keyboard:\nencoding\n\n", 112 kbtype_tab[idx]); 113 p = nl[idx].n_value; 114 kvm_read(kd, p, &r, sizeof(r)); 115 while (r.name != 0) { 116 n = &kbdenc_tab[0]; 117 found = 0; 118 while (n->value) { 119 if (n->value == KB_ENCODING(r.name)) { 120 printf("%s",n->name); 121 found++; 122 } 123 n++; 124 } 125 if (found == 0) { 126 printf("<encoding 0x%04x>",KB_ENCODING(r.name)); 127 rebuild++; 128 } 129 n = &kbdvar_tab[0]; 130 found = 0; 131 variant = KB_VARIANT(r.name); 132 while (n->value) { 133 if ((n->value & KB_VARIANT(r.name)) == n->value) { 134 printf(".%s",n->name); 135 variant &= ~n->value; 136 } 137 n++; 138 } 139 if (variant != 0) { 140 printf(".<variant 0x%08x>",variant); 141 rebuild++; 142 } 143 printf("\n"); 144 p += sizeof(r); 145 kvm_read(kd, p, &r, sizeof(r)); 146 } 147 printf("\n"); 148} 149#endif 150 151void 152kbd_list(void) 153{ 154 int fd, i, kbtype; 155 kvm_t *kd; 156 char device[MAXPATHLEN]; 157 char errbuf[_POSIX2_LINE_MAX]; 158 int pc_kbd = 0; 159 int usb_kbd = 0; 160 int adb_kbd = 0; 161 int zs_kbd = 0; 162 int sun_kbd = 0; 163 int sun5_kbd = 0; 164 int hil_kbd = 0; 165 int gsc_kbd = 0; 166 167 /* Go through all keyboards. */ 168 for (i = 0; i < NUM_KBD; i++) { 169 (void) snprintf(device, sizeof device, "/dev/wskbd%d", i); 170 fd = open(device, O_WRONLY); 171 if (fd < 0) 172 fd = open(device, O_RDONLY); 173 if (fd >= 0) { 174 if (ioctl(fd, WSKBDIO_GTYPE, &kbtype) < 0) 175 err(1, "WSKBDIO_GTYPE"); 176 if ((kbtype == WSKBD_TYPE_PC_XT) || 177 (kbtype == WSKBD_TYPE_PC_AT)) 178 pc_kbd++; 179 if (kbtype == WSKBD_TYPE_USB) 180 usb_kbd++; 181 if (kbtype == WSKBD_TYPE_ADB) 182 adb_kbd++; 183 if (kbtype == WSKBD_TYPE_LK201) 184 zs_kbd++; 185 if (kbtype == WSKBD_TYPE_SUN) 186 sun_kbd++; 187 if (kbtype == WSKBD_TYPE_SUN5) 188 sun5_kbd++; 189 if (kbtype == WSKBD_TYPE_HIL) 190 hil_kbd++; 191 if (kbtype == WSKBD_TYPE_GSC) 192 gsc_kbd++; 193 close(fd); 194 } 195 } 196 197#ifndef NOKVM 198 if ((kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf)) == 0) 199 errx(1, "kvm_openfiles: %s", errbuf); 200 201 if (kvm_nlist(kd, nl) == -1) 202 errx(1, "kvm_nlist: %s", kvm_geterr(kd)); 203 204 if (pc_kbd > 0) 205 kbd_show_enc(kd, SA_PCKBD); 206 207 if (usb_kbd > 0) 208 kbd_show_enc(kd, SA_UKBD); 209 210 if (adb_kbd > 0) 211 kbd_show_enc(kd, SA_AKBD); 212 213 if (zs_kbd > 0) 214 kbd_show_enc(kd, SA_ZSKBD); 215 216 if (sun_kbd > 0) 217 kbd_show_enc(kd, SA_SUNKBD); 218 219 if (sun5_kbd > 0) 220 kbd_show_enc(kd, SA_SUN5KBD); 221 222 if (hil_kbd > 0) 223 kbd_show_enc(kd, SA_HILKBD); 224 225 if (gsc_kbd > 0) 226 kbd_show_enc(kd, SA_GSCKBD); 227 228 kvm_close(kd); 229 230 if (rebuild > 0) { 231 printf("Unknown encoding or variant. kbd(1) needs to be rebuilt.\n"); 232 } 233#else 234 printf("List not available; sorry.\n"); 235#endif 236} 237 238void 239kbd_set(char *name, int verbose) 240{ 241 char buf[_POSIX2_LINE_MAX]; 242 char *c,*b; 243 struct nameint *n; 244 int map = 0,v,i,fd; 245 char device[sizeof "/dev/wskbd00"]; 246 247 c = name; 248 b = buf; 249 while ((*c != '.') && (*c != '\0')) { 250 *b++ = *c++; 251 } 252 *b = '\0'; 253 n = &kbdenc_tab[0]; 254 while (n->value) { 255 if (strcmp(n->name,buf) == 0) { 256 map = n->value; 257 } 258 n++; 259 } 260 if (map == 0) 261 errx(1, "unknown encoding %s", buf); 262 while (*c == '.') { 263 b = buf; 264 c++; 265 while ((*c != '.') && (*c != '\0')) { 266 *b++ = *c++; 267 } 268 *b = '\0'; 269 v = 0; 270 n = &kbdvar_tab[0]; 271 while (n->value) { 272 if (strcmp(n->name,buf) == 0) { 273 v = n->value; 274 } 275 n++; 276 } 277 if (v == 0) 278 errx(1, "unknown variant %s", buf); 279 map |= v; 280 } 281 282 /* Go through all keyboards. */ 283 v = 0; 284 for (i = 0; i < NUM_KBD; i++) { 285 (void) snprintf(device, sizeof device, "/dev/wskbd%d", i); 286 fd = open(device, O_WRONLY); 287 if (fd < 0) 288 fd = open(device, O_RDONLY); 289 if (fd >= 0) { 290 if (ioctl(fd, WSKBDIO_SETENCODING, &map) < 0) { 291 if (errno == EINVAL) { 292 fprintf(stderr, 293 "%s: unsupported encoding %s on %s\n", 294 __progname, name, device); 295 } else { 296 err(1, "WSKBDIO_SETENCODING: %s", device); 297 } 298 v--; 299 } 300 v++; 301 close(fd); 302 } 303 } 304 305 if (verbose && v > 0) 306 fprintf(stderr, "keyboard mapping set to %s\n", name); 307} 308