MCE remote OR22V with the ati_remote kernel module

Posted on December 30th, 2007

The OR22V is a RF remote (not infrared) that comes with an usb-stick as receiver. It is manufactured by X10. When plugged in to a computer with recent linux-kernel running, it should be detected by the ati_remote kernel module. So far so great!! ;-)

Now... Only every second key-press is recognized. And i mean exactly every second!! Digging into the source a little bit revealed, that some bits will be inverted on every second key-press.

Here's how i fixed it for me. Maybe somebody else has the same problem?!?!

First: My kernel is 2.6.22.12-0.1-default from OpenSuSE 10.3

--- ati_remote.c.orig   2007-07-09 01:32:17.000000000 +0200
+++ ati_remote.c        2007-12-30 15:01:09.000000000 +0100
@@ -282,6 +282,14 @@
        {KIND_FILTERED, 0xf4, 0x2F, EV_KEY, KEY_END, 1},        /* END */
        {KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1},     /* SELECT */

+        {KIND_FILTERED, 0xf8, 0x33, EV_KEY, KEY_GREEN, 1},      /* GREEN */
+        {KIND_FILTERED, 0xf7, 0x32, EV_KEY, KEY_RED, 1},        /* RED */
+        {KIND_FILTERED, 0xf9, 0x34, EV_KEY, KEY_YELLOW, 1},     /* YELLOW */
+        {KIND_FILTERED, 0xfa, 0x35, EV_KEY, KEY_BLUE, 1},       /* BLUE */
+        {KIND_FILTERED, 0xf6, 0x31, EV_KEY, KEY_EPG, 1},        /* EPG */
+        {KIND_FILTERED, 0xfc, 0x37, EV_KEY, KEY_KPASTERISK, 1}, /* ASTERISK */
+        {KIND_FILTERED, 0xfd, 0x38, EV_KEY, KEY_KPPLUS, 1},     /* HASH */
+
        {KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0}
 };

@@ -485,6 +493,18 @@
                return;
        }

+        /* Fix data from OR22V Windows MCE remote */
+        if (data[2] >= 0x80) {
+                dbginfo(&ati_remote->interface->dev,
+                        "fix or22v 0x%02x; data %02x,%02x to %02x,%02x\n",
+                        remote_num, data[1], data[2], ((data[1] & 0x80) ? (data[1] & 0x7f) : (data[1] | 0x80)), data[2] & 0x7f);
+                if (data[1] & 0x80)
+                        data[1] &= 0x7f;
+                else
+                        data[1] |= 0x80;
+                data[2] &= 0x7f;
+        }
+
        /* Look up event code index in translation table */
        index = ati_remote_event_lookup(remote_num, data[1], data[2]);
        if (index < 0) {

There is also a patch available for the ATI Remote Wonder Plus, which seems to also make this remote work... You can find it here. It is missing the extra keys though, here it is with the extra keys included:

--- ati_remote.c.orig   2007-12-30 15:08:24.000000000 +0100
+++ ati_remote.c        2007-12-30 15:15:59.000000000 +0100
@@ -159,8 +159,9 @@
 #define SEND_FLAG_COMPLETE     2

 /* Device initialization strings */
-static char init1[] = { 0x01, 0x00, 0x20, 0x14 };
-static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 };
+static char init1[] = {0x80, 0x05, 0x1b, 0x15, 0x14, 0x20, 0x24, 0x15};
+static char init2[] = {0x83, 0x03};
+static char init3[] = {0x84, 0xd7, 0x020};

 struct ati_remote {
        struct input_dev *idev;
@@ -247,6 +248,7 @@
        {KIND_FILTERED, 0xe0, 0x1b, EV_KEY, KEY_D, 1},
        {KIND_FILTERED, 0xe6, 0x21, EV_KEY, KEY_E, 1},
        {KIND_FILTERED, 0xe8, 0x23, EV_KEY, KEY_F, 1},
+       {KIND_FILTERED, 0xf1, 0x2c, EV_KEY, KEY_I, 1},

        /* "special" keys */
        {KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_KPENTER, 1},    /* "check" */
@@ -282,6 +284,14 @@
        {KIND_FILTERED, 0xf4, 0x2F, EV_KEY, KEY_END, 1},        /* END */
        {KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1},     /* SELECT */

+        {KIND_FILTERED, 0xf8, 0x33, EV_KEY, KEY_GREEN, 1},      /* GREEN */
+        {KIND_FILTERED, 0xf7, 0x32, EV_KEY, KEY_RED, 1},        /* RED */
+        {KIND_FILTERED, 0xf9, 0x34, EV_KEY, KEY_YELLOW, 1},     /* YELLOW */
+        {KIND_FILTERED, 0xfa, 0x35, EV_KEY, KEY_BLUE, 1},       /* BLUE */
+        {KIND_FILTERED, 0xf6, 0x31, EV_KEY, KEY_EPG, 1},        /* EPG */
+        {KIND_FILTERED, 0xfc, 0x37, EV_KEY, KEY_KPASTERISK, 1}, /* ASTERISK */
+        {KIND_FILTERED, 0xfd, 0x38, EV_KEY, KEY_KPPLUS, 1},     /* HASH */
+
        {KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0}
 };

