There seems to be a lot of confusion about how Linux deals with IR receivers and remotes. Many people simply can't get anything to work at all, some are having problems with their remotes sending events twice and others can't get every button to work or get them mapped to XBMC the way they want it.

That's why I decided to try to write this guide to try and take away at least some confusion by outlining the options you have to get your remote to work. I will also to the best of my ability try to explain the procedure to get everything to work the way you want it, but I won't go into too much detail. So if you want or have to compile some silly (source wrapped) proprietary driver to get your receiver to work (e.g. nuvoton) or want to compile a newer version of LIRC or a custom kernel, you're on your own. I consider that to be outside the scope of this guide. I just want to sketch the landscape.

I also would like to make clear that, although I am pretty well versed in Linux, I am by no means an expert with regard to remotes or LIRC. So if I make any mistakes feel free to correct me. I will do my best to keep this guide as accurate as possible. Due to my proficiency with Linux I may get ahead of some of you, so please stop me if I do. Do note, however that this is not a tutorial. It's not a sequences of steps or commands that you have execute and all is well. I think that may work very well for particular configurations such as those Asrocks that come with only one type of receiver and one type of remote. But this more of a guide that attempts to be as generic as possible. I'm trying to make you understand how things work, so you should be able to get any configuration working.

Introduction

I think a big part of this confusion is caused by the migration of LIRC functionality to the Linux kernel (drivers). This change started in 2.6.33 with the inclusion of the ir-core module in the mainline kernel. Many older guides currently on the internet have of course not taken this into account, which is why those traditional guides won't work too well. Hence, a 'new' guide.

Somebody has written a good article about this change. Note that even though he talks about 2.6.35, the change started in 2.6.33. The author is simply talking about iMon specifically, which was indeed included in 2.6.35. This means that from 2.6.33 and onward you are risking conflicts between the new kernel interface and lirc. However, the fact that the core has been included does not mean it works for all devices, but it does mean potential conflicts start there. The 'new' drivers have been included in the following versions:

