--- lirc.orig/drivers/lirc_imon/lirc_imon.c 2008-01-19 05:06:46.000000000 -0500 +++ lirc/drivers/lirc_imon/lirc_imon.c 2008-03-30 21:25:18.000000000 -0400 @@ -82,11 +82,13 @@ S_IRGRP | S_IWGRP | S_IROTH) #define DEVFS_NAME LIRC_DEVFS_PREFIX "lcd%d" -#define BUF_CHUNK_SIZE 4 +#define BUF_CHUNK_SIZE 8 #define BUF_SIZE 128 #define BIT_DURATION 250 /* each bit received is 250us */ +#define IMON_LCD_NEXTGEN 0x0038 /* The 0x0038 device requires control urbs */ + #define SUCCESS 0 #define TRUE 1 #define FALSE 0 @@ -162,6 +164,7 @@ struct usb_endpoint_descriptor *tx_endpoint; struct urb *rx_urb; struct urb *tx_urb; + int tx_control; /* if 1, will use a control msg urb */ unsigned char usb_rx_buf[8]; unsigned char usb_tx_buf[8]; @@ -196,6 +199,7 @@ { USB_DEVICE(0x0aa8, 0x8001) }, /* IR only */ { USB_DEVICE(0x15c2, 0xffda) }, /* IR & VFD */ { USB_DEVICE(0x15c2, 0xffdc) }, /* IR & VFD */ + { USB_DEVICE(0x15c2, 0x0038) }, /* IR & LCD */ { USB_DEVICE(0x04e8, 0xff30) }, /* ext IR only */ {} }; @@ -212,6 +216,7 @@ static unsigned short ir_onboard_decode_product_list[] = { /* terminate this list with a 0 */ 0xffdc, + 0x0038, 0 }; /* USB Device data */ @@ -431,17 +436,31 @@ int interval = 0; int retval = SUCCESS; - pipe = usb_sndintpipe(context->dev, + /* Check if we need to use control or interrupt urb */ + if ( context->tx_control == 0 ) + { + pipe = usb_sndintpipe(context->dev, context->tx_endpoint->bEndpointAddress); #ifdef KERNEL_2_5 - interval = context->tx_endpoint->bInterval; + interval = context->tx_endpoint->bInterval; #endif /* Use 0 for 2.4 kernels */ - usb_fill_int_urb(context->tx_urb, context->dev, pipe, - context->usb_tx_buf, sizeof(context->usb_tx_buf), - usb_tx_callback, context, interval); + usb_fill_int_urb(context->tx_urb, context->dev, pipe, + context->usb_tx_buf, sizeof(context->usb_tx_buf), + usb_tx_callback, context, interval); - context->tx_urb->actual_length = 0; + context->tx_urb->actual_length = 0; + } else { + /* setup packet is '21 09 0200 0001 0008' */ + unsigned char setup_packet[8] = { 0x21, 0x09, 0x02, 0x00, 0x00, 0x01, 0x00, 0x08 }; + /* control pipe is endpoint 0x00 */ + pipe = usb_sndctrlpipe(context->dev, 0); + /* build the control urb */ + usb_fill_control_urb(context->tx_urb, context->dev, pipe, setup_packet, + context->usb_tx_buf, sizeof(context->usb_tx_buf), + usb_tx_callback, context); + context->tx_urb->actual_length = 0; + } init_completion(&context->tx.finished); atomic_set(&(context->tx.busy), 1); @@ -874,6 +893,36 @@ int i; #endif + //we need to add some special handling for the imon 0038's IR mouse events + if ((len == 5) && (buf[0] == 0x01) && (buf[4] == 0x00)) { + //first, pad it to 8 bytes so it conforms with everything else + buf[5] = buf[6] = buf[7] = 0; + len = 8; + + /*the imon directional pad functions more like a touchpad. Bytes 3 & 4 + * contain a position coordinate (x,y), with each component ranging + * from -14 to 14. Since this doesn't cooperate well with the way lirc + * works (it would appear to lirc as more than 100 different buttons) + * we need to map it to 4 discrete values. Also, when you get too close + * to diagonals, it has a tendancy to jump back and forth, so lets try + * to ignore when they get too close */ + if ((buf[1] == 0) && ((buf[2] != 0) || (buf[3] != 0))) + { + int y = (int)(char)buf[2]; + int x = (int)(char)buf[3]; + if (abs(abs(x) - abs(y)) < 3) { + return; + } else if (abs(y) > abs(x)) { + buf[2] = 0x00; + buf[3] = (y > 0) ? 0x7f : 0x80; + } else { + buf[3] = 0x00; + buf[2] = (x > 0) ? 0x7f : 0x80; + }; + }; + + } + if (len != 8) { warn("%s: invalid incoming packet size(%d)", __FUNCTION__, len); @@ -1036,6 +1085,7 @@ int alloc_status; int vfd_proto_6p = FALSE; int ir_onboard_decode = FALSE; + int tx_control = 0; struct imon_context *context = NULL; int i; @@ -1111,6 +1161,17 @@ } } + /* If we didn't find a vfd endpoint, and we have a next-gen LCD, + * use control urb instead of interrupt + */ + if (! vfd_ep_found && cpu_to_le16(dev->descriptor.idProduct) == IMON_LCD_NEXTGEN ) + { + tx_control = 1; + vfd_ep_found = TRUE; + if (debug) + info("%s: guessing that LCD (0x0038) device uses control endpoint, not interface OUT endpoint", __FUNCTION__); + } + /* Input endpoint is mandatory */ if (!ir_ep_found) { err("%s: no valid input(IR) endpoint found.", __FUNCTION__); @@ -1215,7 +1276,7 @@ strcpy(plugin->name, MOD_NAME); plugin->minor = -1; plugin->code_length = (ir_onboard_decode) ? - 32 : sizeof(lirc_t) * 8; + 64 : sizeof(lirc_t) * 8; plugin->sample_rate = 0; plugin->features = (ir_onboard_decode) ? LIRC_CAN_REC_LIRCCODE : LIRC_CAN_REC_MODE2; @@ -1272,6 +1333,7 @@ context->vfd_supported = TRUE; context->tx_endpoint = tx_endpoint; context->tx_urb = tx_urb; + context->tx_control = tx_control; } context->plugin = plugin;