From: Jarod Wilson Date: Fri, 23 Apr 2010 05:27:11 +0000 (-0300) Subject: V4L/DVB: IR/imon: convert to ir-core protocol change handling X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=6718e8ad950f73fc895b98a413a63cb2add3b4d2;p=linux-beck.git V4L/DVB: IR/imon: convert to ir-core protocol change handling Drop the imon driver's internal protocol definitions in favor of using those provided by ir-core. Should make ir-keytable Just Work for switching protocol on the fly on the imon devices that support both the native imon remotes and mce remotes. The imon-no-pad-stabilize pseudo-protocol was dropped as a protocol, and converted to a separate modprobe option (which it probably should have been in the first place). On the TODO list is to convert this to an as yet unwritten protocol-specific options framework. While the mce remotes obviously map to IR_TYPE_RC6, I've yet to look at what the actual ir signals from the native imon remotes are, so for the moment, imon native ir is mapped to IR_TYPE_OTHER. Nailing it down more accurately is also on the TODO list. Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- diff --git a/drivers/media/IR/imon.c b/drivers/media/IR/imon.c index d941b98eed3e..b65c31ab4a4f 100644 --- a/drivers/media/IR/imon.c +++ b/drivers/media/IR/imon.c @@ -127,8 +127,7 @@ struct imon_context { u32 kc; /* current input keycode */ u32 last_keycode; /* last reported input keycode */ - u8 ir_protocol; /* iMON or MCE (RC6) IR protocol? */ - u8 ir_proto_mask; /* supported IR protocol mask */ + u64 ir_type; /* iMON or MCE (RC6) IR protocol? */ u8 mce_toggle_bit; /* last mce toggle bit */ bool release_code; /* some keys send a release code */ @@ -173,20 +172,6 @@ enum { IMON_DISPLAY_TYPE_NONE = 4, }; -enum { - IMON_IR_PROTOCOL_AUTO = 0x0, - IMON_IR_PROTOCOL_MCE = 0x1, - IMON_IR_PROTOCOL_IMON = 0x2, - IMON_IR_PROTOCOL_IMON_NOPAD = 0x4, -}; - -enum { - IMON_IR_PROTO_MASK_NONE = 0x0, - IMON_IR_PROTO_MASK_MCE = IMON_IR_PROTOCOL_MCE, - IMON_IR_PROTO_MASK_IMON = IMON_IR_PROTOCOL_IMON | - IMON_IR_PROTOCOL_IMON_NOPAD, -}; - enum { IMON_KEY_IMON = 0, IMON_KEY_MCE = 1, @@ -330,12 +315,10 @@ module_param(display_type, int, S_IRUGO); MODULE_PARM_DESC(display_type, "Type of attached display. 0=autodetect, " "1=vfd, 2=lcd, 3=vga, 4=none (default: autodetect)"); -/* IR protocol: native iMON, Windows MCE (RC-6), or iMON w/o PAD stabilize */ -static int ir_protocol; -module_param(ir_protocol, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(ir_protocol, "Which IR protocol to use. 0=auto-detect, " - "1=Windows Media Center Ed. (RC-6), 2=iMON native, " - "4=iMON w/o PAD stabilize (default: auto-detect)"); +static int pad_stabilize = 1; +module_param(pad_stabilize, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(pad_stabilize, "Apply stabilization algorithm to iMON PAD " + "presses in arrow key mode. 0=disable, 1=enable (default)."); /* * In certain use cases, mouse mode isn't really helpful, and could actually @@ -1007,72 +990,67 @@ static void imon_touch_display_timeout(unsigned long data) * really just RC-6), but only one or the other at a time, as the signals * are decoded onboard the receiver. */ -static void imon_set_ir_protocol(struct imon_context *ictx) +int imon_ir_change_protocol(void *priv, u64 ir_type) { int retval; + struct imon_context *ictx = priv; struct device *dev = ictx->dev; + bool pad_mouse; unsigned char ir_proto_packet[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 }; - if (ir_protocol && !(ir_protocol & ictx->ir_proto_mask)) + if (!(ir_type & ictx->props->allowed_protos)) dev_warn(dev, "Looks like you're trying to use an IR protocol " "this device does not support\n"); - switch (ir_protocol) { - case IMON_IR_PROTOCOL_AUTO: - if (ictx->product == 0xffdc) { - if (ictx->ir_proto_mask & IMON_IR_PROTO_MASK_MCE) { - ir_proto_packet[0] = 0x01; - ictx->ir_protocol = IMON_IR_PROTOCOL_MCE; - ictx->pad_mouse = 0; - init_timer(&ictx->itimer); - ictx->itimer.data = (unsigned long)ictx; - ictx->itimer.function = imon_mce_timeout; - } else { - ictx->ir_protocol = IMON_IR_PROTOCOL_IMON; - ictx->pad_mouse = 1; - } - } - break; - case IMON_IR_PROTOCOL_MCE: + switch (ir_type) { + case IR_TYPE_RC6: dev_dbg(dev, "Configuring IR receiver for MCE protocol\n"); ir_proto_packet[0] = 0x01; - ictx->ir_protocol = IMON_IR_PROTOCOL_MCE; - ictx->pad_mouse = 0; + pad_mouse = false; init_timer(&ictx->itimer); ictx->itimer.data = (unsigned long)ictx; ictx->itimer.function = imon_mce_timeout; break; - case IMON_IR_PROTOCOL_IMON: - dev_dbg(dev, "Configuring IR receiver for iMON protocol\n"); - /* ir_proto_packet[0] = 0x00; // already the default */ - ictx->ir_protocol = IMON_IR_PROTOCOL_IMON; - ictx->pad_mouse = 1; - break; - case IMON_IR_PROTOCOL_IMON_NOPAD: - dev_dbg(dev, "Configuring IR receiver for iMON protocol " - "without PAD stabilize function enabled\n"); + case IR_TYPE_UNKNOWN: + case IR_TYPE_OTHER: + dev_dbg(dev, "Configuring IR receiver for iMON protocol"); + if (pad_stabilize) { + printk(KERN_CONT "\n"); + pad_mouse = true; + } else { + printk(KERN_CONT " (without PAD stabilization)\n"); + pad_mouse = false; + } /* ir_proto_packet[0] = 0x00; // already the default */ - ictx->ir_protocol = IMON_IR_PROTOCOL_IMON_NOPAD; - ictx->pad_mouse = 0; + ir_type = IR_TYPE_OTHER; break; default: - dev_info(dev, "%s: unknown IR protocol specified, will " - "just default to iMON protocol\n", __func__); - ictx->ir_protocol = IMON_IR_PROTOCOL_IMON; - ictx->pad_mouse = 1; + dev_warn(dev, "Unsupported IR protocol specified, overriding " + "to iMON IR protocol"); + if (pad_stabilize) { + printk(KERN_CONT "\n"); + pad_mouse = true; + } else { + printk(KERN_CONT " (without PAD stabilization)\n"); + pad_mouse = false; + } + /* ir_proto_packet[0] = 0x00; // already the default */ + ir_type = IR_TYPE_OTHER; break; } memcpy(ictx->usb_tx_buf, &ir_proto_packet, sizeof(ir_proto_packet)); retval = send_packet(ictx); - if (retval) { - dev_info(dev, "%s: failed to set IR protocol, falling back " - "to standard iMON protocol mode\n", __func__); - ir_protocol = IMON_IR_PROTOCOL_IMON; - ictx->ir_protocol = IMON_IR_PROTOCOL_IMON; - } + if (retval) + goto out; + + ictx->ir_type = ir_type; + ictx->pad_mouse = pad_mouse; + +out: + return retval; } static inline int tv2int(const struct timeval *a, const struct timeval *b) @@ -1329,7 +1307,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) rel_x = buf[2]; rel_y = buf[3]; - if (ictx->ir_protocol == IMON_IR_PROTOCOL_IMON) { + if (ictx->ir_type == IR_TYPE_OTHER && pad_stabilize) { if ((buf[1] == 0) && ((rel_x != 0) || (rel_y != 0))) { dir = stabilize((int)rel_x, (int)rel_y, timeout, threshold); @@ -1386,7 +1364,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) buf[0] = 0x01; buf[1] = buf[4] = buf[5] = buf[6] = buf[7] = 0; - if (ictx->ir_protocol == IMON_IR_PROTOCOL_IMON) { + if (ictx->ir_type == IR_TYPE_OTHER && pad_stabilize) { dir = stabilize((int)rel_x, (int)rel_y, timeout, threshold); if (!dir) { @@ -1499,7 +1477,7 @@ static void imon_incoming_packet(struct imon_context *ictx, kc = imon_panel_key_lookup(panel_key); } else { remote_key = (u32) (le64_to_cpu(temp_key) & 0xffffffff); - if (ictx->ir_protocol == IMON_IR_PROTOCOL_MCE) { + if (ictx->ir_type == IR_TYPE_RC6) { if (buf[0] == 0x80) ktype = IMON_KEY_MCE; kc = imon_mce_key_lookup(ictx, remote_key); @@ -1680,12 +1658,6 @@ static struct input_dev *imon_init_idev(struct imon_context *ictx) struct ir_dev_props *props; struct ir_input_dev *ir; int ret, i; - char *ir_codes = NULL; - - if (ir_protocol == IMON_IR_PROTOCOL_MCE) - ir_codes = RC_MAP_IMON_MCE; - else - ir_codes = RC_MAP_IMON_PAD; idev = input_allocate_device(); if (!idev) { @@ -1727,8 +1699,12 @@ static struct input_dev *imon_init_idev(struct imon_context *ictx) __set_bit(kc, idev->keybit); } + props->priv = ictx; props->driver_type = RC_DRIVER_SCANCODE; - props->allowed_protos = IR_TYPE_UNKNOWN; + /* IR_TYPE_OTHER maps to iMON PAD remote, IR_TYPE_RC6 to MCE remote */ + props->allowed_protos = IR_TYPE_OTHER | IR_TYPE_RC6; + props->change_protocol = imon_ir_change_protocol; + ictx->props = props; ictx->ir = ir; memcpy(&ir->dev, ictx->dev, sizeof(struct device)); @@ -1738,7 +1714,7 @@ static struct input_dev *imon_init_idev(struct imon_context *ictx) input_set_drvdata(idev, ir); - ret = ir_input_register(idev, ir_codes, props, MOD_NAME); + ret = ir_input_register(idev, RC_MAP_IMON_PAD, props, MOD_NAME); if (ret < 0) { dev_err(ictx->dev, "remote input dev register failed\n"); goto idev_register_failed; @@ -2058,13 +2034,14 @@ rx_urb_alloc_failed: * is no actual data to report. However, byte 6 of this buffer looks like * its unique across device variants, so we're trying to key off that to * figure out which display type (if any) and what IR protocol the device - * actually supports. + * actually supports. These devices have their IR protocol hard-coded into + * their firmware, they can't be changed on the fly like the newer hardware. */ static void imon_get_ffdc_type(struct imon_context *ictx) { u8 ffdc_cfg_byte = ictx->usb_rx_buf[6]; u8 detected_display_type = IMON_DISPLAY_TYPE_NONE; - u8 ir_proto_mask = IMON_IR_PROTO_MASK_IMON; + u64 allowed_protos = IR_TYPE_OTHER; switch (ffdc_cfg_byte) { /* iMON Knob, no display, iMON IR + vol knob */ @@ -2076,7 +2053,6 @@ static void imon_get_ffdc_type(struct imon_context *ictx) case 0x35: dev_info(ictx->dev, "0xffdc iMON VFD + knob, no IR"); detected_display_type = IMON_DISPLAY_TYPE_VFD; - ir_proto_mask = IMON_IR_PROTO_MASK_NONE; break; /* iMON VFD, iMON IR */ case 0x24: @@ -2088,7 +2064,7 @@ static void imon_get_ffdc_type(struct imon_context *ictx) case 0x9f: dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR"); detected_display_type = IMON_DISPLAY_TYPE_LCD; - ir_proto_mask = IMON_IR_PROTO_MASK_MCE; + allowed_protos = IR_TYPE_RC6; break; default: dev_info(ictx->dev, "Unknown 0xffdc device, " @@ -2097,10 +2073,11 @@ static void imon_get_ffdc_type(struct imon_context *ictx) break; } - printk(" (id 0x%02x)\n", ffdc_cfg_byte); + printk(KERN_CONT " (id 0x%02x)\n", ffdc_cfg_byte); ictx->display_type = detected_display_type; - ictx->ir_proto_mask = ir_proto_mask; + ictx->props->allowed_protos = allowed_protos; + ictx->ir_type = allowed_protos; } static void imon_set_display_type(struct imon_context *ictx, @@ -2255,9 +2232,6 @@ static int __devinit imon_probe(struct usb_interface *interface, if (product == 0xffdc) imon_get_ffdc_type(ictx); - else - ictx->ir_proto_mask = IMON_IR_PROTO_MASK_MCE | - IMON_IR_PROTO_MASK_IMON; imon_set_display_type(ictx, interface); @@ -2266,7 +2240,12 @@ static int __devinit imon_probe(struct usb_interface *interface, } /* set IR protocol/remote type */ - imon_set_ir_protocol(ictx); + ret = imon_ir_change_protocol(ictx, ictx->ir_type); + if (ret) { + dev_warn(dev, "%s: failed to set IR protocol, falling back " + "to standard iMON protocol mode\n", __func__); + ictx->ir_type = IR_TYPE_OTHER; + } dev_info(dev, "iMON device (%04x:%04x, intf%d) on " "usb<%d:%d> initialized\n", vendor, product, ifnum, @@ -2343,7 +2322,7 @@ static void __devexit imon_disconnect(struct usb_interface *interface) if (!ictx->display_isopen) free_imon_context(ictx); } else { - if (ictx->ir_protocol == IMON_IR_PROTOCOL_MCE) + if (ictx->ir_type == IR_TYPE_RC6) del_timer_sync(&ictx->itimer); mutex_unlock(&ictx->lock); } diff --git a/drivers/media/IR/keymaps/rc-imon-mce.c b/drivers/media/IR/keymaps/rc-imon-mce.c index 9c6dda30c649..e49f350e3a0d 100644 --- a/drivers/media/IR/keymaps/rc-imon-mce.c +++ b/drivers/media/IR/keymaps/rc-imon-mce.c @@ -119,8 +119,8 @@ static struct rc_keymap imon_mce_map = { .map = { .scan = imon_mce, .size = ARRAY_SIZE(imon_mce), - /* its actually RC6, but w/a hardware decoder */ - .ir_type = IR_TYPE_UNKNOWN, + /* its RC6, but w/a hardware decoder */ + .ir_type = IR_TYPE_RC6, .name = RC_MAP_IMON_MCE, } }; diff --git a/drivers/media/IR/keymaps/rc-imon-pad.c b/drivers/media/IR/keymaps/rc-imon-pad.c index 331ba9066b46..bc4db72f02e6 100644 --- a/drivers/media/IR/keymaps/rc-imon-pad.c +++ b/drivers/media/IR/keymaps/rc-imon-pad.c @@ -133,7 +133,8 @@ static struct rc_keymap imon_pad_map = { .map = { .scan = imon_pad, .size = ARRAY_SIZE(imon_pad), - .ir_type = IR_TYPE_UNKNOWN, + /* actual protocol details unknown, hardware decoder */ + .ir_type = IR_TYPE_OTHER, .name = RC_MAP_IMON_PAD, } };