V4L/DVB (4023): Subject: Pinnacle PCTV grey remote control support
This adds support for the older (?) Pinnacle PCTV remotes (with all buttons
colored in grey). There's no autodetection for the type of remote, though;
saa7134 defaults to the colored one, to use the grey remote the
"pinnacle_remote=1" option must be passed to the saa7134 module
Signed-off-by: Sylvain Pasche <sylvain.pasche@gmail.com>
Signed-off-by: Ricardo Cerqueira <v4l@cerqueira.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
index fab97f4..8f4a067 100644
--- a/drivers/media/common/ir-keymaps.c
+++ b/drivers/media/common/ir-keymaps.c
@@ -618,7 +618,7 @@
EXPORT_SYMBOL_GPL(ir_codes_em_terratec);
-IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE] = {
+IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE] = {
[ 0x3a ] = KEY_0,
[ 0x31 ] = KEY_1,
[ 0x32 ] = KEY_2,
@@ -670,7 +670,7 @@
[ 0x27 ] = KEY_RECORD,
};
-EXPORT_SYMBOL_GPL(ir_codes_em_pinnacle_usb);
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle_grey);
IR_KEYTAB_TYPE ir_codes_flyvideo[IR_KEYTAB_SIZE] = {
[ 0x0f ] = KEY_0,
@@ -1290,7 +1290,7 @@
EXPORT_SYMBOL_GPL(ir_codes_winfast);
-IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
+IR_KEYTAB_TYPE ir_codes_pinnacle_color[IR_KEYTAB_SIZE] = {
[ 0x59 ] = KEY_MUTE,
[ 0x4a ] = KEY_POWER,
@@ -1348,7 +1348,7 @@
[ 0x0a ] = KEY_BACKSPACE,
};
-EXPORT_SYMBOL_GPL(ir_codes_pinnacle);
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle_color);
/* Hauppauge: the newer, gray remotes (seems there are multiple
* slightly different versions), shipped with cx88+ivtv cards.
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 86aff37..3ffb568 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -105,7 +105,7 @@
return 1;
}
-static int get_key_pinnacle_usb(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
unsigned char buf[3];
@@ -148,8 +148,8 @@
snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Terratec)");
break;
case (EM2820_BOARD_PINNACLE_USB_2):
- ir->ir_codes = ir_codes_em_pinnacle_usb;
- ir->get_key = get_key_pinnacle_usb;
+ ir->ir_codes = ir_codes_pinnacle_grey;
+ ir->get_key = get_key_pinnacle_usb_grey;
snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Pinnacle PCTV)");
break;
case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 7e66d83..fba30a4 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -150,12 +150,11 @@
return 1;
}
-/* The new pinnacle PCTV remote (with the colored buttons)
+/* Common (grey or coloured) pinnacle PCTV remote handling
*
- * Ricardo Cerqueira <v4l@cerqueira.org>
*/
-
-int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+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;
@@ -167,9 +166,9 @@
}
for (start = 0; start<4; start++) {
- if (b[start] == 0x80) {
- code=b[(start+3)%4];
- parity=b[(start+2)%4];
+ if (b[start] == marker) {
+ code=b[(start+parity_offset+1)%4];
+ parity=b[(start+parity_offset)%4];
}
}
@@ -181,16 +180,14 @@
if (ir->old == parity)
return 0;
-
ir->old = parity;
- /* Reduce code value to fit inside IR_KEYTAB_SIZE
- *
- * this is the only value that results in 42 unique
- * codes < 128
- */
+ /* 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 %= 0x88;
+ code %= code_modulo;
*ir_raw = code;
*ir_key = code;
@@ -200,7 +197,40 @@
return 1;
}
-EXPORT_SYMBOL_GPL(get_key_pinnacle);
+/* 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);
/* ----------------------------------------------------------------------- */
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 1426e4c..7c59549 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -37,6 +37,10 @@
module_param(ir_debug, int, 0644);
MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
+static int pinnacle_remote = 0;
+module_param(pinnacle_remote, int, 0644); /* Choose Pinnacle PCTV remote */
+MODULE_PARM_DESC(pinnacle_remote, "Specify Pinnacle PCTV remote: 0=coloured, 1=grey (defaults to 0)");
+
#define dprintk(fmt, arg...) if (ir_debug) \
printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
#define i2cdprintk(fmt, arg...) if (ir_debug) \
@@ -316,8 +320,13 @@
switch (dev->board) {
case SAA7134_BOARD_PINNACLE_PCTV_110i:
snprintf(ir->c.name, sizeof(ir->c.name), "Pinnacle PCTV");
- ir->get_key = get_key_pinnacle;
- ir->ir_codes = ir_codes_pinnacle;
+ if (pinnacle_remote == 0) {
+ ir->get_key = get_key_pinnacle_color;
+ ir->ir_codes = ir_codes_pinnacle_color;
+ } else {
+ ir->get_key = get_key_pinnacle_grey;
+ ir->ir_codes = ir_codes_pinnacle_grey;
+ }
break;
case SAA7134_BOARD_UPMOST_PURPLE_TV:
snprintf(ir->c.name, sizeof(ir->c.name), "Purple TV");
diff --git a/include/media/ir-common.h b/include/media/ir-common.h
index 302d5b3..f0beace 100644
--- a/include/media/ir-common.h
+++ b/include/media/ir-common.h
@@ -73,7 +73,7 @@
extern IR_KEYTAB_TYPE ir_codes_avertv_303[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_dntv_live_dvbt_pro[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_flyvideo[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_flydvb[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_cinergy[IR_KEYTAB_SIZE];
@@ -87,7 +87,7 @@
extern IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_pinnacle_color[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE];
#endif
diff --git a/include/media/ir-kbd-i2c.h b/include/media/ir-kbd-i2c.h
index 730f21e..a455f7c 100644
--- a/include/media/ir-kbd-i2c.h
+++ b/include/media/ir-kbd-i2c.h
@@ -20,5 +20,6 @@
int (*get_key)(struct IR_i2c*, u32*, u32*);
};
-int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
+int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
+int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
#endif