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