patch to make the imon PAD generate mouse events

Linux support for Soundgraph iMON USB IR/VFD modules used in Ahanix, Silverstone, Uneed, Accent and other cases.

Moderator: Venky

Postby perkinbr » Wed Feb 01, 2006 7:15 pm

I use it for myth. It's not great, but it works. I don't doubt that something could be improved, perhaps in such a way that my patch would be unnecessary.

I haven't been using it for very long, but it seems to help.
perkinbr
 
Posts: 8
Joined: Tue Jan 31, 2006 11:25 pm

Postby perkinbr » Fri Feb 03, 2006 12:06 am

anssi:

I thought about what you said, and I think I've come up with a better solution. The old patch just waited for MOUSE_KEY_REPEAT events and then used the last relative motion as the direction.
This one keeps track of how far we went in both X and Y. When a certain distance is reached, an event is generated.

I also added a threashold number of events where it just resets the distance to zero again, hoping to avoid drift. It may be unnecessary or worse.

It's a bit fast as it is now, repeats can be slowed down by increasing CURSOR_LIMIT.

There's also the annoying thing where it will only repeat about 15 times before you have to lift off the mouse to get it to generate another event, just like in the older version. Anyone know why that happens?

Feel might be improved if we reset the x/y counter after a certain amount of _time_. As it is, reversing direction feels a bit sluggish.

In my quick testing, the spurious perpendicular events seem greatly reduced.

Code: Select all
--- lirc_imon.c.orig   2006-01-31 23:12:57.000000000 -0500
+++ lirc_imon.c   2006-02-02 23:45:25.000000000 -0500
@@ -84,7 +84,7 @@
#define   TRUE      1
#define FALSE      0

-#define CURSOR_LIMIT    2      
+#define CURSOR_LIMIT    16      

#define MOUSE_KEY_REPEAT 8

@@ -174,7 +174,8 @@
      int status;           /* status of tx completion   */

   } tx;
-
+        int key_x;
+        int key_y;
         int mode_kbd;                        /* keyboard/mouse mode       */
         struct input_dev mouse;              /* mouse interface           */
         pad_key_t last_mouse_key;            /* last mouse key pressed    */
@@ -590,9 +591,12 @@
   context ->rx.count = 0;
   context ->rx.initial_space = 1;
   context ->rx.prev_bit = 0;
-
+        context ->key_x = 0;                       
+        context ->key_y = 0;                     
+        context ->last_count = 0;                     
         context ->mode_kbd = 1;                        /* init keyboard mode       */

