Blame src/kbdrate.c

Packit Service 50ad14
/*
Packit Service 50ad14
From: faith@cs.unc.edu (Rik Faith)
Packit Service 50ad14
Subject: User mode keyboard rate changer
Packit Service 50ad14
Date: 27 Apr 92 13:44:26 GMT
Packit Service 50ad14
Packit Service 50ad14
I put together this program, called kbdrate.c, which will reset the keyboard
Packit Service 50ad14
repeat rate and delay in user mode.  The program must have read/write
Packit Service 50ad14
access to /dev/port, so if /dev/port is only read/writeable by group port,
Packit Service 50ad14
then kbdrate must run setgid to group port (for example).
Packit Service 50ad14
Packit Service 50ad14
The "rate" is the rate in characters per second
Packit Service 50ad14
Packit Service 50ad14
The "delay" is the amount of time the key must remain depressed before it
Packit Service 50ad14
will start to repeat.
Packit Service 50ad14
Packit Service 50ad14
Usage examples:
Packit Service 50ad14
Packit Service 50ad14
kbdrate                 set rate to IBM default (10.9 cps, 250ms delay)
Packit Service 50ad14
kbdrate -r 30.0         set rate to 30 cps and delay to 250ms
Packit Service 50ad14
kbdrate -r 20.0 -s      set rate to 20 cps (delay 250ms) -- don't print message
Packit Service 50ad14
kbdrate -r 0 -d 0       set rate to 2.0 cps and delay to 250 ms
Packit Service 50ad14
Packit Service 50ad14
I find it useful to put kbdrate in my /etc/rc file so that the keyboard
Packit Service 50ad14
rate is set to something that I find comfortable at boot time.  This sure
Packit Service 50ad14
beats rebuilding the kernel!
Packit Service 50ad14
Packit Service 50ad14
Packit Service 50ad14
  kbdrate.c -- Set keyboard typematic rate (and delay)
Packit Service 50ad14
  Created: Thu Apr 23 12:24:30 1992
Packit Service 50ad14
  Author: Rickard E. Faith, faith@cs.unc.edu
Packit Service 50ad14
Packit Service 50ad14
  Copyright 1992 Rickard E. Faith.  Distributed under the GPL.
Packit Service 50ad14
  This program comes with ABSOLUTELY NO WARRANTY.
Packit Service 50ad14
  Usage: kbdrate [-r rate] [-d delay] [-s]
Packit Service 50ad14
         Rate can range from 2.0 to 30.0 (units are characters per second)
Packit Service 50ad14
         Delay can range from 250 to 1000 (units are milliseconds)
Packit Service 50ad14
         -s suppressed message
Packit Service 50ad14
  Compiles under gcc 2.1 for Linux (tested with the pre-0.96 kernel)
Packit Service 50ad14
 
Packit Service 50ad14
  Wed Jun 22 21:35:43 1994, faith@cs.unc.edu:
Packit Service 50ad14
            Changed valid_rates per suggestion by Andries.Brouwer@cwi.nl.
Packit Service 50ad14
  Wed Jun 22 22:18:29 1994, faith@cs.unc.edu:
Packit Service 50ad14
            Added patch for AUSTIN notebooks from John Bowman
Packit Service 50ad14
            (bowman@hagar.ph.utexas.edu)
Packit Service 50ad14
 
Packit Service 50ad14
  Linux/68k modifications by Roman Hodek 
Packit Service 50ad14
 				(Roman.Hodek@informatik.uni-erlangen.de):
Packit Service 50ad14
 
Packit Service 50ad14
  Reading/writing the Intel I/O ports via /dev/port is not the
Packit Service 50ad14
  English way... Such hardware dependent stuff can never work on
Packit Service 50ad14
  other architectures.
Packit Service 50ad14
  
Packit Service 50ad14
  Linux/68k has an new ioctl for setting the keyboard repeat rate
Packit Service 50ad14
  and delay. Both values are counted in msecs, the kernel will do
Packit Service 50ad14
  any rounding to values possible with the underlying hardware.
Packit Service 50ad14
 
Packit Service 50ad14
  kbdrate now first tries if the KDKBDREP ioctl is available. If it
Packit Service 50ad14
  is, it is used, else the old method is applied.
Packit Service 50ad14
Packit Service 50ad14
  1999-02-22 Arkadiusz Miƛkiewicz <misiek@misiek.eu.org>
Packit Service 50ad14
  - added Native Language Support
Packit Service 50ad14
Packit Service 50ad14
  1999-03-17
Packit Service 50ad14
  Linux/SPARC modifications by Jeffrey Connell <ankh@canuck.gen.nz>:
Packit Service 50ad14
  It seems that the KDKBDREP ioctl is not available on this platform.
Packit Service 50ad14
  However, Linux/SPARC has its own ioctl for this (since 2.1.30),
Packit Service 50ad14
  with yet another measurement system.  Thus, try for KIOCSRATE, too.
Packit Service 50ad14
Packit Service 50ad14
*/
Packit Service 50ad14
#include "config.h"
Packit Service 50ad14
Packit Service 50ad14
#include <fcntl.h>
Packit Service 50ad14
#include <stdio.h>
Packit Service 50ad14
#include <unistd.h>
Packit Service 50ad14
#include <stdlib.h>
Packit Service 50ad14
#include <errno.h>
Packit Service 50ad14
#include <sys/file.h>
Packit Service 50ad14
#include <sys/ioctl.h>
Packit Service 50ad14
#include <linux/kd.h>
Packit Service 50ad14
Packit Service 50ad14
#ifdef __sparc__
Packit Service 50ad14
#include <asm/param.h>
Packit Service 50ad14
#endif
Packit Service 50ad14
Packit Service 50ad14
#ifdef COMPAT_HEADERS
Packit Service 50ad14
#include "compat/linux-kd.h"
Packit Service 50ad14
#endif
Packit Service 50ad14
Packit Service 50ad14
/* Equal to kernel version, but field names vary. */
Packit Service 50ad14
struct my_kbd_repeat {
Packit Service 50ad14
	int delay;  /* in msec; <= 0: don't change */
Packit Service 50ad14
	int period; /* in msec; <= 0: don't change */
Packit Service 50ad14
	            /* earlier this field was misnamed "rate" */
Packit Service 50ad14
};
Packit Service 50ad14
Packit Service 50ad14
#include <signal.h>
Packit Service 50ad14
Packit Service 50ad14
#include "nls.h"
Packit Service 50ad14
#include "version.h"
Packit Service 50ad14
#include "kbd_error.h"
Packit Service 50ad14
Packit Service 50ad14
static int valid_rates[] = { 300, 267, 240, 218, 200, 185, 171, 160, 150,
Packit Service 50ad14
	                     133, 120, 109, 100, 92, 86, 80, 75, 67,
Packit Service 50ad14
	                     60, 55, 50, 46, 43, 40, 37, 33, 30, 27,
Packit Service 50ad14
	                     25, 23, 21, 20 };
