302 lines
6.6 KiB
C
302 lines
6.6 KiB
C
/* $OpenBSD: kbd_wscons.c,v 1.36 2022/05/05 16:12:42 bluhm Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 2001 Mats O Jansson. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/ioctl.h>
|
|
#include <sys/time.h>
|
|
#include <dev/wscons/wsconsio.h>
|
|
#include <dev/wscons/wsksymdef.h>
|
|
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <limits.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#define NUM_KBD 10
|
|
|
|
char *kbtype_tab[] = {
|
|
"pc-xt/pc-at",
|
|
"usb",
|
|
"adb",
|
|
"lk201",
|
|
"sun",
|
|
"sun5",
|
|
"hil",
|
|
"gsc",
|
|
"sgi"
|
|
};
|
|
enum { SA_PCKBD,
|
|
SA_UKBD,
|
|
SA_AKBD,
|
|
SA_LKKBD,
|
|
SA_SUNKBD,
|
|
SA_SUN5KBD,
|
|
SA_HILKBD,
|
|
SA_GSCKBD,
|
|
SA_SGIKBD,
|
|
|
|
SA_MAX
|
|
};
|
|
|
|
struct nameint {
|
|
int value;
|
|
char *name;
|
|
};
|
|
|
|
struct nameint kbdenc_tab[] = {
|
|
KB_ENCTAB
|
|
,
|
|
{ 0, NULL }
|
|
};
|
|
|
|
struct nameint kbdvar_tab[] = {
|
|
KB_VARTAB
|
|
,
|
|
{ 0, NULL }
|
|
};
|
|
|
|
extern char *__progname;
|
|
|
|
void kbd_show_enc(struct wskbd_encoding_data *encs, int idx);
|
|
void kbd_get_encs(int fd, struct wskbd_encoding_data *encs);
|
|
void kbd_list(void);
|
|
void kbd_set(char *name, int verbose);
|
|
|
|
void
|
|
kbd_show_enc(struct wskbd_encoding_data *encs, int idx)
|
|
{
|
|
int found;
|
|
kbd_t encoding, variant;
|
|
struct nameint *n;
|
|
int i;
|
|
|
|
printf("tables available for %s keyboard:\nencoding\n\n",
|
|
kbtype_tab[idx]);
|
|
|
|
for (i = 0; i < encs->nencodings; i++) {
|
|
found = 0;
|
|
encoding = encs->encodings[i];
|
|
for (n = &kbdenc_tab[0]; n->value; n++) {
|
|
if (n->value == KB_ENCODING(encoding)) {
|
|
printf("%s", n->name);
|
|
found++;
|
|
}
|
|
}
|
|
if (found == 0)
|
|
printf("<encoding 0x%04x>", KB_ENCODING(encoding));
|
|
found = 0;
|
|
variant = KB_VARIANT(encoding);
|
|
for (n = &kbdvar_tab[0]; n->value; n++) {
|
|
if ((n->value & KB_VARIANT(encoding)) == n->value) {
|
|
printf(".%s", n->name);
|
|
variant &= ~n->value;
|
|
}
|
|
}
|
|
if (variant != 0)
|
|
printf(".<variant 0x%08x>", variant);
|
|
printf("\n");
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
void
|
|
kbd_get_encs(int fd, struct wskbd_encoding_data *encs)
|
|
{
|
|
int nencodings = 64;
|
|
|
|
encs->nencodings = nencodings;
|
|
while (encs->nencodings == nencodings) {
|
|
encs->encodings = reallocarray(encs->encodings,
|
|
encs->nencodings, sizeof(kbd_t));
|
|
if (encs->encodings == NULL)
|
|
err(1, NULL);
|
|
if (ioctl(fd, WSKBDIO_GETENCODINGS, encs) == -1)
|
|
err(1, "WSKBDIO_GETENCODINGS");
|
|
if (encs->nencodings == nencodings) {
|
|
nencodings *= 2;
|
|
encs->nencodings = nencodings;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
kbd_list(void)
|
|
{
|
|
int kbds[SA_MAX];
|
|
struct wskbd_encoding_data encs[SA_MAX];
|
|
int fd, i, kbtype, t, error = 0;
|
|
char device[PATH_MAX];
|
|
|
|
memset(kbds, 0, sizeof(kbds));
|
|
memset(encs, 0, sizeof(encs));
|
|
|
|
/* Go through all keyboards. */
|
|
for (i = 0; i < NUM_KBD; i++) {
|
|
(void) snprintf(device, sizeof device, "/dev/wskbd%d", i);
|
|
fd = open(device, O_WRONLY);
|
|
if (fd == -1)
|
|
fd = open(device, O_RDONLY);
|
|
if (fd == -1) {
|
|
/* remember the first error number */
|
|
if (error == 0)
|
|
error = errno;
|
|
} else {
|
|
/* at least one success, do not print error */
|
|
error = -1;
|
|
|
|
if (ioctl(fd, WSKBDIO_GTYPE, &kbtype) == -1)
|
|
err(1, "WSKBDIO_GTYPE %s", device);
|
|
switch (kbtype) {
|
|
case WSKBD_TYPE_PC_XT:
|
|
case WSKBD_TYPE_PC_AT:
|
|
t = SA_PCKBD;
|
|
break;
|
|
case WSKBD_TYPE_USB:
|
|
t = SA_UKBD;
|
|
break;
|
|
case WSKBD_TYPE_ADB:
|
|
t = SA_AKBD;
|
|
break;
|
|
case WSKBD_TYPE_LK201:
|
|
case WSKBD_TYPE_LK401:
|
|
t = SA_LKKBD;
|
|
break;
|
|
case WSKBD_TYPE_SUN:
|
|
t = SA_SUNKBD;
|
|
break;
|
|
case WSKBD_TYPE_SUN5:
|
|
t = SA_SUN5KBD;
|
|
break;
|
|
case WSKBD_TYPE_HIL:
|
|
t = SA_HILKBD;
|
|
break;
|
|
case WSKBD_TYPE_GSC:
|
|
t = SA_GSCKBD;
|
|
break;
|
|
case WSKBD_TYPE_SGI:
|
|
t = SA_SGIKBD;
|
|
break;
|
|
default:
|
|
t = SA_MAX;
|
|
break;
|
|
}
|
|
|
|
if (t != SA_MAX) {
|
|
kbds[t]++;
|
|
if (encs[t].encodings == NULL)
|
|
kbd_get_encs(fd, &encs[t]);
|
|
}
|
|
close(fd);
|
|
}
|
|
}
|
|
if (error > 0) {
|
|
errno = error;
|
|
err(1, "/dev/wskbd0");
|
|
}
|
|
|
|
for (i = 0; i < SA_MAX; i++)
|
|
if (kbds[i] != 0)
|
|
kbd_show_enc(&encs[i], i);
|
|
|
|
for (i = 0; i < SA_MAX; i++)
|
|
free(encs[i].encodings);
|
|
}
|
|
|
|
void
|
|
kbd_set(char *name, int verbose)
|
|
{
|
|
char buf[LINE_MAX], *c, *b, device[sizeof "/dev/wskbd00"];
|
|
int map = 0, v, i, fd, error = 0;
|
|
struct nameint *n;
|
|
|
|
c = name;
|
|
b = buf;
|
|
while (*c != '.' && *c != '\0' && b < buf + sizeof(buf) - 1)
|
|
*b++ = *c++;
|
|
*b = '\0';
|
|
n = &kbdenc_tab[0];
|
|
while (n->value) {
|
|
if (strcmp(n->name, buf) == 0)
|
|
map = n->value;
|
|
n++;
|
|
}
|
|
if (map == 0)
|
|
errx(1, "unknown encoding %s", buf);
|
|
while (*c == '.') {
|
|
b = buf;
|
|
c++;
|
|
while (*c != '.' && *c != '\0' && b < buf + sizeof(buf) - 1)
|
|
*b++ = *c++;
|
|
*b = '\0';
|
|
v = 0;
|
|
for (n = &kbdvar_tab[0]; n->value; n++) {
|
|
if (strcmp(n->name, buf) == 0)
|
|
v = n->value;
|
|
}
|
|
if (v == 0)
|
|
errx(1, "unknown variant %s", buf);
|
|
map |= v;
|
|
}
|
|
|
|
/* Go through all keyboards. */
|
|
v = 0;
|
|
for (i = 0; i < NUM_KBD; i++) {
|
|
(void) snprintf(device, sizeof device, "/dev/wskbd%d", i);
|
|
fd = open(device, O_WRONLY);
|
|
if (fd == -1)
|
|
fd = open(device, O_RDONLY);
|
|
if (fd == -1) {
|
|
/* remember the first error number */
|
|
if (error == 0)
|
|
error = errno;
|
|
} else {
|
|
/* at least one success, do not print error */
|
|
error = -1;
|
|
|
|
if (ioctl(fd, WSKBDIO_SETENCODING, &map) == -1) {
|
|
if (errno != EINVAL)
|
|
err(1, "WSKBDIO_SETENCODING %s",
|
|
device);
|
|
fprintf(stderr,
|
|
"%s: unsupported encoding %s on %s\n",
|
|
__progname, name, device);
|
|
} else
|
|
v++;
|
|
close(fd);
|
|
}
|
|
}
|
|
if (error > 0) {
|
|
errno = error;
|
|
err(1, "/dev/wskbd0");
|
|
}
|
|
|
|
if (verbose && v > 0)
|
|
fprintf(stderr, "kbd: keyboard mapping set to %s\n", name);
|
|
}
|