+
   usb_fill_int_urb (context ->rx_urb, context ->dev,
      usb_rcvintpipe (context ->dev,
            context ->rx_endpoint-> bEndpointAddress),
@@ -733,51 +737,62 @@

             /* keyboard direction key emulation */
             if(context->mode_kbd) {
-
+          if( context->last_count > 32 )
+            {  /* Hopefully eliminate drift*/
+         context->last_count=0;
+         context->key_y=0;
+         context->key_x=0;
+            }
+          context->last_count++;
           if(buf[1] & 0x01 || buf[1] >> 2 & 0x01) {
             //          warn("press\n");
                   /* mouse pressed */
           }

-           if(abs(rel_y) > abs(rel_x)) {
-                   if(rel_y > CURSOR_LIMIT) { /* mouse s */
+          if(abs(context->key_x) > CURSOR_LIMIT ||
+             abs(context->key_y) > CURSOR_LIMIT ) {
+           
+            if(abs(context->key_y )> abs(context->key_x)) {
+                                  /* mouse s/n */
+         if(context->key_y > 0 && rel_y > 0) { /* mouse n */
                      key = MOUSE_KEY_S;
                      buf[0] = 0x68;
                 buf[1] = 0x82;
                 buf[2] = 0x91;
-              } else if(rel_y < -CURSOR_LIMIT) { /* mouse n */
+          
+         } else if(context->key_y < 0 && rel_y<0) { /* mouse s */
+         
                      key = MOUSE_KEY_N;
                      buf[0] = 0x69;
                 buf[1] = 0x02;
                 buf[2] = 0x81;
-              } else {
-                      return; /* discard those key codes */
              }

-           } else {
-                   if(rel_x > CURSOR_LIMIT) { /* mouse e */
+            } else { /*mouse e/w*/
+         if(context->key_x > 0 && rel_x > 0 ) { /* mouse e */
                      key = MOUSE_KEY_E;
                      buf[0] = 0x68;
                 buf[1] = 0x8A;
                 buf[2] = 0x81;
-                    } else if(rel_x < -CURSOR_LIMIT) { /* mouse w */
+         } else if(context->key_y < 0 && rel_x < 0  ) { /* mouse w */
                      key = MOUSE_KEY_W;
                           buf[0] = 0x6A;
                 buf[1] = 0x82;
                 buf[2] = 0x81;
-                    } else {
-                           return; /* discard those key codes */
               }
           }
-           /* check for repeats we want to discard */
-           if (key == context->last_mouse_key) {
-                    context->last_count++;
-                    if (context->last_count < MOUSE_KEY_REPEAT)
+          }
+          else {
+            context->key_x += rel_x;
+            context->key_y += rel_y;
+           
                           return; /* discard those key codes */
-           } else {
-                    context->last_mouse_key = key;
           }
          
+         
+          context->last_mouse_key = key;
+         
+          
        } else {

           /* mouse emulation */
@@ -797,6 +812,8 @@

     /* a key was pressed or a synthetic mouse key let through,
      * so reset count */
+     context->key_x = 0;
+     context->key_y = 0;
     context->last_count = 0;
    
     /* mouse/kbd button 29 91 15 b7 */
[/code]
perkinbr
 
Posts: 8
Joined: Tue Jan 31, 2006 11:25 pm

Postby anssi » Fri Feb 03, 2006 4:29 am

Now we are talking!
This looks great, I have to try it in the weekend.
anssi
 
Posts: 23
Joined: Tue Nov 29, 2005 5:47 am
Location: Helsinki, Finland

Postby perkinbr » Fri Feb 03, 2006 12:28 pm

BTW the:

Code: Select all
if(context->key_x > 0 && rel_x > 0 )


the rel_x > 0 avoids a weird problem when reversing direction where it gives an extra event in the wrong direction.

Come to think of it this might be even better:

Code: Select all
if(context->key_x > 0 && rel_x > 0 && abs(rel_x) > abs(rel_y)   )


To avoid an extra event when switching frum up/down to left/right.

Feel free to jump in if you have any idea of why the repeats stop after a while. :)
perkinbr
 
Posts: 8
Joined: Tue Jan 31, 2006 11:25 pm

Postby Guest » Fri Feb 03, 2006 3:50 pm

Could you post the patch as an attachment or something because applying a copy-paste-patch doesn't work because of the tabs in the code?

Cheers!
Guest
 

Postby perkinbr » Fri Feb 03, 2006 4:56 pm

patch -l should help with whitespace problems.

If I recall correctly, this is a diff against thomasvs's patched version from sourceforge http://cvs.sourceforge.net/viewcvs.py/davedina/package/lirc/lirc-imon-pad.patch?rev=1.1&view=log

I'll try to make a better diff when I get home.
perkinbr
 
Posts: 8
Joined: Tue Jan 31, 2006 11:25 pm

Postby perkinbr » Fri Feb 03, 2006 9:57 pm

A better patch:

http://www.netspace.org/~bperkins/lirc_imon_ipad_betterkeys.patch

This one is against unpatched lirc-0.8.0-CVS, the source rpm from atrpms.

If in doubt, you can see if it will work this way:

cd lirc-source/

patch -p1 --dry-run < lirc_imon_ipad_betterkeys.patch
perkinbr
 
Posts: 8
Joined: Tue Jan 31, 2006 11:25 pm

Postby anssi » Sun Feb 05, 2006 7:29 am

Hi again!

Your patch seems to work quite well!
I'm still testing it but the first impressions are very positive!
Nice work!

- Anssi Kanninen
anssi
 
Posts: 23
Joined: Tue Nov 29, 2005 5:47 am
Location: Helsinki, Finland

Patch Working ?

Postby Grandyaka » Sun Feb 05, 2006 10:43 am

Hello,
Sorry for my poor english... I've tried the last pach, an the pad seems to work well, but is too slow for my screen (1920*1200).
I have already modified the "accelerator" parameter in lircmd without succes.

Is there another parameter to adapt ?

But anyway, thank you for our contribution.
Grandyaka
 
Posts: 1
Joined: Sun Feb 05, 2006 10:28 am
Location: France Toulouse

Postby perkinbr » Sun Feb 05, 2006 12:09 pm

Grandyaka:

I assume you're talking abou the mouse movement.
My patch doesn't really affect the mouse mode at all.

The simplest way would be to turn the mouse sensitivity and acceleration all the way up.

Assumuing you've tried that and it's not acceptable for some reason, you could probably change lines 806 and 807 (or so) from:
Code: Select all
                           input_report_rel(mouse, REL_X,     rel_x);
                           input_report_rel(mouse, REL_Y,     rel_y);

to:
Code: Select all

                         input_report_rel(mouse, REL_X,     2*rel_x);
                          input_report_rel(mouse, REL_Y,     2*rel_y);

You can change 2 to whatever floats your boat (i.e. larger numbers for bigger mouse movements). I'd avoid floating point numbers like 1.5 if possible, but they _should_ work. You can always just try it :)


BTW, my testing procedure has been:

edit lirc_imon.c
make
rmmod lirc_imod (make sure nothing's running like irw, mythfrontend, etc)
insmod ./lirc_imod
irw
(test mouse, keys etc.)
control-c
repeat


Once you get it to the way you like it you could add a kernel parameter, but that's an exercise left to the reader. :)
perkinbr
 
Posts: 8
Joined: Tue Jan 31, 2006 11:25 pm

Re: Patch Working ?

Postby anssi » Mon Feb 06, 2006 4:42 am

Grandyaka wrote:Hello,
Sorry for my poor english... I've tried the last pach, an the pad seems to work well, but is too slow for my screen (1920*1200).
I have already modified the "accelerator" parameter in lircmd without succes.

Is there another parameter to adapt ?

But anyway, thank you for our contribution.

Lircmd??
So you're saying that you don't use the mouse mode provided by the first patch at all?
You don't need lircmd if you use the mouse mode provided by the patch. Just hit "Keyboard/Mouse" button and mouse should work.
anssi
 
Posts: 23
Joined: Tue Nov 29, 2005 5:47 am
Location: Helsinki, Finland

Patch updated for 2.6.15 kernel

Postby SiliconFiend » Mon Feb 06, 2006 10:02 am

Okay, I updated this patch to work with 2.6.15 and greater kernels (should work with earlier versions, too). This is a modification of davedina's patch. I reduced the MOUSE_KEY_REPEAT from 8 to 4, which made it more responsive in keyboard mode. I believe this fixes the kernel panic/oops that some people have been seeing (at least it did for me). This doesn't require lircmd, but you should have the following lines in your lircd.conf to get the keyboard working
Code: Select all
Up    0x690281b7
Down  0x688291b7
Left  0x6a8281b7
Right 0x688a81b7


If anyone wants to apply this modification to other patches, the key is to change the static "struct input_dev mouse" to a pointer ("struct input_dev * mouse") and then input_allocate_device() to create the struct. Just look for the lines surrounded by:
Code: Select all
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
/* code for kernels prior to 2.6.15 */
#else
/* code for kernels greater than or equal to 2.6.15 */
#endif


Here's the patch:
Code: Select all
diff -Naur lirc-0.8.0/drivers/lirc_imon/lirc_imon.c lirc-0.8.0.new/drivers/lirc_imon/lirc_imon.c
--- lirc-0.8.0/drivers/lirc_imon/lirc_imon.c    2005-12-03 07:18:07.000000000 -0800
+++ lirc-0.8.0.new/drivers/lirc_imon/lirc_imon.c        2006-01-23 13:51:14.000000000 -0800
@@ -53,6 +53,7 @@

#include <linux/errno.h>
#include <linux/init.h>
+#include <linux/input.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -68,7 +69,7 @@
#define MOD_AUTHOR     "Venky Raju <dev@venky.ws>"
#define MOD_DESC       "Driver for Soundgraph iMON MultiMedian IR/VFD"
#define MOD_NAME       "lirc_imon"
-#define MOD_VERSION    "0.3"
+#define MOD_VERSION    "0.3M"

#define VFD_MINOR_BASE 144     /* Same as LCD */
#define DEVFS_MODE     S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH
@@ -83,6 +84,9 @@
#define        TRUE            1
#define FALSE          0

+#define CURSOR_LIMIT    2
+
+#define MOUSE_KEY_REPEAT 4

/* ------------------------------------------------------------
  *                     P R O T O T Y P E S
@@ -118,6 +122,14 @@
static int __init imon_init (void);
static void __exit imon_exit (void);

+typedef enum {
+  MOUSE_KEY_NONE,
+  MOUSE_KEY_N,
+  MOUSE_KEY_E,
+  MOUSE_KEY_S,
+  MOUSE_KEY_W
+} pad_key_t;
+
/* ------------------------------------------------------------
  *                     G L O B A L S
  * ------------------------------------------------------------
@@ -160,7 +172,17 @@
                struct completion finished;  /* wait for write to finish  */
                atomic_t busy;               /* write in progress         */
                int status;                  /* status of tx completion   */
+
        } tx;
+
+        int mode_kbd;                        /* keyboard/mouse mode       */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
+        struct input_dev mouse;              /* mouse interface           */
+#else
+        struct input_dev * mouse;            /* mouse interface           */
+#endif
+        pad_key_t last_mouse_key;            /* last mouse key pressed    */
+        int last_count;                      /* number of times pressed   */
};

#define LOCK_CONTEXT   down (&context ->sem)
@@ -575,6 +597,8 @@
        context ->rx.initial_space = 1;
        context ->rx.prev_bit = 0;

+        context ->mode_kbd = 1;                        /* init keyboard mode       */
+
        usb_fill_int_urb (context ->rx_urb, context ->dev,
                usb_rcvintpipe (context ->dev,
                                context ->rx_endpoint-> bEndpointAddress),
@@ -703,11 +727,98 @@

        if (context ->ir_onboard_decode) {

-               /* The signals have been decoded onboard the iMON controller */
+         /* The signals have been decoded onboard the iMON controller */

-               lirc_buffer_write_1 (context ->plugin ->rbuf, buf);
-               wake_up (&context ->plugin ->rbuf ->wait_poll);
-               return;
+          /* mouse pad */
+         if(buf[0] & 0x40) {
+                 pad_key_t key;
+                 int rel_x = (buf[1] & 0x08) | (buf[1] & 0x10) >> 2 | (buf[1] & 0x20) >> 4 | (buf[1] & 0x40) >> 6;
+                 int rel_y = (buf[2] & 0x08) | (buf[2] & 0x10) >> 2 | (buf[2] & 0x20) >> 4 | (buf[2] & 0x40) >> 6;
+                 if(buf[0] & 0x02) rel_x |= ~0x10+1;
+                 if(buf[0] & 0x01) rel_y |= ~0x10+1;
+
+                 /* keyboard direction key emulation */
+                 if(context->mode_kbd) {
+
+                         if(buf[1] & 0x01 || buf[1] >> 2 & 0x01) {
+                           //              warn("press\n");
+                                 /* mouse pressed */
+                         }
+
+                         if(abs(rel_y) > abs(rel_x)) {
+                                 if(rel_y > CURSOR_LIMIT) { /* mouse s */
+                                         key = MOUSE_KEY_S;
+                                         buf[0] = 0x68;
+                                         buf[1] = 0x82;
+                                         buf[2] = 0x91;
+                                 } else if(rel_y < -CURSOR_LIMIT) { /* mouse n */
+                                         key = MOUSE_KEY_N;
+                                         buf[0] = 0x69;
+                                         buf[1] = 0x02;
+                                         buf[2] = 0x81;
+                                 } else {
+                                         return; /* discard those key codes */
+                                 }
+
+                         } else {
+                                 if(rel_x > CURSOR_LIMIT) { /* mouse e */
+                                         key = MOUSE_KEY_E;
+                                         buf[0] = 0x68;
+                                         buf[1] = 0x8A;
+                                         buf[2] = 0x81;
+                                  } else if(rel_x < -CURSOR_LIMIT) { /* mouse w */
+                                         key = MOUSE_KEY_W;
+                                         buf[0] = 0x6A;
+                                         buf[1] = 0x82;
+                                         buf[2] = 0x81;
+                                  } else {
+                                         return; /* discard those key codes */
+                                  }
+                         }
+                         /* check for repeats we want to discard */
+                         if (key == context->last_mouse_key) {
+                                  context->last_count++;
+                                  if (context->last_count < MOUSE_KEY_REPEAT)
+                                         return; /* discard those key codes */
+                         } else {
+                                  context->last_mouse_key = key;
+                         }
+
+                 } else {
+
+                         /* mouse emulation */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
+                          struct input_dev *mouse = &context->mouse;
+#else
+                          struct input_dev *mouse = context->mouse;
+#endif
+                          context->last_mouse_key = MOUSE_KEY_NONE;
+                          input_report_key(mouse, BTN_LEFT,   buf[1] & 0x01);
+                          input_report_key(mouse, BTN_RIGHT,  buf[1] >> 2 & 0x01);
+                          input_report_rel(mouse, REL_X,     rel_x);
+                          input_report_rel(mouse, REL_Y,     rel_y);
+                          input_sync(mouse);
+                         return;
+                 }
+         } else {
+                 /* was not a mouse key, so reset */
+                 context->last_mouse_key = MOUSE_KEY_NONE;
+         }
+
+         /* a key was pressed or a synthetic mouse key let through,
+          * so reset count */
+         context->last_count = 0;
+
+         /* mouse/kbd button 29 91 15 b7 */
+         if((buf[0] == 0x29) && (buf[1] == 0x91) && (buf[2] == 0x15) && (buf[3] == 0xb7)) {
+           //            warn("toggle kbd %d -> %d\n", context->mode_kbd, !context->mode_kbd);
+                 context->mode_kbd = !context->mode_kbd;
+                 return;
+         }
+
+         lirc_buffer_write_1 (context ->plugin ->rbuf, buf);
+         wake_up (&context ->plugin ->rbuf ->wait_poll);
+         return;
        }

        /*
@@ -1084,6 +1195,39 @@
#endif
        }

+       /* register with kernel input system for PAD mouse */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
+       context->mouse.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+       context->mouse.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+       context->mouse.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+       context->mouse.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA);
+       context->mouse.relbit[0] |= BIT(REL_WHEEL);
+       context->mouse.private = context;
+
+       context->mouse.id.bustype = BUS_USB;
+       context->mouse.id.vendor = le16_to_cpu(dev->descriptor.idVendor);
+       context->mouse.id.product = le16_to_cpu(dev->descriptor.idProduct);
+       context->mouse.id.version = le16_to_cpu(dev->descriptor.bcdDevice);
+       context->mouse.dev = &dev->dev;
+
+       input_register_device(&context->mouse);
+#else
+       context->mouse = input_allocate_device();
+       context->mouse->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+       context->mouse->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+       context->mouse->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+       context->mouse->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA);
+       context->mouse->relbit[0] |= BIT(REL_WHEEL);
+       context->mouse->private = context;
+
+       context->mouse->id.bustype = BUS_USB;
+       context->mouse->id.vendor = le16_to_cpu(dev->descriptor.idVendor);
+       context->mouse->id.product = le16_to_cpu(dev->descriptor.idProduct);
+       context->mouse->id.version = le16_to_cpu(dev->descriptor.bcdDevice);
+       context->mouse->dev = &dev->dev;
+
+       input_register_device(context->mouse);
+#endif
        info ("%s: iMON device on usb<%d:%d> initialized",
                        __FUNCTION__, dev ->bus ->busnum, dev ->devnum);

@@ -1149,6 +1293,11 @@
#endif
        }

+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
+       input_unregister_device (&context ->mouse);
+#else
+       input_unregister_device (context ->mouse);
+#endif
        UNLOCK_CONTEXT;

        if (!context ->ir_isopen && !context ->vfd_isopen)


I'll try Brian Perkin's patch later and see how it works.
SiliconFiend
 

Question about perkinbr's patch

Postby SiliconFiend » Mon Feb 06, 2006 5:01 pm

Brian (I think that's your name perkinbr),

I took a look at your new cumulative motion key patch and I'm confused about the purpose of the last_mouse_key variable. It appears to be write-only. i.e., the value is written but never read so it doesn't affect the logic at all. Am I missing something?
SiliconFiend
 

Postby SiliconFiend » Mon Feb 06, 2006 5:08 pm

Oops, nevermind. I just realized that was in the original and it's not specific to your patch.
SiliconFiend
 

Postby Guest » Tue Feb 07, 2006 4:36 pm

Yeah, sorry, it's cruft.
Guest
 

PreviousNext

Return to Soundgraph iMON IR/VFD Modules

Who is online

Users browsing this forum: No registered users and 0 guests

cron