--- lirc_imon.c.old	2005-04-16 20:10:02.000000000 +0200
+++ lirc_imon.c	2005-07-25 01:04:04.406805182 +0200
@@ -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,7 @@
 #define	TRUE		1
 #define FALSE		0
 
+#define CURSOR_LIMIT    2	    
 
 /* ------------------------------------------------------------
  *                     P R O T O T Y P E S
@@ -160,7 +162,11 @@
 		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       */
+        struct input_dev mouse;              /* mouse interface           */
 };
 
 #define LOCK_CONTEXT	down (&context ->sem)
@@ -573,6 +579,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),
@@ -616,7 +624,7 @@
 
 	LOCK_CONTEXT;
 
-	usb_unlink_urb (context ->rx_urb);
+	usb_kill_urb (context ->rx_urb);
 	context ->ir_isopen = FALSE;
 	MOD_DEC_USE_COUNT;
 	info ("IR port closed");
@@ -701,11 +709,72 @@
 
 	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;
+	  if(buf[0] & 0x40) {
+	          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 */
+				          buf[0] = 0x68;
+					  buf[1] = 0x82;
+					  buf[2] = 0x91;
+				  } else if(rel_y < -CURSOR_LIMIT) { /* mouse n */
+				          buf[0] = 0x69;
+					  buf[1] = 0x02;
+					  buf[2] = 0x81;
+				  } else {
+				          return; /* discard those key codes */
+				  }
+
+			  } else {
+			          if(rel_x > CURSOR_LIMIT) { /* mouse e */
+				          buf[0] = 0x68;
+					  buf[1] = 0x8A;
+					  buf[2] = 0x81;
+			           } else if(rel_x < -CURSOR_LIMIT) { /* mouse w */
+			                  buf[0] = 0x6A;
+					  buf[1] = 0x82;
+					  buf[2] = 0x81;
+			           } else {
+			                  return; /* discard those key codes */
+				   }
+			  }
+			  
+		  } else {
+
+			  /* mouse emulation */
+                          struct input_dev *mouse = &context->mouse;
+                          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;
+		  }
+	  }
+	  
+	  /* 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;
 	}
 	
 	/*
@@ -1082,6 +1151,22 @@
 #endif
 	}
 
+	/* register with kernel input system for PAD mouse */
+	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);
+
 	info ("%s: iMON device on usb<%d:%d> initialized",
 			__FUNCTION__, dev ->bus ->busnum, dev ->devnum);
 
@@ -1125,12 +1210,12 @@
 	context ->dev_present = FALSE;
 
 	/* Stop reception */
-	usb_unlink_urb (context ->rx_urb);
+	usb_kill_urb (context ->rx_urb);
 
 	/* Abort ongoing write */
 	if (atomic_read (&context ->tx.busy)) {
 
-		usb_unlink_urb (context ->tx_urb);
+		usb_kill_urb (context ->tx_urb);
 		wait_for_completion (&context ->tx.finished);
 	}
 
@@ -1147,6 +1232,8 @@
 #endif
 	}
 
+	input_unregister_device (&context ->mouse);
+
 	UNLOCK_CONTEXT;
 
 	if (!context ->ir_isopen && !context ->vfd_isopen)
