/* kbd_cmd.c - aeb, 940505 */
/*
* This program must have write permission to /dev/port - probably that
* means that it has to be suid root.
*
* Without arguments: enable keyboard.
*
* With a single argument "sane": enable keyboard and set default scancodes.
*
* [These are useful commands, but when the keyboard is in some obscure
* state they probably cannot be typed. Under X you can have them as a
* menu item. Otherwise you might use "sleep 300; kbd_cmd sane" before
* doing something dangerous, like playing with this program.]
*
* With a sequence of two-character hexadecimal values or symbolic commands:
* send these values to the keyboard.
* An argument W or w means wait.
*
* e.g., "kbd_cmd LED 7" will set the LEDs behind the kernel's back -
* use the program "setleds" if you want the lights to mean anything.
*
* "kbd_cmd f0 1; showkey -s; kbd_cmd f0 2" will enable you to study the
* scancodes produced in a different scancode mode.
*
* "kbd_cmd W f0 1 f0 0 W f0 2 & showkey -s" will enable you to find the
* identifications of the various scancode sets, and similarly
* "kbd_cmd W f2 & showkey -s" yields the keyboard identification.
*
* Playing with these things is dangerous! It is very easy to get into a
* state in which the keyboard cannot be used anymore. Set up an escape
* (as suggested above).
* These commands work on my keyboard. For other keyboards the results
* may be unpredictible.
*/
#include stdio.h
#include stdlib.h
#include sys/file.h
struct {
unsigned char cmd;
int argct, resct;
char *name;
} commands[] = {
0xed, 1, 0, "LED", /* arg 0-7: 1 ScrollLock, 2 NumLock, 4 CapsLock */
0xee, 0, 1, "echo", /* result: ee */
0xf0, 1, 1, "get_scancodes", /* arg: 0, result: 43, 41 or 3f */
0xf0, 1, 0, "set_scancodes", /* arg: 1-3 */
0xf2, 0, 2, "identify_keyboard", /* result: ab 41 */
0xf3, 1, 0, "set_repeat_rate",
0xf4, 0, 0, "enable",
0xf5, 0, 0, "reset_and_disable",
0xf6, 0, 0, "reset_and_enable",
0xfe, 0, 1, "resend",
0xff, 0, 1, "reset_and_selftest" /* result: aa (OK) / fc (error) */
};
int fd;
int args_expected;
send_cmd(unsigned char x) {
char z;
int i;
do {
lseek( fd, 0x64, 0 );
read( fd, &z, 1 );
} while ((z & 2) == 2 ); /* wait */
lseek( fd, 0x60, 0 );
write( fd, &x, 1 );
if (args_expected)
args_expected--;
else {
for(i=0; i<sizeof(commands)/sizeof(commands[0]); i++)
if(x == commands[i].cmd) {
args_expected = commands[i].argct;
break;
}
}
}
int hexd(char c) {
if ('0' <= c && c <= '9') return(c - '0');
if ('a' <= c && c <= 'f') return(c - 'a' + 10);
if ('A' <= c && c <= 'F') return(c - 'A' + 10);
fprintf(stderr, "kbd_cmd: expected a hex digit, got _%c_ (0%o)\n", c);
leave(1);
}
unsigned char tohex(char *s) {
if(!s[0])
return(0);
else if(!s[1])
return(hexd(s[0]));
else
return((hexd(s[0])<<4) + hexd(s[1]));
}
void main(int argc, char **argv) {
int i, j;
if ( (fd = open("/dev/port", O_RDWR)) < 0) {
perror("Cannot open /dev/port");
exit(1);
}
if (argc < 2) {
send_cmd(0xf4); /* enable */
} else if (argc == 2 && !strcmp(argv[1], "sane")) {
send_cmd(0); /* Just in case the kbd was waiting */
/* for the second byte of a command */
send_cmd(0xf0); /* Select scancode set */
send_cmd(0x02); /* set 2 */
send_cmd(0xf4); /* Enable keyboard */
} else for (i=1; i<argc; i++) {
if (!strcmp(argv[i], "W") || !strcmp(argv[i], "w")) {
sleep(1);
} else if (strlen(argv[i]) > 2) {
for (j=0; j < sizeof(commands)/sizeof(commands[0]); j++)
if(!strcmp(commands[j].name, argv[i])) {
send_cmd(commands[j].cmd);
goto fnd;
}
fprintf(stderr, "kbd_cmd: unrecognized command %s\n", argv[i]);
leave(1);
fnd:;
} else
send_cmd(tohex(argv[i]));
}
leave(0);
}
leave(int n) {
/* prevent frozen keyboards, waiting for command arguments */
while(args_expected)
send_cmd(0);
exit(n);
}
Copyright © 1994 - 2019 Linux Journal. All rights reserved.