|
@@ -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);
|
|
|
}
|