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;
}
Comments:

Post a Comment:
Comments are closed for this entry.
About

user12614486

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today