Packit Service 50ad14
#define RATE_COUNT (sizeof(valid_rates) / sizeof(int))
Packit Service 50ad14
Packit Service 50ad14
static int valid_delays[] = { 250, 500, 750, 1000 };
Packit Service 50ad14
#define DELAY_COUNT (sizeof(valid_delays) / sizeof(int))
Packit Service 50ad14
Packit Service 50ad14
static int
Packit Service 50ad14
KDKBDREP_ioctl_ok(double rate, int delay, int silent)
Packit Service 50ad14
{
Packit Service 50ad14
	/*
Packit Service 50ad14
	 * This ioctl is defined in <linux/kd.h> but is not
Packit Service 50ad14
	 * implemented anywhere - must be in some m68k patches.
Packit Service 50ad14
	 * Since 2.4.9 also on i386.
Packit Service 50ad14
	 */
Packit Service 50ad14
	struct my_kbd_repeat kbdrep_s;
Packit Service 50ad14
Packit Service 50ad14
	/* don't change, just test */
Packit Service 50ad14
	kbdrep_s.period = -1;
Packit Service 50ad14
	kbdrep_s.delay  = -1;
Packit Service 50ad14
	if (ioctl(0, KDKBDREP, &kbdrep_s)) {
Packit Service 50ad14
		if (errno == EINVAL || errno == ENOTTY)
Packit Service 50ad14
			return 0;
Packit Service 50ad14
		kbd_error(EXIT_FAILURE, errno, "ioctl KDKBDREP");
Packit Service 50ad14
	}
Packit Service 50ad14
Packit Service 50ad14
#if 0
Packit Service 50ad14
	printf("old delay %d, period %d\n",
Packit Service 50ad14
	       kbdrep_s.delay, kbdrep_s.period);
Packit Service 50ad14
#endif
Packit Service 50ad14
Packit Service 50ad14
	/* do the change */
Packit Service 50ad14
	if (rate == 0) /* switch repeat off */
Packit Service 50ad14
		kbdrep_s.period = 0;
Packit Service 50ad14
	else
Packit Service 50ad14
		kbdrep_s.period = 1000.0 / rate; /* convert cps to msec */
Packit Service 50ad14
	if (kbdrep_s.period < 1)
Packit Service 50ad14
		kbdrep_s.period = 1;
Packit Service 50ad14
	kbdrep_s.delay          = delay;
Packit Service 50ad14
	if (kbdrep_s.delay < 1)
Packit Service 50ad14
		kbdrep_s.delay = 1;
Packit Service 50ad14
Packit Service 50ad14
	if (ioctl(0, KDKBDREP, &kbdrep_s)) {
Packit Service 50ad14
		kbd_error(EXIT_FAILURE, errno, "ioctl KDKBDREP");
Packit Service 50ad14
	}
Packit Service 50ad14
Packit Service 50ad14
	/* report */
Packit Service 50ad14
	if (kbdrep_s.period == 0)
Packit Service 50ad14
		rate = 0;
Packit Service 50ad14
	else
Packit Service 50ad14
		rate = 1000.0 / (double)kbdrep_s.period;
Packit Service 50ad14
Packit Service 50ad14
	if (!silent)
Packit Service 50ad14
		printf(_("Typematic Rate set to %.1f cps (delay = %d ms)\n"),
Packit Service 50ad14
		       rate, kbdrep_s.delay);
Packit Service 50ad14
Packit Service 50ad14
	kbdrep_s.period = -1;
Packit Service 50ad14
	kbdrep_s.delay  = -1;
Packit Service 50ad14
	if (ioctl(0, KDKBDREP, &kbdrep_s)) {
Packit Service 50ad14
		if (errno == EINVAL)
Packit Service 50ad14
			return 0;
Packit Service 50ad14
		kbd_error(EXIT_FAILURE, errno, "ioctl KDKBDREP");
Packit Service 50ad14
	}
Packit Service 50ad14
	printf("old delay %d, period %d\n",
Packit Service 50ad14
	       kbdrep_s.delay, kbdrep_s.period);
Packit Service 50ad14
	if (kbdrep_s.period == 0)
Packit Service 50ad14
		rate = 0;
Packit Service 50ad14
	else
Packit Service 50ad14
		rate = 1000.0 / (double)kbdrep_s.period;
Packit Service 50ad14
Packit Service 50ad14
	if (!silent)
Packit Service 50ad14
		printf(_("Typematic Rate set to %.1f cps (delay = %d ms)\n"),
Packit Service 50ad14
		       rate, kbdrep_s.delay);
Packit Service 50ad14
Packit Service 50ad14
	return 1; /* success! */
Packit Service 50ad14
}
Packit Service 50ad14
Packit Service 50ad14
#ifndef KIOCSRATE
Packit Service 50ad14
#define arg_state __attribute__((unused))
Packit Service 50ad14
#else
Packit Service 50ad14
#define arg_state
Packit Service 50ad14
#endif
Packit Service 50ad14
Packit Service 50ad14
static int
Packit Service 50ad14
KIOCSRATE_ioctl_ok(arg_state double rate, arg_state int delay, arg_state int silent)
Packit Service 50ad14
{
Packit Service 50ad14
#ifdef KIOCSRATE
Packit Service 50ad14
	struct kbd_rate kbdrate_s;
Packit Service 50ad14
	int fd;
Packit Service 50ad14
Packit Service 50ad14
	fd = open("/dev/kbd", O_RDONLY);
Packit Service 50ad14
	if (fd == -1) {
Packit Service 50ad14
		kbd_error(EXIT_FAILURE, errno, "open /dev/kbd");
Packit Service 50ad14
	}
Packit Service 50ad14
Packit Service 50ad14
	kbdrate_s.rate  = (int)(rate + 0.5); /* round up */
Packit Service 50ad14
	kbdrate_s.delay = delay * HZ / 1000; /* convert ms to Hz */
Packit Service 50ad14
	if (kbdrate_s.rate > 50)
Packit Service 50ad14
		kbdrate_s.rate = 50;
Packit Service 50ad14
Packit Service 50ad14
	if (ioctl(fd, KIOCSRATE, &kbdrate_s)) {
Packit Service 50ad14
		kbd_error(EXIT_FAILURE, errno, "ioctl KIOCSRATE");
Packit Service 50ad14
	}
Packit Service 50ad14
	close(fd);
Packit Service 50ad14
Packit Service 50ad14
	if (!silent)
Packit Service 50ad14
		printf("Typematic Rate set to %d cps (delay = %d ms)\n",
Packit Service 50ad14
		       kbdrate_s.rate, kbdrate_s.delay * 1000 / HZ);
Packit Service 50ad14
Packit Service 50ad14
	return 1;
Packit Service 50ad14
#else  /* no KIOCSRATE */
Packit Service 50ad14
	return 0;
Packit Service 50ad14
#endif /* KIOCSRATE */
Packit Service 50ad14
}
Packit Service 50ad14
Packit Service 50ad14
static void
Packit Service 50ad14
sigalrmhandler(int sig __attribute__((unused)))
Packit Service 50ad14
{
Packit Service 50ad14
	kbd_warning(0, "Failed waiting for kbd controller!\n");
Packit Service 50ad14
	raise(SIGINT);
Packit Service 50ad14
}
Packit Service 50ad14
Packit Service 50ad14
int main(int argc, char **argv)
Packit Service 50ad14
{
Packit Service 50ad14
#ifdef __sparc__
Packit Service 50ad14
	double rate = 5.0; /* Default rate */
Packit Service 50ad14
	int delay   = 200; /* Default delay */
Packit Service 50ad14
#else
Packit Service 50ad14
	double rate = 10.9; /* Default rate */
Packit Service 50ad14
	int delay   = 250; /* Default delay */
Packit Service 50ad14
#endif
Packit Service 50ad14
	int value = 0x7f; /* Maximum delay with slowest rate */
Packit Service 50ad14
	                  /* DO NOT CHANGE this value */
Packit Service 50ad14
	int silent = 0;
Packit Service 50ad14
	int fd;
Packit Service 50ad14
	char data;
Packit Service 50ad14
	int c;
Packit Service 50ad14
	unsigned int i;
Packit Service 50ad14
	extern char *optarg;
Packit Service 50ad14
Packit Service 50ad14
	set_progname(argv[0]);
Packit Service 50ad14
Packit Service 50ad14
	setlocale(LC_ALL, "");
Packit Service 50ad14
	bindtextdomain(PACKAGE_NAME, LOCALEDIR);
Packit Service 50ad14
	textdomain(PACKAGE_NAME);
Packit Service 50ad14
Packit Service 50ad14
	if (argc == 2 &&
Packit Service 50ad14
	    (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version")))
Packit Service 50ad14
		print_version_and_exit();
Packit Service 50ad14
Packit Service 50ad14
	while ((c = getopt(argc, argv, "r:d:s")) != EOF) {
Packit Service 50ad14
		switch (c) {
Packit Service 50ad14
			case 'r':
Packit Service 50ad14
				rate = atof(optarg);
Packit Service 50ad14
				break;
Packit Service 50ad14
			case 'd':
Packit Service 50ad14
				delay = atoi(optarg);
Packit Service 50ad14
				break;
Packit Service 50ad14
			case 's':
Packit Service 50ad14
				silent = 1;
Packit Service 50ad14
				break;
Packit Service 50ad14
			default:
Packit Service 50ad14
				fprintf(stderr,
Packit Service 50ad14
				        _("Usage: kbdrate [-V | --version] [-s] [-r rate] [-d delay]\n"));
Packit Service 50ad14
				exit(EXIT_FAILURE);
Packit Service 50ad14
		}
Packit Service 50ad14
	}
Packit Service 50ad14
Packit Service 50ad14
	if (KDKBDREP_ioctl_ok(rate, delay, silent)) /* m68k? */
Packit Service 50ad14
		return 0;
Packit Service 50ad14
Packit Service 50ad14
	if (KIOCSRATE_ioctl_ok(rate, delay, silent)) /* sparc? */
Packit Service 50ad14
		return 0;
Packit Service 50ad14
Packit Service 50ad14
	/* The ioport way */
Packit Service 50ad14
Packit Service 50ad14
	for (i = 0; i < RATE_COUNT; i++)
Packit Service 50ad14
		if (rate * 10 >= valid_rates[i]) {
Packit Service 50ad14
			value &= 0x60;
Packit Service 50ad14
			value |= i;
Packit Service 50ad14
			break;
Packit Service 50ad14
		}
Packit Service 50ad14
Packit Service 50ad14
	for (i = 0; i < DELAY_COUNT; i++)
Packit Service 50ad14
		if (delay <= valid_delays[i]) {
Packit Service 50ad14
			value &= 0x1f;
Packit Service 50ad14
			value |= i << 5;
Packit Service 50ad14
			break;
Packit Service 50ad14
		}
Packit Service 50ad14
Packit Service 50ad14
	if ((fd = open("/dev/port", O_RDWR)) < 0) {
Packit Service 50ad14
		kbd_error(EXIT_FAILURE, errno, _("Cannot open /dev/port"));
Packit Service 50ad14
	}
Packit Service 50ad14
Packit Service 50ad14
	signal(SIGALRM, sigalrmhandler);
Packit Service 50ad14
	alarm(3);
Packit Service 50ad14
Packit Service 50ad14
	do {
Packit Service 50ad14
		lseek(fd, 0x64, 0);
Packit Service 50ad14
		if (read(fd, &data, 1) == -1) {
Packit Service 50ad14
			kbd_error(EXIT_FAILURE, errno, "read");
Packit Service 50ad14
		}
Packit Service 50ad14
	} while ((data & 2) == 2); /* wait */
Packit Service 50ad14
Packit Service 50ad14
	lseek(fd, 0x60, 0);
Packit Service 50ad14
	data = 0xf3; /* set typematic rate */
Packit Service 50ad14
	if (write(fd, &data, 1) == -1) {
Packit Service 50ad14
		kbd_error(EXIT_FAILURE, errno, "write");
Packit Service 50ad14
	}
Packit Service 50ad14
Packit Service 50ad14
	do {
Packit Service 50ad14
		lseek(fd, 0x64, 0);
Packit Service 50ad14
		if (read(fd, &data, 1) == -1) {
Packit Service 50ad14
			kbd_error(EXIT_FAILURE, errno, "read");
Packit Service 50ad14
		}
Packit Service 50ad14
	} while ((data & 2) == 2); /* wait */
Packit Service 50ad14
Packit Service 50ad14
	alarm(0);
Packit Service 50ad14
Packit Service 50ad14
	lseek(fd, 0x60, 0);
Packit Service 50ad14
	sleep(1);
Packit Service 50ad14
	if (write(fd, &value, 1) == -1) {
Packit Service 50ad14
		kbd_error(EXIT_FAILURE, errno, "write");
Packit Service 50ad14
	}
Packit Service 50ad14
Packit Service 50ad14
	close(fd);
Packit Service 50ad14
Packit Service 50ad14
	if (!silent)
Packit Service 50ad14
		printf(_("Typematic Rate set to %.1f cps (delay = %d ms)\n"),
Packit Service 50ad14
		       valid_rates[value & 0x1f] / 10.0,
Packit Service 50ad14
		       valid_delays[(value & 0x60) >> 5]);
Packit Service 50ad14
Packit Service 50ad14
	return EXIT_SUCCESS;
Packit Service 50ad14
}