Kjetil's Information Center: A Blog About My Projects

XP MCE Keyboard on Raspberry Pi Zero W

I have an old Remote Keyboard for Windows XP Media Center Edition which I have managed to "connect" to a Raspberry Pi Zero W through IR.

To get a IR functionality on the Pi, I followed these instructions and bought a Vishay TSOP38238 IR Receiver. This can be connected (or in my case soldered) directly to the GPIO header of the Pi.

|----------------|---------|---------------|
|                | TSOP    | Raspberry Pi  | 
| Name           | 38238   | Zero W Header |
|----------------|---|-----|----|----------|
| Signal Data    | 1 | OUT | 8  | GPIO14   |
| Ground         | 2 | GND | 6  | Ground   |
| Supply Voltage | 3 | VS  | 1  | 3V3      |
|----------------|---|-----|----|----------|
          


IR Receiver on Raspberry Pi Zero W


To enable the GPIO pin 14 as IR the following must be set in /boot/config.txt on the Pi:

dtoverlay=gpio-ir,gpio_pin=14
          


To be able to configure the IR related mappings in the Linux kernel, the "ir-keytable" program must be installed:

sudo apt-get install ir-keytable
          


This XP MCE keyboard uses both the RC-6 protocol for multimedia buttons and a custom protocol of the regular keys, to enable both add this to /etc/rc.local on the Pi:

ir-keytable -p rc-6 -p mce_kbd
          


Now, this should have been enough to get it working, but in my case it didn't. I suspect there might be a bug/mismatch in either the Linux kernel itself or with the ir-keytable program. At the time of writing, the Pi is running kernel version 5.10.17+ and ir-keytable version 1.16.3. The problem I observed is that most of the keys on the keyboard does not send a EV_KEY event when monitoring with the "evtest" program, which in turn causes the key to not really work at all. After some debugging and troubleshooting I discovered that the affected keys are missing from the keybit[] array in the input_dev structure for the driver.

My solution to this is to patch the Linux kernel with a custom "ir-mce_kbd-decoder.ko" kernel module. To build this you will of course need the relevant Linux kernel sources for the Pi. Using this script and instructions seems to be the easiest way. The specific kernel version downloaded in my case was commit 3a33f11c48572b9dd0fecac164b3990fc9234da8.

Here is one way to build that single kernel module, assuming you have the kernel sources and the build tools installed:

mkdir ir-mce_kbd-decoder
cd ir-mce_kbd-decoder/
cp /home/pi/linux-3a33f11c48572b9dd0fecac164b3990fc9234da8/drivers/media/rc/ir-mce_kbd-decoder.c .
cp /home/pi/linux-3a33f11c48572b9dd0fecac164b3990fc9234da8/drivers/media/rc/rc-core-priv.h .
echo "obj-m := ir-mce_kbd-decoder.o" > Makefile
make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
          


The ir-mce_kbd-decoder.c file needs to be patched with the following to set those missing bits in the keybit[] array:

--- ir-mce_kbd-decoder.orig     2021-10-17 12:28:27.991142273 +0200
+++ ir-mce_kbd-decoder.c        2021-10-17 13:18:46.908921902 +0200
@@ -360,11 +360,20 @@

 static int ir_mce_kbd_register(struct rc_dev *dev)
 {
+       int i;
        struct mce_kbd_dec *mce_kbd = &dev->raw->mce_kbd;

        timer_setup(&mce_kbd->rx_timeout, mce_kbd_rx_timeout, 0);
        spin_lock_init(&mce_kbd->keylock);

+       for (i = 0; i < 256; i++) {
+               if (kbd_keycodes[i] != KEY_RESERVED) {
+                       __set_bit(kbd_keycodes[i], dev->input_dev->keybit);
+               }
+       }
+       __set_bit(BTN_LEFT, dev->input_dev->keybit);
+       __set_bit(BTN_RIGHT, dev->input_dev->keybit);
+
        return 0;
 }
          


To load the new module temporarily for test, use the following commands:

sudo modprobe -r ir-mce_kbd-decoder
sudo insmod ir-mce_kbd-decoder.ko
sudo ir-keytable -p rc-6 -p mce_kbd
          

If it works fine, the module may be copied (and overwritten) to /usr/lib/modules/5.10.17+/kernel/drivers/media/rc/ir-mce_kbd-decoder.ko

Topic: Configuration, by Kjetil @ 23/10-2021, Article Link