@@ -410,10 +420,19 @@
                /*
                 * Decide if the table entry matches the remote input.
                 */
-               if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) &&
-                   ((((ati_remote_tbl[i].data1 >> 4) -
-                      (d1 >> 4) + rem) & 0x0f) == 0x0f) &&
-                   (ati_remote_tbl[i].data2 == d2))
+               if (((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f) &&
+                     (((ati_remote_tbl[i].data1 >> 4) - (d1 >> 4) + rem) & 0x0f) == 0x0f) ||
+                     ((ati_remote_tbl[i].data1 & 0x0f) == ((d1 | 0x80) & 0x0f) && (((ati_remote_tbl[i].data1 >> 4) - ((d1 | 0x80) >> 4) + rem) & 0x0f) == 0x0f)) &&
+                    ati_remote_tbl[i].data2 == d2
+                   ) ||
+                   ((ati_remote_tbl[i].data1 & 0x0f) == ((d1 | 0x80) & 0x0f) &&
+                    (((ati_remote_tbl[i].data1 >> 4) - ((d1 | 0x80) >> 4) + rem) & 0x0f) == 0x0f &&
+                    (ati_remote_tbl[i].data2 == (d2 ^ 0x80))
+                   ) ||
+                   ((ati_remote_tbl[i].data1 & 0x0f) == ((d1 ^ 0x80) & 0x0f) &&
+                    (((ati_remote_tbl[i].data1 >> 4) - ((d1 ^ 0x80) >> 4) + rem) & 0x0f) == 0x0f &&
+                    (ati_remote_tbl[i].data2 == (d2 ^ 0x80))
+                   ))
                        return i;

        }
@@ -469,7 +488,7 @@
        int remote_num;

        /* Deal with strange looking inputs */
-       if ( (urb->actual_length != 4) || (data[0] != 0x14) ||
+       if ( (urb->actual_length != 4) || (data[0] != 0x14 && data[0] != 0x15) ||
                ((data[3] & 0x0f) != 0x00) ) {
                ati_remote_dump(data, urb->actual_length);
                return;
@@ -498,6 +517,32 @@
                remote_num, data[1], data[2], index, ati_remote_tbl[index].code);

        if (ati_remote_tbl[index].kind == KIND_LITERAL) {
+               if (data[0] == 0x15) {
+                       if ((ati_remote->old_data[0] == data[1]) &&
+                           (ati_remote->old_data[1] == data[2]) &&
+                           time_before(jiffies, ati_remote->old_jiffies + msecs_to_jiffies(repeat_filter))) {
+                               ati_remote->repeat_count++;
+                       } else {
+                               ati_remote->repeat_count = 0;
+                       }
+
+                       ati_remote->old_data[0] = data[1];
+                       ati_remote->old_data[1] = data[2];
+                       ati_remote->old_jiffies = jiffies;
+
+                       if ((ati_remote->repeat_count > 0)
+                       && (ati_remote->repeat_count < 3))
+                               return;
+
+                       if (ati_remote->repeat_count >= 3) {
+                               input_event(dev, ati_remote_tbl[index].type,
+                                       ati_remote_tbl[index].code, 0);
+                               input_sync(dev);
+                               ati_remote->repeat_count = 0;
+                               return;
+                       }
+               }
+
                input_event(dev, ati_remote_tbl[index].type,
                        ati_remote_tbl[index].code,
                        ati_remote_tbl[index].value);
@@ -712,8 +757,9 @@
        ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

        /* send initialization strings */
-       if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) ||
-           (ati_remote_sendpacket(ati_remote, 0x8007, init2))) {
+       if ((ati_remote_sendpacket(ati_remote, 0x8007, init1)) ||
+           (ati_remote_sendpacket(ati_remote, 0x8002, init2)) ||
+           (ati_remote_sendpacket(ati_remote, 0x8003, init3))) {
                dev_err(&ati_remote->interface->dev,
                         "Initializing ati_remote hardware failed.\n");
                return -EIO;

So long!!
:-)

Same problem

Hello,

I have the same RF Remote Control and I have the same problem (in Mythbuntu 8.04). Besides that, I cannot get the right mapping of buttons to MythTV functionality. The kernel is newer (2.6.24) I've searched my system, but I did not find the source file ati_remote.c

Can you explain in a few more words how I could apply your patch in my situation? I assume compiling needs to be done, but then?

Thanks a lot.

Regards
Hans

Hmm... Have u installed the

Hmm... Have u installed the kernel-sources? If so, the file should be located in:
/usr/src/linux/drivers/input/misc/ati_remote.c

You will then have to patch that file, and rebuild the module... How to build a kernel-module kinda depends on the distribution, so your best shot is to look for an explanation how to configure, build and install kernel in mythbuntu!

After compiling and installing the module all you have to do is reboot... Or:
rmmod ati_remote
modprobe ati_remote

:-)

I never tried to patch the

I never tried to patch the kernel module. Instead I use lirc's builtin atilibusb driver to control mythtv and xine. See more details at the mythtv forum:
http://www.mythtvtalk.com/forum/installation-issues/8407-how-configure-x...

/Tomas

AddThis button



About Me

Photo of myself Aike J Sommer
web [at] aikesommer [dot] name
Feed: RSS Syndicate content
Company: AS Media