Resurrecting The Griffin PowerMate on Linux

I own both a Griffin PowerMate and a Shuttle Xpress: these are both USB input devices that are old enough to qualify as tech antiques. But the PowerMate at least is worth working on: it's essentially a beautifully made USB volume knob. That's it. Sometimes simplicity is good. It used to have a Linux driver, but no more. The Shuttle Xpress never had a driver at all, and so has collected dust for a decade. How do you get them to do anything useful? This was the question that drove me to really dig into udev rules in my previous blog entry. Please read that before tackling this one.

The tools I ended up using to identify and make these work are similar but slightly different from those used previously. I was looking at block devices (storage) yesterday, I'm now looking at input devices (keyboards, mice, and ... these things).

When the PowerMate is plugged in, you can find it by numerous methods. dmesg:

[2291635.687395] usb 1-1.4: new low-speed USB device number 80 using xhci_hcd
[2291635.807116] usb 1-1.4: New USB device found, idVendor=077d, idProduct=0410, bcdDevice= 4.00
[2291635.807131] usb 1-1.4: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[2291635.807136] usb 1-1.4: Product: Griffin PowerMate
[2291635.807189] usb 1-1.4: Manufacturer: Griffin Technology, Inc.
[2291635.817402] input: Griffin PowerMate as /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1.4/1-1.4:1.0/input/input52

lsusb:

Bus 001 Device 080: ID 077d:0410 Griffin Technology PowerMate

cat /proc/bus/input/devices:

I: Bus=0003 Vendor=077d Product=0410 Version=0400
N: Name="Griffin PowerMate"
P: Phys=usb-0000:00:14.0-1.4/input0
S: Sysfs=/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1.4/1-1.4:1.0/input/input52
U: Uniq=
H: Handlers=event17
B: PROP=0
B: EV=17
B: KEY=1 0 0 0 0
B: REL=80
B: MSC=2

This last has something very useful that I don't think can be found elsewhere, namely the Sysfs path for the device. To learn more about the device, we use that value and run udevadm info -ap /devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1.4/1-1.4:1.0/input/input52 - this generates 294 lines of output so I won't paste it here, but from that collection I found these two:

ATTR{id/product}=="0410"
ATTR{id/vendor}=="077d"

Again: read the previous entry for warnings about how you need to test these attributes, carefully and often. In this case, these turned out to be the "correct" attributes, because this udev rule worked:

SUBSYSTEMS=="input" \
, ACTION=="add" \
, ATTR{id/vendor}=="077d" \
, ATTR{id/product}=="0410" \
, NAME="input/powermate" \
, RUN+="/usr/local/bin/udevlogger 'PowerMate found'"

This relies on the /usr/local/bin/udevlogger script in the previous entry.

This is, of itself, not too useful: we've identified the device and logged when it's connected to the system. But there's no current driver for the PowerMate, so it's still not very useful.

We can test it with the evtest command (on Debian, install the "evtest" package). Just point the command at the device link: /usr/bin/evtest /dev/input/by-id/usb-Griffin_Technology__Inc._Griffin_PowerMate-event-if00. The initial output looks like this:

Input driver version is 1.0.1
Input device ID: bus 0x3 vendor 0x77d product 0x410 version 0x400
Input device name: "Griffin PowerMate"
Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 256 (BTN_0)
  Event type 2 (EV_REL)
    Event code 7 (REL_DIAL)
  Event type 4 (EV_MSC)
    Event code 1 (MSC_PULSELED)
Properties:
Testing ... (interrupt to exit)

But the interesting part happens when you start twisting the knob or clicking the top:

Event: time 1699585314.188129, type 2 (EV_REL), code 7 (REL_DIAL), value -1
Event: time 1699585314.188129, -------------- SYN_REPORT ------------
Event: time 1699585314.548214, type 2 (EV_REL), code 7 (REL_DIAL), value 1
Event: time 1699585314.548214, -------------- SYN_REPORT ------------
Event: time 1699585316.188087, type 1 (EV_KEY), code 256 (BTN_0), value 1
Event: time 1699585316.188087, -------------- SYN_REPORT ------------
Event: time 1699585316.372273, type 1 (EV_KEY), code 256 (BTN_0), value 0
Event: time 1699585316.372273, -------------- SYN_REPORT ------------

Which is all grand: we've proved the device is issuing commands that are available to the system. But without a valid driver for the device, it's not very useful! I didn't know where to go with it.

Enter m0aws, with a simple, ghetto, yet brilliant script idea:

#!/bin/bash
# https://m0aws.co.uk/?p=2201 (GO: 2023-11-08)
devName="/dev/input/by-id/usb-Griffin_Technology__Inc._Griffin_PowerMate-event-if00"
/usr/bin/evtest ${devName} | while read LINE
do
    case $LINE in
        *"(REL_DIAL), value 1") echo "clock" ;;
        *"(REL_DIAL), value -1") echo "counter" ;;
        *"(BTN_0), value 1") echo "click" ;;
    esac
done

I've massively stripped down his script. It never occurred to me to simply read the output of the test command. Simple and brilliant. Why do I say "ghetto?" Because this is effectively the same as screen-scraping: if the output of evtest changes, it can break this script. And if input comes in too fast, Bash may not keep up. There are problems. But you know what? I think it's fantastic because I'm not limited by the choices of whoever wrote a driver for the PowerMate who thought (for example) the only possible thing I could want to do with it was activate the XF86VolumeUp key when the knob was turned. This script allows me to run a command: mpc volume +1 which adjusts the volume on my MPD server.

The adjustment is incredibly easy:

#!/bin/bash
# https://m0aws.co.uk/?p=2201 (GO: 2023-11-08)
devName="/dev/input/by-id/usb-Griffin_Technology__Inc._Griffin_PowerMate-event-if00"
export MPD_HOST="pi44v3.local"
/usr/bin/evtest ${devName} | while read LINE
do
    case $LINE in
        *"(REL_DIAL), value 1") mpc volume -1 ;;
        *"(REL_DIAL), value -1") mpc volume +1 ;;
        *"(BTN_0), value 1") mpc toggle ;;
    esac
done

And like that, the Griffin connected to my desktop controls my MPD server (on a separate Raspberry Pi).

Ideally, this script would be started by the udev rule(s) when the PowerMate is plugged in, and stopped by another rule when the PowerMate is removed. That's a project for another day.

The Shuttle Xpress has more buttons and knobs. I'm still in the process of mapping them to functions, but it works well too - even though a driver was never available for it!