--- lirc-clean/drivers/lirc_imon/lirc_imon.c 2008-08-22 23:38:17.000000000 +0200 +++ lirc-evdev/drivers/lirc_imon/lirc_imon.c 2008-11-13 02:48:08.000000000 +0100 @@ -57,6 +57,7 @@ #include #include +#include #include #include #include @@ -73,9 +74,9 @@ #define MOD_AUTHOR "Venky Raju " -#define MOD_DESC "Driver for Soundgraph iMON MultiMedia IR/VFD" +#define MOD_DESC "Driver for Soundgraph iMON MultiMedia IR/VFD w/imon pad2keys and mouse emulation patch" #define MOD_NAME "lirc_imon" -#define MOD_VERSION "0.3" +#define MOD_VERSION "0.3p2km" #define VFD_MINOR_BASE 144 /* Same as LCD */ #define DEVFS_MODE (S_IFCHR | S_IRUSR | S_IWUSR | \ @@ -91,6 +92,11 @@ #define TRUE 1 #define FALSE 0 +#define CURSOR_LIMIT 16 + +#ifndef LONG(x) +#define LONG(x) ((x)/BITS_PER_LONG) +#endif /* ------------------------------------------------------------ * P R O T O T Y P E S @@ -110,9 +116,9 @@ static void usb_tx_callback(struct urb *urb); #endif #else -static void *imon_probe(struct usb_device *dev, unsigned int intf, +static void *imon_probe(struct usb_device *udev, unsigned int intf, const struct usb_device_id *id); -static void imon_disconnect(struct usb_device *dev, void *data); +static void imon_disconnect(struct usb_device *udev, void *data); static void usb_rx_callback(struct urb *urb); static void usb_tx_callback(struct urb *urb); #endif @@ -135,13 +141,21 @@ 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 * ------------------------------------------------------------ */ struct imon_context { - struct usb_device *dev; + struct usb_device *udev; int vfd_supported; /* not all controllers do */ int vfd_isopen; /* VFD port has been opened */ #if !defined(KERNEL_2_5) @@ -178,6 +192,16 @@ atomic_t busy; /* write in progress */ int status; /* status of tx completion */ } tx; + + int key_x; + int key_y; + int mode_kbd; /* keyboard/mouse mode */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) + struct input_dev idev; /* mouse interface */ +#else + struct input_dev *idev; +#endif + int last_count; /* number of times pressed */ }; #define LOCK_CONTEXT down(&context->sem) @@ -265,6 +289,9 @@ static int is_lcd; /* If LIRC_IMON_LCD not defined, default to non-LCD */ #endif +/* pad2keys module parameter. pad2keys patch active? */ +static int pad2keys_active = 0; + #if !defined(KERNEL_2_5) #define MAX_DEVICES 4 /* In case there's more than one iMON device */ @@ -288,6 +315,7 @@ MODULE_AUTHOR(MOD_AUTHOR); MODULE_DESCRIPTION(MOD_DESC); +MODULE_VERSION(MOD_VERSION); /* MBr: was missing */ MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(usb, imon_usb_id_table); @@ -304,6 +332,9 @@ "1=yes (default:no)"); #endif +module_param (pad2keys_active, int, 0); +MODULE_PARM_DESC (pad2keys_active, "pad2keys patch active: 0=no, 1=yes (default: no)"); + static inline void delete_context(struct imon_context *context) { if (context->vfd_supported) @@ -451,13 +482,13 @@ /* Check if we need to use control or interrupt urb */ if (!context->tx_control) { - pipe = usb_sndintpipe(context->dev, + pipe = usb_sndintpipe(context->udev, context->tx_endpoint->bEndpointAddress); #ifdef KERNEL_2_5 interval = context->tx_endpoint->bInterval; #endif /* Use 0 for 2.4 kernels */ - usb_fill_int_urb(context->tx_urb, context->dev, pipe, + usb_fill_int_urb(context->tx_urb, context->udev, pipe, context->usb_tx_buf, sizeof(context->usb_tx_buf), usb_tx_callback, context, interval); @@ -476,10 +507,10 @@ control_req->wLength = cpu_to_le16(0x0800); /* control pipe is endpoint 0x00 */ - pipe = usb_sndctrlpipe(context->dev, 0); + pipe = usb_sndctrlpipe(context->udev, 0); /* build the control urb */ - usb_fill_control_urb(context->tx_urb, context->dev, pipe, + usb_fill_control_urb(context->tx_urb, context->udev, pipe, (unsigned char *)control_req, context->usb_tx_buf, sizeof(context->usb_tx_buf), usb_tx_callback, context); @@ -562,7 +593,7 @@ struct device_attribute *attr, char *buf) { - struct imon_context *context = dev_get_drvdata(d); + struct imon_context *context = input_get_drvdata(d); if (!context) return -ENODEV; @@ -587,7 +618,7 @@ { struct imon_context *context; - context = dev_get_drvdata(d); + context = input_get_drvdata(d); if (!context) return -ENODEV; @@ -761,7 +792,6 @@ UNLOCK_CONTEXT; return (retval == SUCCESS) ? n_bytes : retval; } - /** * Callback function for USB core API: transmit data */ @@ -814,8 +844,14 @@ context->rx.initial_space = 1; context->rx.prev_bit = 0; - usb_fill_int_urb(context->rx_urb, context->dev, - usb_rcvintpipe(context->dev, + /* init pad context for pad2keys */ + 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->udev, + usb_rcvintpipe(context->udev, context->rx_endpoint->bEndpointAddress), context->usb_rx_buf, sizeof(context->usb_rx_buf), usb_rx_callback, context, context->rx_endpoint->bInterval); @@ -963,6 +999,135 @@ if (context->ir_onboard_decode) { /* The signals have been decoded onboard the iMON controller */ + + if (pad2keys_active) + { + /* imon pad2keys patch + * + * make PAD and mouse buttons available for use with VDR, + * based on pad-mouse-emu patch from venky's forum + * + * last change: M.Brakemeier 2007-10-14 + * + * generated PAD key codes: + * Mouse_N 0x690281B7 + * Mouse_S 0x688291B7 + * Mouse_W 0x6A8281B7 + * Mouse_E 0x688A81B7 + * + * mouse buttons (non-synthetic): + * MouseRightClick 0x688481B7 + * MouseLeftClick 0x688301B7 + */ + + if(((buf[0] & 0x40) && !(context->mode_kbd && ((buf[1] & 0x01) || ((buf[1] >> 2) & 0x01)))) + /* mouse move or one of mouse buttons is pressed */ + || (!context->mode_kbd && ((buf[0] == 0x28) && ((buf[1] == 0x87) || (buf[1] == 0x93)) && (buf[2] == 0x95)))) + /* one of channel buttons (which emulates scrollwheel) is pressed */ + { + 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; + + if(context->mode_kbd) { + + /* keyboard direction key emulation */ + if( context->last_count > 32 ) + { /* Hopefully eliminate drift*/ + context->last_count=0; + context->key_y=0; + context->key_x=0; + } + context->last_count++; + + /* limit decoded events */ + 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 s */ + buf[0] = 0x68; + buf[1] = 0x82; + buf[2] = 0x91; + } + else if(context->key_y < 0 && rel_y < 0) + { /* mouse n */ + buf[0] = 0x69; + buf[1] = 0x02; + buf[2] = 0x81; + } + } + else + { /* mouse e/w*/ + if(context->key_x > 0 && rel_x > 0 ) + { /* mouse e */ + buf[0] = 0x68; + buf[1] = 0x8A; + buf[2] = 0x81; + } + else if(context->key_x < 0 && rel_x < 0 ) + { /* mouse w */ + buf[0] = 0x6A; + buf[1] = 0x82; + buf[2] = 0x81; + } + } + } + else + { + context->key_x += rel_x; + context->key_y += rel_y; + + return; /* discard those key codes */ + } + } + else + { + /* mouse emulation */ + int direction = 0; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) + struct input_dev *idev = &context->idev; +#else + struct input_dev *idev = context->idev; +#endif + if((buf[0] == 0x28) && (buf[1] == 0x93) && (buf[2] == 0x95) && (buf[3] == 0xb7)) + direction = 1; + if((buf[0] == 0x28) && (buf[1] == 0x87) && (buf[2] == 0x95) && (buf[3] == 0xb7)) + direction = -1; + + if (!direction) { + + input_report_key(idev, BTN_LEFT, buf[1] & 0x01); + input_report_key(idev, BTN_RIGHT, (buf[1] >> 2) & 0x01); + input_report_rel(idev, REL_Y, rel_y + rel_y / 2); + input_report_rel(idev, REL_X, rel_x + rel_x / 2); + } + else{ + input_report_rel(idev, REL_WHEEL, direction); + } + + input_sync(idev); + return; + } + } + } + /* 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 */ + 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; @@ -1049,7 +1214,6 @@ } - /** * Callback function for USB core API: Probe */ @@ -1057,12 +1221,12 @@ static int imon_probe(struct usb_interface *interface, const struct usb_device_id *id) #else -static void *imon_probe(struct usb_device *dev, unsigned int intf, +static void *imon_probe(struct usb_device *udev, unsigned int intf, const struct usb_device_id *id) #endif { #ifdef KERNEL_2_5 - struct usb_device *dev = NULL; + struct usb_device *udev = NULL; struct usb_host_interface *iface_desc = NULL; #else struct usb_interface *interface = NULL; @@ -1111,11 +1275,11 @@ #endif #ifdef KERNEL_2_5 - dev = usb_get_dev(interface_to_usbdev(interface)); + udev = interface_to_usbdev(interface); iface_desc = interface->cur_altsetting; num_endpoints = iface_desc->desc.bNumEndpoints; #else - interface = &dev->actconfig->interface[intf]; + interface = &udev->actconfig->interface[intf]; iface_desc = &interface->altsetting[interface->act_altsetting]; num_endpoints = iface_desc->bNumEndpoints; #endif @@ -1268,7 +1432,7 @@ plugin->set_use_inc = ir_open; plugin->set_use_dec = ir_close; #ifdef LIRC_HAVE_SYSFS - plugin->dev = &dev->dev; + plugin->dev = &udev->dev; #endif plugin->owner = THIS_MODULE; @@ -1287,7 +1451,9 @@ /* Needed while unregistering! */ plugin->minor = lirc_minor; - context->dev = dev; + context->udev = udev; + input_set_drvdata(udev, context); + context->dev_present = TRUE; context->rx_endpoint = rx_endpoint; context->rx_urb = rx_urb; @@ -1302,7 +1468,7 @@ #ifdef KERNEL_2_5 usb_set_intfdata(interface, context); - if (cpu_to_le16(dev->descriptor.idProduct) == 0xffdc) { + if (cpu_to_le16(udev->descriptor.idProduct) == 0xffdc) { int err; err = sysfs_create_group(&interface->dev.kobj, @@ -1338,8 +1504,41 @@ #endif } + /* register with kernel input system for PAD mouse */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) + context->idev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + context->idev.keybit(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); + context->idev.relbit[0] =[LONG BIT(REL_X) | BIT(REL_Y); + context->idev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA); + context->idev.relbit[0] |= BIT(REL_WHEEL); + context->idev.private = context; + + context->idev.id.bustype = BUS_USB; + context->idev.id.vendor = le16_to_cpu(dev->descriptor.idVendor); + context->idev.id.product = le16_to_cpu(dev->descriptor.idProduct); + context->idev.id.version = le16_to_cpu(dev->descriptor.bcdDevice); + context->idev.udev = &udev->dev; + + input_register_device(&context->idev); +#else + context->idev = input_allocate_device(); + if (!context->idev) + return -ENOMEM; + + context->idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); + context->idev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE); + context->idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); + context->idev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA); + context->idev->relbit[0] |= BIT_MASK(REL_WHEEL); + context->idev->id.bustype = BUS_USB; + context->idev->id.vendor = le16_to_cpu(udev->descriptor.idVendor); + context->idev->id.product = le16_to_cpu(udev->descriptor.idProduct); + context->idev->id.version = le16_to_cpu(udev->descriptor.bcdDevice); + context->idev->dev.parent = &udev->dev; + input_register_device(context->idev); +#endif info("%s: iMON device on usb<%d:%d> initialized", - __FUNCTION__, dev->bus->busnum, dev->devnum); + __FUNCTION__, udev->bus->busnum, udev->devnum); UNLOCK_CONTEXT; @@ -1380,7 +1579,7 @@ #ifdef KERNEL_2_5 static void imon_disconnect(struct usb_interface *interface) #else -static void imon_disconnect(struct usb_device *dev, void *data) +static void imon_disconnect(struct usb_device *udev, void *data) #endif { struct imon_context *context; @@ -1429,6 +1628,11 @@ devfs_unregister(context->devfs); #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) + input_unregister_device (&context ->idev); +#else + input_unregister_device (context ->idev); +#endif UNLOCK_CONTEXT; if (!context->ir_isopen && !context->vfd_isopen)