* Markus Rechberger <mrechberger@gmail.com>
* modified for DViCO Fusion HDTV 5 RT GOLD by
* Chaogui Zhang <czhang1974@gmail.com>
+ * modified for MSI TV@nywhere Plus by
+ * Henry Wong <henry@stuffedcow.net>
+ * Mark Schultz <n9xmj@yahoo.com>
+ * Brian Rogers <brian_rogers@comcast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
int size, int offset)
{
unsigned char buf[6];
- int start, range, toggle, dev, code;
+ int start, range, toggle, dev, code, ircode;
/* poll IR chip */
if (size != i2c_master_recv(&ir->c,buf,size))
if (!start)
/* no key pressed */
return 0;
+ /*
+ * Hauppauge remotes (black/silver) always use
+ * specific device ids. If we do not filter the
+ * device ids then messages destined for devices
+ * such as TVs (id=0) will get through causing
+ * mis-fired events.
+ *
+ * We also filter out invalid key presses which
+ * produce annoying debug log entries.
+ */
+ ircode= (start << 12) | (toggle << 11) | (dev << 6) | code;
+ if ((ircode & 0x1fff)==0x1fff)
+ /* invalid key press */
+ return 0;
+
+ if (dev!=0x1e && dev!=0x1f)
+ /* not a hauppauge remote */
+ return 0;
if (!range)
code += 64;
/* return key */
*ir_key = code;
- *ir_raw = (start << 12) | (toggle << 11) | (dev << 6) | code;
+ *ir_raw = ircode;
return 1;
}
}
if(buf[0] !=0 || buf[1] !=0 || buf[2] !=0 || buf[3] != 0)
- dprintk(2, "%s: 0x%2x 0x%2x 0x%2x 0x%2x\n", __FUNCTION__,
+ dprintk(2, "%s: 0x%2x 0x%2x 0x%2x 0x%2x\n", __func__,
buf[0], buf[1], buf[2], buf[3]);
/* no key pressed or signal from other ir remote */
return 1;
}
-/* Common (grey or coloured) pinnacle PCTV remote handling
- *
- */
-static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
- int parity_offset, int marker, int code_modulo)
-{
- unsigned char b[4];
- unsigned int start = 0,parity = 0,code = 0;
-
- /* poll IR chip */
- if (4 != i2c_master_recv(&ir->c,b,4)) {
- dprintk(2,"read error\n");
- return -EIO;
- }
-
- for (start = 0; start < ARRAY_SIZE(b); start++) {
- if (b[start] == marker) {
- code=b[(start+parity_offset+1)%4];
- parity=b[(start+parity_offset)%4];
- }
- }
-
- /* Empty Request */
- if (parity==0)
- return 0;
-
- /* Repeating... */
- if (ir->old == parity)
- return 0;
-
- ir->old = parity;
-
- /* drop special codes when a key is held down a long time for the grey controller
- In this case, the second bit of the code is asserted */
- if (marker == 0xfe && (code & 0x40))
- return 0;
-
- code %= code_modulo;
-
- *ir_raw = code;
- *ir_key = code;
-
- dprintk(1,"Pinnacle PCTV key %02x\n", code);
-
- return 1;
-}
-
-/* The grey pinnacle PCTV remote
- *
- * There are one issue with this remote:
- * - I2c packet does not change when the same key is pressed quickly. The workaround
- * is to hold down each key for about half a second, so that another code is generated
- * in the i2c packet, and the function can distinguish key presses.
- *
- * Sylvain Pasche <sylvain.pasche@gmail.com>
- */
-int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
-{
-
- return get_key_pinnacle(ir, ir_key, ir_raw, 1, 0xfe, 0xff);
-}
-
-EXPORT_SYMBOL_GPL(get_key_pinnacle_grey);
-
-
-/* The new pinnacle PCTV remote (with the colored buttons)
- *
- * Ricardo Cerqueira <v4l@cerqueira.org>
- */
-int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
-{
- /* code_modulo parameter (0x88) is used to reduce code value to fit inside IR_KEYTAB_SIZE
- *
- * this is the only value that results in 42 unique
- * codes < 128
- */
-
- return get_key_pinnacle(ir, ir_key, ir_raw, 2, 0x80, 0x88);
-}
-
-EXPORT_SYMBOL_GPL(get_key_pinnacle_color);
-
/* ----------------------------------------------------------------------- */
static void ir_key_poll(struct IR_i2c *ir)
static void ir_work(struct work_struct *work)
{
struct IR_i2c *ir = container_of(work, struct IR_i2c, work);
+ int polling_interval = 100;
+
+ /* MSI TV@nywhere Plus requires more frequent polling
+ otherwise it will miss some keypresses */
+ if (ir->c.adapter->id == I2C_HW_SAA7134 && ir->c.addr == 0x30)
+ polling_interval = 50;
ir_key_poll(ir);
- mod_timer(&ir->timer, jiffies + msecs_to_jiffies(100));
+ mod_timer(&ir->timer, jiffies + msecs_to_jiffies(polling_interval));
}
/* ----------------------------------------------------------------------- */
goto err_out_detach;
}
- /* Phys addr can only be set after attaching (for ir->c.dev.bus_id) */
+ /* Phys addr can only be set after attaching (for ir->c.dev) */
snprintf(ir->phys, sizeof(ir->phys), "%s/%s/ir0",
- ir->c.adapter->dev.bus_id,
- ir->c.dev.bus_id);
+ dev_name(&ir->c.adapter->dev),
+ dev_name(&ir->c.dev));
/* init + register input device */
ir_input_init(input_dev, &ir->ir, ir_type, ir->ir_codes);
static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 };
static const int probe_cx23885[] = { 0x6b, -1 };
const int *probe;
- struct i2c_client *c;
- unsigned char buf;
+ struct i2c_msg msg = {
+ .flags = I2C_M_RD,
+ .len = 0,
+ .buf = NULL,
+ };
int i, rc;
switch (adap->id) {
return 0;
}
- c = kzalloc(sizeof(*c), GFP_KERNEL);
- if (!c)
- return -ENOMEM;
-
- c->adapter = adap;
for (i = 0; -1 != probe[i]; i++) {
- c->addr = probe[i];
- rc = i2c_master_recv(c, &buf, 0);
+ msg.addr = probe[i];
+ rc = i2c_transfer(adap, &msg, 1);
dprintk(1,"probe 0x%02x @ %s: %s\n",
probe[i], adap->name,
- (0 == rc) ? "yes" : "no");
- if (0 == rc) {
+ (1 == rc) ? "yes" : "no");
+ if (1 == rc) {
ir_attach(adap, probe[i], 0, 0);
- break;
+ return 0;
}
}
- kfree(c);
+
+ /* Special case for MSI TV@nywhere Plus remote */
+ if (adap->id == I2C_HW_SAA7134) {
+ u8 temp;
+
+ /* MSI TV@nywhere Plus controller doesn't seem to
+ respond to probes unless we read something from
+ an existing device. Weird... */
+
+ msg.addr = 0x50;
+ rc = i2c_transfer(adap, &msg, 1);
+ dprintk(1, "probe 0x%02x @ %s: %s\n",
+ msg.addr, adap->name,
+ (1 == rc) ? "yes" : "no");
+
+ /* Now do the probe. The controller does not respond
+ to 0-byte reads, so we use a 1-byte read instead. */
+ msg.addr = 0x30;
+ msg.len = 1;
+ msg.buf = &temp;
+ rc = i2c_transfer(adap, &msg, 1);
+ dprintk(1, "probe 0x%02x @ %s: %s\n",
+ msg.addr, adap->name,
+ (1 == rc) ? "yes" : "no");
+ if (1 == rc)
+ ir_attach(adap, msg.addr, 0, 0);
+ }
+
return 0;
}