[linux-dvb] [patch] MSI TV@nywhere Plus IR remote support

Mark Schultz n9xmj at yahoo.com
Sat Oct 28 08:25:07 CEST 2006


Note regarding this patch: A few of the changes outlined below are
strictly formatting, prettification and "disambiguation" to ensure that
the MSI TV at nywhere MASTER is not confused with the TV at nywhere PLUS (two
completely different boards).  The bulk of the changes are those that
were inspired by orignal work done by Henry Wong, which I adapted
(largely unchanged) to the current codebase.

Shortly after posting my intention to apply this patch, I noted a
(recent) message on this list from the original author asking, in
effect, what had happened to his contribution.  It would seem as if
Henry was making his inquiry just about the same time as I was
re-implementing his work.  If Henry would prefer to drive the process
of submission, I will gladly step aside, as all this is somewhat new to
me - I have some experience as a programmer, but this is my first
attempt at participation in a public open-source project.

As I have an up-and-running linux box (SUSE 10.1 w/2.6.16.21-0.25 stock
kernel) with a MSI TV at nywhere Plus card installed (and working!) I
would be happy to serve as a testbed for patches relevant to this
board.

Without further ado, here's the diff:

diff -r 18a778dbf540 linux/drivers/media/common/ir-keymaps.c
--- a/linux/drivers/media/common/ir-keymaps.c	Sat Oct 14 12:21:02 2006
-0700
+++ b/linux/drivers/media/common/ir-keymaps.c	Sun Oct 15 20:19:54 2006
-0700
@@ -424,7 +424,8 @@ EXPORT_SYMBOL_GPL(ir_codes_adstech_dvb_t
 
 /*
----------------------------------------------------------------------
*/
 
-/* MSI TV at nywhere remote */
+/* MSI TV at nywhere MASTER remote */
+
 IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE] = {
 	/* Keys 0 to 9 */
 	[ 0x00 ] = KEY_0,
@@ -440,8 +441,8 @@ IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[I
 
 	[ 0x0c ] = KEY_MUTE,
 	[ 0x0f ] = KEY_SCREEN,		/* Full Screen */
-	[ 0x10 ] = KEY_F,			/* Funtion */
-	[ 0x11 ] = KEY_T,			/* Time shift */
+	[ 0x10 ] = KEY_F,		/* Funtion */
+	[ 0x11 ] = KEY_T,		/* Time shift */
 	[ 0x12 ] = KEY_POWER,
 	[ 0x13 ] = KEY_MEDIA,		/* MTS */
 	[ 0x14 ] = KEY_SLOW,
@@ -455,6 +456,95 @@ IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[I
 };
 
 EXPORT_SYMBOL_GPL(ir_codes_msi_tvanywhere);
+
+/*
----------------------------------------------------------------------
*/
+
+/* 
+  Keycodes for remote on the MSI TV at nywhere Plus. The controller IC on
the card
+  is marked "KS003". The controller is I2C at address 0x30, but does
not seem
+  to respond to probes until a read is performed from a valid device.
+  I don't know why...
+
+  Note: This remote may be of similar or identical design to the 
+  Pixelview remote (?).  The raw codes and duplicate button codes
+  appear to be the same.
+
+  Henry Wong <henry at stuffedcow.net>
+  Some changes to formatting and keycodes by Mark Schultz
<n9xmj at yahoo.com>
+*/
+
+IR_KEYTAB_TYPE ir_codes_msi_tvanywhere_plus[IR_KEYTAB_SIZE] = {
+
+/*  ---- Remote Button Layout ----
+
+    POWER   SOURCE  SCAN    MUTE    
+    TV/FM   1       2       3
+    |>      4       5       6
+    <|      7       8       9
+    ^^UP    0       +       RECALL
+    vvDN    RECORD  STOP    PLAY
+
+        MINIMIZE          ZOOM
+	
+                  CH+
+      VOL-                   VOL+
+                  CH-
+
+        SNAPSHOT           MTS
+	
+     <<      FUNC    >>     RESET
+*/
+
+	[ 0x01 ] = KEY_KP1,		/* 1 */
+	[ 0x0B ] = KEY_KP2,		/* 2 */
+	[ 0x1B ] = KEY_KP3,		/* 3 */
+	[ 0x05 ] = KEY_KP4,		/* 4 */
+	[ 0x09 ] = KEY_KP5,		/* 5 */
+	[ 0x15 ] = KEY_KP6,		/* 6 */
+	[ 0x06 ] = KEY_KP7,		/* 7 */
+	[ 0x0A ] = KEY_KP8,		/* 8 */
+	[ 0x12 ] = KEY_KP9,		/* 9 */
+	[ 0x02 ] = KEY_KP0,		/* 0 */
+	[ 0x10 ] = KEY_KPPLUS,		/* + */
+	[ 0x13 ] = KEY_AGAIN,		/* Recall */
+
+ 	[ 0x1E ] = KEY_POWER,		/* Power */
+	[ 0x07 ] = KEY_TUNER,		/* Source */
+	[ 0x1C ] = KEY_SEARCH,		/* Scan */
+	[ 0x18 ] = KEY_MUTE,		/* Mute */
+
+	[ 0x03 ] = KEY_RADIO,		/* TV/FM */
+	/* The next four keys are duplicates that appear to send the
+           same IR code as Ch+, Ch-, >>, and << .  The raw code
assigned
+           to them is the actual code + 0x20 - they will never be
+           detected as such unless some way is discovered to
distinguish
+           these buttons from those that have the same code. */
+	[ 0x3F ] = KEY_RIGHT,		/* |> and Ch+ */
+	[ 0x37 ] = KEY_LEFT,		/* <| and Ch- */
+	[ 0x2C ] = KEY_UP,		/* ^^Up and >> */
+	[ 0x24 ] = KEY_DOWN,		/* vvDn and << */
+
+	[ 0x00 ] = KEY_RECORD,		/* Record */
+	[ 0x08 ] = KEY_STOP,		/* Stop */
+ 	[ 0x11 ] = KEY_PLAY,		/* Play */
+
+	[ 0x0F ] = KEY_CLOSE,		/* Minimize */
+	[ 0x19 ] = KEY_ZOOM,		/* Zoom */
+	[ 0x1A ] = KEY_SHUFFLE,		/* Snapshot */
+	[ 0x0D ] = KEY_LANGUAGE,	/* MTS */
+
+	[ 0x14 ] = KEY_VOLUMEDOWN,	/* Vol- */
+	[ 0x16 ] = KEY_VOLUMEUP,	/* Vol+ */
+	[ 0x17 ] = KEY_CHANNELDOWN,	/* Ch- */
+	[ 0x1F ] = KEY_CHANNELUP,	/* Ch+ */
+
+	[ 0x04 ] = KEY_REWIND,		/* << */
+	[ 0x0E ] = KEY_MENU,		/* Function */
+	[ 0x0C ] = KEY_FASTFORWARD,	/* >> */
+	[ 0x1D ] = KEY_RESTART,		/* Reset */
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_msi_tvanywhere_plus);
 
 /*
----------------------------------------------------------------------
*/
 
diff -r 18a778dbf540 linux/drivers/media/video/ir-kbd-i2c.c
--- a/linux/drivers/media/video/ir-kbd-i2c.c	Sat Oct 14 12:21:02 2006
-0700
+++ b/linux/drivers/media/video/ir-kbd-i2c.c	Sun Oct 15 18:34:05 2006
-0700
@@ -10,6 +10,9 @@
  *      Ulrich Mueller <ulrich.mueller42 at web.de>
  * modified for em2820 based USB TV tuners by
  *      Markus Rechberger <mrechberger at gmail.com>
+ * modified for MSI TV at nywhere Plus by
+ *      Henry Wong <henry at stuffedcow.net>
+ *      Mark Schultz <n9xmj at yahoo.com>
  *
  *  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
@@ -60,6 +63,8 @@ MODULE_PARM_DESC(hauppauge, "Specify Hau
 #define dprintk(level, fmt, arg...)	if (debug >= level) \
 	printk(KERN_DEBUG DEVNAME ": " fmt , ## arg)
 
+static int polling_interval = 100;	/* Milliseconds */
+
 /*
-----------------------------------------------------------------------
*/
 
 static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
@@ -249,16 +254,16 @@ static void ir_key_poll(struct IR_i2c *i
 	static u32 ir_key, ir_raw;
 	int rc;
 
-	dprintk(2,"ir_poll_key\n");
 	rc = ir->get_key(ir, &ir_key, &ir_raw);
 	if (rc < 0) {
-		dprintk(2,"error\n");
+		dprintk(2,"Error\n");
 		return;
 	}
 
 	if (0 == rc) {
 		ir_input_nokey(ir->input, &ir->ir);
 	} else {
+		dprintk(2,"Keycode = 0x%02X\n", ir_key);
 		ir_input_keydown(ir->input, &ir->ir, ir_key, ir_raw);
 	}
 }
@@ -273,7 +278,7 @@ static void ir_work(void *data)
 {
 	struct IR_i2c *ir = data;
 	ir_key_poll(ir);
-	mod_timer(&ir->timer, jiffies+HZ/10);
+	mod_timer(&ir->timer, jiffies + polling_interval*HZ/1000);
 }
 
 /*
-----------------------------------------------------------------------
*/
@@ -361,6 +366,8 @@ static int ir_attach(struct i2c_adapter 
 		ir->get_key = get_key_knc1;
 		ir_type     = IR_TYPE_OTHER;
 		ir_codes    = ir_codes_empty;
+		if (adap->id == I2C_HW_SAA7134) /* Handled by saa7134-input */
+			polling_interval = 50;  /* mS */
 		break;
 	case 0x7a:
 	case 0x47:
@@ -448,7 +455,7 @@ static int ir_probe(struct i2c_adapter *
 	*/
 
 	static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1};
-	static const int probe_saa7134[] = { 0x7a, 0x47, -1 };
+	static const int probe_saa7134[] = { 0x7a, 0x47, 0x30, -1 };
 	static const int probe_em28XX[] = { 0x30, 0x47, -1 };
 	const int *probe = NULL;
 	struct i2c_client c;
@@ -476,7 +483,38 @@ static int ir_probe(struct i2c_adapter *
 	c.adapter = adap;
 	for (i = 0; -1 != probe[i]; i++) {
 		c.addr = probe[i];
-		rc = i2c_master_recv(&c,&buf,0);
+	
+		/* Special case for MSI TV at nywhere Plus remote */
+
+		if (c.adapter->id == I2C_HW_SAA7134 && probe[i] == 0x30)
+		{
+			struct i2c_client c2;
+			memset (&c2, 0, sizeof(c2));
+			c2.adapter = c.adapter;
+
+			/* MSI TV at nywhere Plus controller doesn't seem to
+			   respond to probes unless we read something from 
+			   an existing device. Weird... */
+
+			/* Find a device that responds. If none found, oh well. */
+
+			for (c2.addr = 0x7F; c2.addr > 0; c2.addr--)
+			{
+				if (0 == i2c_master_recv(&c2,&buf,0))
+					break;
+			}
+
+			/* Now do the probe. The controller does not respond
+			   to 0-byte reads, so we use a 1-byte read instead. */
+
+			rc = i2c_master_recv(&c,&buf,1);
+			rc--;
+		}
+		else
+		{
+			rc = i2c_master_recv(&c,&buf,0);
+		}
+
 		dprintk(1,"probe 0x%02x @ %s: %s\n",
 			probe[i], adap->name,
 			(0 == rc) ? "yes" : "no");
diff -r 18a778dbf540 linux/drivers/media/video/saa7134/saa7134-cards.c
--- a/linux/drivers/media/video/saa7134/saa7134-cards.c	Sat Oct 14
12:21:02 2006 -0700
+++ b/linux/drivers/media/video/saa7134/saa7134-cards.c	Fri Oct 27
22:58:17 2006 -0700
@@ -2561,7 +2561,7 @@ struct saa7134_board saa7134_boards[] = 
 			.gpio   = 0x0200000,
 		},
 	},
-	[SAA7134_BOARD_MSI_TVATANYWHERE_PLUS] = {
+	[SAA7134_BOARD_MSI_TVANYWHERE_PLUS] = {
 		.name           = "MSI TV at Anywhere plus",
 		.audio_clock    = 0x00187de7,
 		.tuner_type     = TUNER_PHILIPS_TDA8290,
@@ -3606,8 +3606,14 @@ struct pci_device_id saa7134_pci_tbl[] =
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
 		.subvendor    = 0x1462,
-		.subdevice    = 0x6231,
-		.driver_data  = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS,
+		.subdevice    = 0x6231,  /* Original */
+		.driver_data  = SAA7134_BOARD_MSI_TVANYWHERE_PLUS,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1462,
+		.subdevice    = 0x8624,  /* Alternate devid, same board? */
+		.driver_data  = SAA7134_BOARD_MSI_TVANYWHERE_PLUS,
 	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
@@ -3960,6 +3966,7 @@ int saa7134_board_init1(struct saa7134_d
 	case SAA7134_BOARD_PINNACLE_PCTV_110i:
 	case SAA7134_BOARD_PINNACLE_PCTV_310i:
 	case SAA7134_BOARD_UPMOST_PURPLE_TV:
+	case SAA7134_BOARD_MSI_TVANYWHERE_PLUS:
 		dev->has_remote = SAA7134_REMOTE_I2C;
 		break;
 	case SAA7134_BOARD_AVERMEDIA_A169_B:
diff -r 18a778dbf540 linux/drivers/media/video/saa7134/saa7134-i2c.c
--- a/linux/drivers/media/video/saa7134/saa7134-i2c.c	Sat Oct 14
12:21:02 2006 -0700
+++ b/linux/drivers/media/video/saa7134/saa7134-i2c.c	Sun Oct 15
00:04:22 2006 -0700
@@ -351,6 +351,7 @@ static int attach_inform(struct i2c_clie
 	switch (client->addr) {
 		case 0x7a:
 		case 0x47:
+		case 0x30:
 		{
 			struct IR_i2c *ir = i2c_get_clientdata(client);
 			d1printk("%s i2c IR detected (%s).\n",
diff -r 18a778dbf540 linux/drivers/media/video/saa7134/saa7134-input.c
--- a/linux/drivers/media/video/saa7134/saa7134-input.c	Sat Oct 14
12:21:02 2006 -0700
+++ b/linux/drivers/media/video/saa7134/saa7134-input.c	Fri Oct 27
22:59:29 2006 -0700
@@ -89,6 +89,52 @@ static int build_key(struct saa7134_dev 
 }
 
 /* --------------------- Chip specific I2C key builders
----------------- */
+
+static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key,
u32 *ir_raw)
+{
+	unsigned char b;
+	int rc;
+	int gpio;
+
+	/* <dev> is needed to access GPIO. Used by the saa_readl macro. */
+	struct saa7134_dev *dev = ir->c.adapter->algo_data;
+	if (dev == NULL) {
+		dprintk ("get_key_msi_tvanywhere_plus: gir->c.adapter->algo_data is
NULL!\n");
+		return -EIO;
+	}
+
+	/* rising SAA7134_GPIO_GPRESCAN reads the status */
+
+	saa_clearb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN);
+	saa_setb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN);
+
+	gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
+
+	/* GPIO&0x40 is pulsed low when a button is pressed. Don't do
+	   I2C receive if gpio&0x40 is not low. */
+
+	if (gpio & 0x40) 
+		return 0;	/* No button press */
+
+	/* GPIO says there is a button press. Get it. */
+
+	if (1 != (rc=i2c_master_recv(&ir->c,&b,1))) {
+		dprintk("get_key_msi_tvanywhere_plus: read error %d\n", rc);
+		return -EIO;
+	}
+
+	/* No button press */
+
+	if (b == 0xFF)
+		return 0;
+	
+	/* Button pressed */
+
+	dprintk ("get_key_msi_tvanywhere_plus: Key = 0x%02X\n", b);
+	*ir_key = b;
+	*ir_raw = b;
+	return 1;
+}
 
 static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32
*ir_raw)
 {
@@ -336,10 +382,10 @@ void saa7134_set_i2c_ir(struct saa7134_d
 	case SAA7134_BOARD_PINNACLE_PCTV_110i:
 		snprintf(ir->c.name, sizeof(ir->c.name), "Pinnacle PCTV");
 		if (pinnacle_remote == 0) {
-			ir->get_key   = get_key_pinnacle_color;
+			ir->get_key  = get_key_pinnacle_color;
 			ir->ir_codes = ir_codes_pinnacle_color;
 		} else {
-			ir->get_key   = get_key_pinnacle_grey;
+			ir->get_key  = get_key_pinnacle_grey;
 			ir->ir_codes = ir_codes_pinnacle_grey;
 		}
 		break;
@@ -347,6 +393,11 @@ void saa7134_set_i2c_ir(struct saa7134_d
 		snprintf(ir->c.name, sizeof(ir->c.name), "Purple TV");
 		ir->get_key   = get_key_purpletv;
 		ir->ir_codes  = ir_codes_purpletv;
+		break;
+	case SAA7134_BOARD_MSI_TVANYWHERE_PLUS:
+		snprintf(ir->c.name, sizeof(ir->c.name), "MSI TV at nywhere Plus");
+		ir->get_key  = get_key_msi_tvanywhere_plus;
+		ir->ir_codes = ir_codes_msi_tvanywhere_plus;
 		break;
 	default:
 		dprintk("Shouldn't get here: Unknown board %x for I2C
IR?\n",dev->board);
diff -r 18a778dbf540 linux/drivers/media/video/saa7134/saa7134.h
--- a/linux/drivers/media/video/saa7134/saa7134.h	Sat Oct 14 12:21:02
2006 -0700
+++ b/linux/drivers/media/video/saa7134/saa7134.h	Fri Oct 27 22:56:24
2006 -0700
@@ -217,7 +217,7 @@ struct saa7134_format {
 #define SAA7134_BOARD_SEDNA_PC_TV_CARDBUS     79
 #define SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV 80
 #define SAA7134_BOARD_PHILIPS_TIGER  81
-#define SAA7134_BOARD_MSI_TVATANYWHERE_PLUS  82
+#define SAA7134_BOARD_MSI_TVANYWHERE_PLUS  82
 #define SAA7134_BOARD_CINERGY250PCI 83
 #define SAA7134_BOARD_FLYDVB_TRIO 84
 #define SAA7134_BOARD_AVERMEDIA_777 85
diff -r 18a778dbf540 linux/include/media/ir-common.h
--- a/linux/include/media/ir-common.h	Sat Oct 14 12:21:02 2006 -0700
+++ b/linux/include/media/ir-common.h	Sun Oct 15 08:06:25 2006 -0700
@@ -92,6 +92,7 @@ extern IR_KEYTAB_TYPE ir_codes_npgtech[I
 extern IR_KEYTAB_TYPE ir_codes_npgtech[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_norwood[IR_KEYTAB_SIZE];
 extern IR_KEYTAB_TYPE ir_codes_proteus_2309[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_msi_tvanywhere_plus[IR_KEYTAB_SIZE];
 
 #endif
 




More information about the linux-dvb mailing list