Friday June 30, 2006 Dell USB keyboard volume keys hack
If you have a Dell SK-8125 keyboard (101-key, black, built in 2-port hub, with a silver band at the top and 8 silver application keys, the right three of which are Volume Up/Down/Mute), this hack might interest you.
It turns out Solaris attaches a hid driver instance to the special "consumer control" device that makes up the 8 multimedia keys, but there's no client driver module that interprets the data, and in fact if no one opens that hid device, the data isn't ever generated.
But if you *do* open it, it turns out reading the keys is easy...and since /dev/audioctl is also an easy way to do volume, the following silly userland program has me using volume keys, when I run it as dellusb /dev/usb/hid2.
Maybe if you have a similar keyboard, you can hack it, so I've left the debug dump. This Dell sends 4 bytes for make and break, and doesn't seem to change anything but the second byte, which is a bitmask of keys pressed... pretty easy.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/audio.h>
#define VOLDOWN 128
#define VOLUP 64
#define MUTE 32
#define HOME 16
#define RELOAD 8
#define CANCEL 4
#define FORWARD 2
#define BACK 1
void volevent(unsigned char mask);
void dump_event(unsigned char mask);
int
main(int argc, char **argv)
{
int fd;
char errmsg[80];
unsigned char kbuf[4];
unsigned char mask;
if (argc < 2) {
fprintf(stderr, "usage: dellusb <hid-device>\n");
exit(1);
}
if ((fd = open(argv[1], O_RDONLY)) < 0) {
sprintf(errmsg, "open %s", argv[1]);
perror(errmsg);
exit(1);
}
while (1) {
read(fd, kbuf, sizeof(kbuf));
mask = kbuf[1];
if (!mask)
continue;
#if 0
dump_event(mask);
#else
if (mask & (VOLUP | VOLDOWN | MUTE))
volevent(mask);
#endif
}
}
void
volevent(unsigned char mask)
{
struct audio_info i;
static uint_t gain_at_mute = 0;
int fd;
/* get audio info, no matter what we have to do */
if ((fd = open("/dev/audioctl", O_RDWR)) < 0) {
perror("open /dev/audioctl");
return;
}
ioctl(fd, AUDIO_GETINFO, &i);
switch (mask & (VOLUP | VOLDOWN | MUTE)) {
case VOLUP:
i.play.gain += 5;
if (i.play.gain > AUDIO_MAX_GAIN)
i.play.gain = AUDIO_MAX_GAIN;
break;
case VOLDOWN:
/* gain is a uint_t, requiring this silly dance */
if (i.play.gain <= 5)
i.play.gain = 0;
else
i.play.gain -= 5;
break;
case MUTE:
if (gain_at_mute) {
i.play.gain = gain_at_mute;
gain_at_mute = 0;
} else {
gain_at_mute = i.play.gain;
i.play.gain = 0;
}
break;
default:
goto out;
}
ioctl(fd, AUDIO_SETINFO, &i);
out:
close(fd);
return;
}
void
dump_event(unsigned char mask)
{
if (mask & VOLDOWN) printf("VOLDOWN ");
if (mask & VOLUP) printf("VOLUP ");
if (mask & MUTE) printf("MUTE ");
if (mask & HOME) printf("HOME ");
if (mask & RELOAD) printf("RELOAD ");
if (mask & CANCEL) printf("CANCEL ");
if (mask & FORWARD) printf("FORWARD ");
if (mask & BACK) printf("BACK ");
if (mask) printf("\n");
return;
}
( Jun 30 2006, 06:50:35 PM PDT )
Permalink