[BACK]Return to kbd_wscons.c CVS log [TXT][DIR] Up to [local] / src / sbin / kbd

File: [local] / src / sbin / kbd / kbd_wscons.c (download)

Revision 1.36, Thu May 5 16:12:42 2022 UTC (2 years ago) by bluhm
Branch: MAIN
CVS Tags: OPENBSD_7_5_BASE, OPENBSD_7_5, OPENBSD_7_4_BASE, OPENBSD_7_4, OPENBSD_7_3_BASE, OPENBSD_7_3, OPENBSD_7_2_BASE, OPENBSD_7_2, HEAD
Changes since 1.35: +22 -12 lines

Add error handling if setting the keyboard encoding fails.  After
open of all /dev/wskbd* devices failed, report the error from the
first one.  Also wrap long lines.
OK mpi@

/*	$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);
}