What's coming in kernel v4.16 for rc-core

In kernel v4.16 there are more changes than usual for rc-core.

lirc_zilog

First of all, the last remaining staging lirc driver has been ported to rc-core: lirc_zilog. The old driver needed a “signal database”, a file with specific IR messages in it. So to make it work, you needed a file haup-ir-blaster.bin and lirc_zilog.conf and then needed to know the specific name of the IR message you wanted to send.

The new driver is in ir-i2c-kbd.c. The transmitter now works like other IR devices, in that it can send raw IR (i.e. just pulse and space). The old signal database files haup-ir-blaster.bin and lirc_zilog.conf are no longer needed and not supported either.

This driver is for the Hauppauge PVR-150, HVR-1600, USB PVR2 and HD-PVR IR interface.

End of lirc staging and lirc_dev.h

With lirc_zilog gone, the entire staging lirc directory is gone, and the lirc kernel api is gone too. This means that no out of tree lirc drivers will compile any more.

Just to be clear, this makes no difference to userspace.

This means that lirc_rpi no longer works. For the Raspbery Pi, there is the gpio-ir-recv, gpio-ir-tx (or pwm-ir-tx) to replace this driver. Those drivers are generic and much shorter than lirc_rpi.

Not having the lirc kernel api made it possible to clean up much of the kernel code. The lirc userspace api (see lirc_dev.c) is much cleaner than what we used to have (lirc_dev.c and ir-lirc-decoder.c).

Lirc scancode interface

One feature I have been working towards for some time is the new lirc scancode interface. This makes it possible to do two new things.

First of all, we’ve had in-kernel IR encoders for some time. They were only used for the nuvoton wakeup IR programming. Now, it is possible to send IR by specifying the protocol and the scancode required. There is no need for keymaps or anything complicated.

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
int tx_scancode(unsigned scancode)
{
int fd, mode;
struct lirc_scancode sc = {
.rc_proto = RC_PROTO_RC5,
.scancode = scancode
};

fd = open("/dev/lirc0", O_RDWR);
if (fd == -1) {
printf("Failed to open /dev/lirc\n");
return -1;
}
mode = LIRC_MODE_SCANCODE;
if (ioctl(fd, LIRC_SET_SEND_MODE, &mode)) {
printf("kernel too old or device cannot send scancodes\n");
return -1;
}
if (write(fd, &sc, sizeof(sc)) < 0) {
printf("invalid scancode or failed to transmit\n");
return -1;
}
close(fd);
return 0;
}

Secondly, rather than transmitting scancodes, it is also possible to receive scancodes with complete protocol information. This is really useful for use-case of “what protocol is my remote using?”.

Both features can be used using v4l-utils from git, or v1.14 when it is released. To find out what IR protocol your remote is using, you can use ir-keytable -t. Ensure you have all protocols enabled (-p all) and (-c) to safe-guard from any scancode mapping to e.g. power-off.

1
2
3
4
5
6
7
8
9
10
$ ir-keytable -c -p all -t
Old keytable cleared
Protocols changed to lirc rc-5 rc-5-sz jvc sony nec sanyo mce_kbd rc-6 sharp xmp
Testing events. Please, press CTRL-C to abort.
2124.576099: lirc protocol(rc5): scancode = 0x1e11
2124.576143: event type EV_MSC(0x04): scancode = 0x1e11
2124.576143: event type EV_SYN(0x00).
2125.601002: lirc protocol(rc6_mce): scancode = 0x800f0410
2125.601051: event type EV_MSC(0x04): scancode = 0x800f0410
2125.601051: event type EV_SYN(0x00).

Note the rc5 and rc6_mce protocol names. This is two different remotes, a Hauppauge rc-5 remote and Microsoft MCE remote. Again, This requires a recent v4l-utils.

Opening /dev/lirc more than once

If you happen to run the lirc daemon, then the /dev/lirc device was always in use since the lirc daemon would hold it open. This is no longer a problem, now a /dev/lirc device can be opened as many times as needed, and every process that opens it will get a copy of the IR received. This actually saves some memory if no process has a /dev/lirc device open, as there are no buffers allocated (they are per-fd now).