So it depends on your Linux version and IR receiver whether you can follow my guide. Here the overview:
<=2.6.32 all receivers: you can NOT follow this guide, but there will also be no conflicts. Just use a lirc tutorial and you'll be fine
>=2.6.33 all combinations (or better) not (white)listed above: you can NOT follow this guide, because your receiver is not supported (yet). However, there can be conflicts, so disable the new interface by blacklisting all ir-* and rc-* modules. Then you can just use lirc regularly. Or if you can download, compile and install the drivers separately for your kernel, you can of course follow this guide.
All other cases: you can choose to follow my guide OR use the lirc bridge (>=2.6.36) (see section 2.1 in post #2) or do rc-* ir-* mceusb/imon/in-kernel-driver-for-your-receiver blacklisting to just use lirc.

You can find out which version you are running by executing

Code:

uname -r

Note: Ubuntu "Lucid" 10.04 LTS runs 2.6.32 or 2.6.35 (both are included in the official APT repository), so it falls into the first (2.6.32) or second (2.6.35) category, except if you have an iMON receiver. Why you would want to run Lucid on a bleeding edge multimedia system such as an HTPC is beyond me, but I thought I should explicitly mention Lucid a lot of people still run it.

Executive Summary

After reading this guide I hope you are able to:

understand how IR signals are processed by Linux;

emulate a keyboard with your remote;

map almost every button on your remote to the appropriate key press or media centre event; or

assign various actions to the same button on your remote in XBMC, depending on the context

Anyway, to the guide it is.

The guide

There are roughly three stages that all have to worked out to get a seamless experience. Depending on your hardware, software, configuration and certain choices you make, these stage may require anything from almost no configuration to a lot of compiling and configuring.

0. Table of Contents

IR receiver (post #1)

The remote (posts #2 and #3)

Mapping buttons to XBMC (post #4)

Since the posts are restricted to 10000 chars, this will be a three part guide, corresponding to the abovementioned list. Stage 1 will be included in this post and stage 2 and 3 will get their own posts.

1. IR Receiver
The focus will be on the second and third stage, since the first stage isn't radically different from what it used to be in the past. Like with any device it's about finding the right driver (kernel module), optionally compiling it and installing and using it. It's the way it's always been. Like I said, if you want to know about DKMS or something have a look at DKMS guide or tutorial and then come back here. So that I'm not going to pay too much attention to right now.

All I can do if that if you are still planning to buy an IR receiver, make sure it is compatible with Linux out-of-the-box, meaning that the driver should be included in the vanilla Linux kernel. This will make life a lot easier for you.

Just so you know, my receiver worked out of the box. I hand picked it .

Anyway, this is nothing new. Like I said it's something you may have to do for every device: look if it works by default, if not, search for and install the appropriate driver(s).

What has changed is the testing procedure. Many traditional guides will start by using

Code:

irw

to verify if your receiver can receive IR signals and thus if the driver works well. This however, is no longer a reliable method, due to the changes in Linux 2.6.33 and onward. I will get back to this in stage two, but for the purpose of simply testing your IR receiver, stop lirc and execute

Code:

ir-keytable -c -p NEC,RC-5,RC-6,JVC,SONY -t

It should be generating events now. I will dissect this command and its output in section 2.2, but for now it suffices to see if it works at all. Remember, this is just about the receiver. If you don't have this command, install the package that provides it. In Ubuntu this is ir-keytable, but I think it varies per distribution.

Also try all your other remotes if it didn't work: from your TV, DVD, BR, Xbox, A/V receiver and your dog. Some remotes simply are not compatible, but one of them definitely will be.

If all of this has failed, it's pretty safe to say your driver probably hasn't been installed correctly. Go back to start and do not receive €20000.

So you have established that the receiver works. Now you have to have software that receives and interprets those IR signals. In the past, there was only LIRC. But as of Linux 2.6.36, functionality is being moved into the kernel (Kernel Newbies).

While this can potentially be very useful, it does seem to be at the root of the confusion of many people. This is perfectly understandable, as official documentation is very sparse.

The problem seems to be that the kernel now 'catches' all the events and does not let them through to LIRC. And sometimes LIRC also seems to get in the way of the kernel, especially when you've already configured lirc.

So basically LIRC and the in-kernel drivers interfere with each other. Note that I'm using LIRC 0.8.7 (Ubuntu Natty default) and according to the LIRC FAQ you need 0.9.0 with in-kernel drivers. So upgrading will most likely solve this problem, but if you don't feel like upgrading LIRC you can also do what I said before, which was to disable lirc entirely or let the kernel pass through all commands to LIRC.

I think it would also be possible to simply disable the kernel drivers by blacklisting all ir-* and rc-* modules, but I see no reason to do that instead of using passthrough.

In short, there seem to be three possible 'paths' that an incoming IR signal can go through:

Let the kernel pass the signal through to LIRC

Do everything completely in-kernel

Let the kernel cooperate with LIRC

2.1 Let the kernel pass the signal through to LIRC
The first one will allow you to follow the traditional LIRC guides. All you have to do is execute

Code:

modprobe ir-lirc-codec
ir-keytable -p LIRC

You can add 'ir-lirc-codec' to /etc/modules and the ir-keytable command to /etc/rc.local (or equivalent) if you want to make it persistent.

This should allow irw to function as it has always done, so you can now use hardware.conf, lircd.conf and irrecord as described in the traditional lirc howtos.

If you choose this path, you probably won't be able to emulate keypresses and assign different actions to the same button (I think). You will have to use Lircmap.xml instead of keyboard.xml and the latter looks much more versatile (at least the vanilla ones).

So then the guide stops here and I suggest you follow a good guide about LIRC. I do however, recommend you to switch to the kernel drivers.

2.2 Do everything completely in-kernel
If you use the in-kernel functionality you will be able to easily emulate keyboard presses.

First, start by disabling LIRC. You can disable lirc semi-permanently by changing the START_LIRCD config value to false in /etc/lirc/hardware.conf. Or by simply uninstalling it. We're not going to need it any way. But first stop lirc, because when that variable is set to false, you can't stop or start lirc. Also stop XBMC for the time being, because you don't want your remote to do funny things with XBMC when it starts working.

Then, if you haven't got it-keytable installed yet, do it now and execute

The important line is the line "Supported protocols". Like the name says, it indicates which protocols are supported by your receiver. This is important, because your remote and your receiver will have to 'speak' the same protocol.

Based on the very little experience I have, I have found that RC5 (you can ommit the dash) is mainly used by TVs, RC6 by MCE remotes and NEC by most other remotes that are not Sony or JVC based. Apparently there can also be overlap between protocols. For instance, my Sony Bravia TV remote generates events for both RC5 and SONY.

So you may have to find out what protocol your remote 'speaks'. You could probably just select all of them and you'll most likely be fine, but it is also possible that you really have to pick the correct one.

In any case, execute

Code:

ir-keytable -c -p $protocols -t

-c clears your mapping table if you already programmed one.
-p defines which protocols your IR receiver should listen to. Replace $protocols with a comma separated list of all your supported protocols. In my case that would be NEC,RC-5,RC-6,JVC,SONY,LIRC.
-t initiates the test mode. Think of it as the kernel version of irw.

The 1f3f scancode is useless, because it's always the same, no matter which button I press. You can test which protocol is the truly correct one by using ir-keytable again:

Code:

ir-keytable -c -p $proto -t

One by one you can test each protocol. In my case, when I set the protocol to RC5, it generates the 1f3f codes and when I set it to SONY, it generates the right ones. All the other protocols do not generate anything. So now I know that my Bravia remote uses SONY (duhh).

But like I said you can probably get away with just using all supported protocols at once. The 1f3f scancodes are harmful when left unconfigured.

By the way, once you've set the protocol(s) you wish to use you don't have to enter them again. At least not until you reboot. So from hereon you can simply use `ir-keyable -t` to test. The -c flag you'll only need when you want to reset the table.

So enter `ir-keyable -t` again and see if all your buttons are functional. It's possible not all of them are, but there's little you can do about that I'm afraid.

Now the part that MAY require the most work. You are now capable of generating events, but they have yet to be connected to a certain key press. If you have a common remote, such as the famous MCE remote, it could be as simple as using the right config file (let's say a lircd.conf for ir-keytable). Execute the following command to see the included config files:

Code:

ls /lib/udev/rc_keymaps/

If you see anything resembling the remote your wish to use with XBMC, you may be lucky. But let's find out for sure. You could be browsing through all these files manually, but this is *NIX, so there's a command for that. Enter `ir-keyable -t` again and press a standard button, such as the ok, up or down. Then copy the resulting scan code and execute the following command:

Code:

grep -iH $scancode /lib/udev/rc_keymaps/*

For instance, if you get "1309375577.020898: event MSC: scancode = 1e14", execute

So that means either file could be appropriate. Compare this file against more scancodes to be sure. If you're lucky, your remote has a preconfigured config file and you can largely skip the next few steps about creating a custom config file. However, in order to map different XBMC actions to one button depending on the context in which this button is pressed, you will have to make modifications. For that, read through part III & IV first. After the section about creating a custom config file you will be able to find how to load this config file into the memory. And do not modify the files in /lib/udev/rc_keymaps, but copy the appropriate file to /etc/rc_keymaps/.

Creating a custom config file
If the grep command did not return any output, however, you will have to create your custom config file. Let's look at a snippet of stock config file (rc6_mce, for MCE remotes) for the general syntax of such a config file:

So on the left we have a code (which should correspond to the scan code) starting with '0x'. On the right we have the key that has to be pressed. This key can be any 'normal' key on a keyboard (e.g. KEY_A) or any more or less standardized MCE 'key' such as KEY_PLAY, KEY_STOP, KEY_MENU, KEY_RED/GREEN/YELLOW/BLUE or KEY_NUMERIC_x. I'm not sure though how or where those MCE keys are mapped, but many of them work in XBMC. Regardless, all we really need are regular keys anyway, since we can simply map those in the keyboard.xml file (section 3) and many of them are already mapped by default. After all, XBMC can already be controlled using a regular keyboard and we are emulating a keyboard. For instance, XBMC doesn't seem to pickup KEY_INFO, but the 'I' in the keyboard is (also) mapped to this action, we can just use 0x123abc KEY_I, with 123abc being the scancode for the button with which you want to trigger the video info in XBMC.

So what you have to do know if have a good look at your remote and start thinking about which button you want to link to which keyboard button and/or action. I suggest you start defining the default actions that are always the same anyway, such as play, pause, left, right, etc. So open one terminal window with the `ir-keytable -t` command running and one text editor with your config file. Now, for every unambiguous key press it once on your remote, copy the scancode to your config file and connect it to the appropriate action. All in the format depicted above. So if your scancode is 44222a when you press your play button, the line in your config file should look like this: "0x44222a KEY_PLAY". At the end of this process you will have a config file with which your remote can at least control the basic functions.

Before you load your config file I suggest you put the following line/comment on line 1:

Code:

# table some-name, type: $proto

Loading your config file
Whether you have created your own config file or used a stock one, you have to load it in order for it to be used. The config file goes into the /etc/rc_keymaps/ folder. The name doesn't really matter. Just keep it brief and concise. By the way, do not overwrite the standard config files in /lib/udev/rc_keymaps/. If you want to use one, copy it to /etc/rc_keymaps/ and modify it there.

Anyway, to load your config file, use ir-keytable again:

Code:

ir-keytable -c -p $proto -w /etc/rc_keymaps/$file

If you've defined the correct protocol in the comment in the file, you can ommit the -p $proto part. Here I use:

Code:

ir-keytable -c -w /etc/rc_keymaps/onkyo-dvd

For the record, I'm using a universal remote that came with my TX-NR509 AV receiver. It can control a lot of devices (I have a good 10 pages of remote control codes) and I've set it up as a DVD player remote. This is my config file:

But like I said, for now, just pay attention to the standard functionality. Also note that ir-keytable will segfault if it finds any comments prior to the first definition. Took me a while to figure out what the hell was wrong with my config file (not that that is a valid reason to segfault but ok). Anyway, the command should output something like this:

So it should recognize the keys you entered. Now start XBMC and see if the buttons you configured actually do something there as well!

If you want to load the config file at boot time you can use /etc/rc_maps.cfg, but I haven't quite figured out how yet. Since my HTPC is also my server, uptime is of some significance to me, so I can't just reboot whenever I want. But in the meantime you can copy the ir-keytable command to /etc/rc.local.

2.3 Let the kernel cooperate with LIRC

Apparently you can also combine the strengths of both the in-kernel mapping and keyboard emulation with LIRC, which does seem to have some capabilities that the kernel drivers don't, such a connecting certain scripts to certain buttons, through irexec. You'll only need to do this though if you need this sort of advanced functionality. According to the LIRC website you need at least 0.9.0, but I also got it working with LIRC 0.8.7. YMMV though. I also didn't really test it very thoroughly, as I don't have any use for LIRC at this moment. For this section you will need to have done everything from section 2.2. You can skip section 2.1.

First, start with installing lirc if you've deinstalled it or never installed it in the first place. If you're asked what remote you want to use, choose "Linux input layer (/dev/input/eventX)". Generally you won't need a transmitter device for XBMC, so select "none". For the device, pick the one with the name in it. In my case, this is the resulting hardware.conf. If your package manager doesn't generate it, just use mine and adapt it:

#Don't start lircmd even if there seems to be a good config file
#START_LIRCMD="false"

#Try to load appropriate kernel modules
LOAD_MODULES="true"

# Default configuration files for your hardware if any
LIRCMD_CONF=""

FORCE_NONINTERACTIVE_RECONFIGURATION="false"
START_LIRCMD=""

Then, modprobe the module that provides support for the LIRC protocol to ir-keytable:

Code:

modprobe ir-lirc-codec

If you want to automatically load this module at boot time, add it to /etc/modules. Next, execute the same ir-keytable command again, but add LIRC to your comma separated (list of) protcol(s), e.g.:

Code:

ir-keytable -c -w /etc/rc_keymaps/myconfig -p NEC,LIRC

If you want to make this persistent, change the command in your /etc/rc.local (or equivalent) as well. Note that if you run a Debian based distro, you wil have to (re)issue this command after you reinstall or dpkg-reconfigure lirc, because it will reset the protocol to LIRC only.

Then, again if your package manager didn't generate a correct hardware.conf, you'll most likely also need to modify your lircd.conf. For now, just add

If all went well, you have now mapped all the basic functionality and you know how to emulate keyboard presses. There is one slight problem, though, which you will probably find out if you start mapping all the functionality onto your remote. It's kind of obvious when you think about it. The solution however, can be bit more complicated. But let's start with the problem. The problem is that your remote probably has much fewer keys than your remote has.

When using a keyboard, you have the luxury of having a large number of keys available and the standard XBMC keyboard.xml to at least some extent uses this space. Practically, this means that you have a lot of keys that do have some function, but that are simply unavailable in many parts of the program. For instance, there's the 'O' key, which displays codec information while playing a movie. But in the rest of the program, it doesn't seem to do one bit. Or the 'C' button. It displays the context menu when browsing through the files or library, but in other parts is doesn't seem to have any function.

When using a keyboard, it doesn't really matter. Like I said, there are more than enough keys. But when using a regular remote you do NOT have this luxury. Having buttons that are useless 70% of the time is a waste of buttons. If you want to map all functionality, you will have to come up with a creative solution, especially when you don't have a lot of buttons.

In this part I will try to outline one solution that could solve this problem. I will show you how you can create multifunctional remote buttons that have a different function depending on the context in which this button is used. This means that you can 'recycle' a button in different environments in different parts of the program. I had gotten used to this efficient behaviour before I had my 'real' remote and used the Android XBMC App:

For instance, the title button not only triggers the context menu, the same button also shows the codec info when playing a video. And the "menu" button of course triggers the menu, but it also returns you to your Home Screen instantly when your are not playing a video. I found this to be very efficient use of (virtual) buttons and wanted to copy this behaviour with my real remote.

After all, if you don't and you have a limited number of buttons on your remote, you're going to have to settle for a limited subset of the functionality. Or you would have to start working with rather illogical button mappings, such as mapping certain actions to the numeric section of the remote. It'd be like an automated phone call: press 1 for codec info, press 2 for ...

Fortunately, the framework to make this happen already exists and is already being used, even on a keyboard (take for example the "up" key). This magic is all contained in, or at least exposed to the user via keyboard.xml and any user-specific or system wide overrides. And that's exactly what you have to do: create overrides for the vanilla keyboard.xml to map your buttons exactly the way you want to. After all, remember we are emulating a keyboard, so we can configure it as such.

First it's important that you understand how the keyboard.xml file works. Have a good look at the vanilla keyboard.xml. The structure of this file is pretty simple, although maybe a bit too verbose due to being XML and all. The general structure is like this:

So there a different sections. The most important one is "global". Other examples include Home, MyVideoLibrary, FullscreenVideo and lots of others. Just have a look at the default keyboard.xml. The important thing is that you realize there are different sections that can each have different keymappings.

Knowing this, mapping the right actions to exactly the right keys should be relatively easy. However, do NOT change the default keyboard.xml. Rather, create a file of which the contents will automatically override the respective mapping from the central keyboard.xml. The location of this file or these files is ~/.xbmc/userdata/keymaps/. All the files there that have the .xml extension will be processed automatically by XBMC. All you have to do is create a file there (e.g. custom.xml) and you're good to go.

Also important are the actions. You can see most of them in the keyboard.xml file, but there's an exhaustive list here. Those are the actions/command that XBMC will understand. Most them are pretty much self-explanatory, but there's always the description.

Let's go back to the example where we want to map the ContextMenu and CodecInfo to one button on our remote. First, you have to look how they are mapped now. The Context Menu can be triggered with the "C" key as you can see. The Codec Info overlay can be triggered using the "O" button. Now you can do two things: map the Codec Info to the C button or the Context Menu to the O in the appropriate sections. Technically it doesn't matter which route you take, but it's smart to check how many overrides you need and take the one that requires the least overrides. Both actions have been defined globally, so we can simply count the sections in which we would need overrides. Say we wanted to map ContextMenu to "O". We would have to create overrides in MyVideoLibrary, MyVideoFiles, MyMusicLibrary, ... MyFiles, etc, etc. Basically everywhere where you can browse files or database entries. Those are a lot of sections. However, if we chose to map CodecInfo to "C" it would be less work. With <FullscreenVideo> the most important mapping would already be fixed.

Now, make sure your custom.xml has the proper structure to begin with, which is basically a <keymap> tag to open and a </keymap> tag to close. Between those tags you can map your keys (within sections). So we wanted to map the CodecInfo action the the C button. The first question is in which sections. Global? No, because then the content menu wouldn't function anymore. So, where do we need CodecInfo? Only when a video is playing of course. The most prominent section is <FullscreenVideo>, but there are also other. If we make this map, everytime you press the button that is mapped to KEY_C in ir-keytable, you get the codec info overlay, while in other parts of XBMC the default behaviour of the C button remains (open/close a context menu).

Another, slightly simpler example, is this: normally, the backspace key goes to the parent directory (i.e. back). But when playing a video I wanted to use my "back" button to go back 7 secs. This way I have a good control over the video: up/down for a big step (10 minutes or one chapter) forward/backward, left/right for 30 second steps and back for a 7 second step back (in case I missed something someone just said or something that just happened and I don't want to rewatch 30 seconds).

And you can also add 'new' functionality. For instance, I have a "Home" button, with which I would like to go back to the Home Screen whenever I press it. There's no mapping to a normal key, so we have to create one. The "H" is not in use so let's take that one. We can just define it in the 'global' section. The action is XBMC.ActivateWindow(Home).

Also, I would like the "menu" button ("M" on the keyboard) to open the Settings. In the video sections this button has already been mapped to opening the OSD Menu, so all we have to do is create a 'global' override (which is not valid for the sections where "M" has already been defined explicitly). The resulting file looks like this:

In the comments I documented the default behaviour for KEY_C, but it's not necessary of course. Note the repetitive pattern with just different section tags. I hope it's pretty self-explanatory.

So know you know how to 'add' functionality/actions and override currently mapped functionality. Note that the examples I just gave you are just that: examples. Like I said, I was basically inspired by the way the XBMC Android Remote App mapped its buttons. When mapping your own keys you will have to use your own preferences and creativity.

Q: What are the advantages and disadvantages of using kernel drivers with ir-keytable instead of LIRC?
A: The advantages basically are that you are able to emulate a keyboard, that it's much more in line with the way Linux handles other input devices and that it's simpler to configure, but that one is just my opinion. Disadvantages are that LIRC probably has support for more receivers and a bigger userbase, meaning much more lircd.conf files available that might apply to your remote. Also, at this moment LIRC seems to have somewhat more extensive functionality and is more mature.

Q: Are there any known quirks?
The most important concern I have at the moment is that ir-keytable doesn't play nicely on the i386 architecture.

Q: How can I make the receiver work again after waking up from standby or hibernation?
A: See this post

Ah yes it saw it on the Ubuntu forums, but I didn't know you also posted it here (or that you were the author, for that matter). Any way, I intend to make my guide a bit more generic, extensive and with more (background) information, but yes the cornerstone is the same. Still, I hope people find my guide useful.

Looking forward to part 3 and 4
Been pulling my hair out trying to get this to work. Option 1 does not work for me, so hopefully the kernel drivers will. I get a response back from ir-keytable but nothing happens in XBMC.

gazrat Wrote:Looking forward to part 3 and 4
Been pulling my hair out trying to get this to work. Option 1 does not work for me, so hopefully the kernel drivers will. I get a response back from ir-keytable but nothing happens in XBMC.

Look forward to the next part

I think you need to modprobe ir-lirc-codec. I forgot that one yesterday. Then restart lirc and reissue the ir-keytable command.

gazrat Wrote:Ok, this all seems to be making sense to me so far (thank again for doing this, best explanation I've found so far on what is happening)

I've modified my keymap to correspond to the response I get when running ir-keytable -t
Loading it seems to work as well

However, I stil don't see the keys listed now when doing a new test

Any idea what I'm missing ? It seems so close to being right !

Did you use the vanilla rc6_copy (or a verbatim copy thereof)? Because it looks like you've got an Xbox 360 Universal Remote, or one that uses the same codes. I recognized the codes, because I also have an Xbox 360 with that remote .

The vanilla rc6_mce file contains codes that are almost the same, but one digit is different. If I'm not mistaken you pressed OK and then UP, right? Look at the difference:

Strange. You seem to have load all the right kernel modules (well, it's supposed to happen automatically anyway but you never know) and your config file looks just fine. After you've loaded a config file, does `ir-keytable -r` return the proper table you just loaded?