Note regarding this patch: A few of the changes outlined below are strictly formatting, prettification and "disambiguation" to ensure that the MSI TV@nywhere MASTER is not confused with the TV@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@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@nywhere remote */ +/* MSI TV@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@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@xxxxxxxxxxxxxx> + Some changes to formatting and keycodes by Mark Schultz <n9xmj@xxxxxxxxx> +*/ + +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@xxxxxx> * modified for em2820 based USB TV tuners by * Markus Rechberger <mrechberger@xxxxxxxxx> + * modified for MSI TV@nywhere Plus by + * Henry Wong <henry@xxxxxxxxxxxxxx> + * Mark Schultz <n9xmj@xxxxxxxxx> * * 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@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@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@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@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 _______________________________________________ linux-dvb mailing list linux-dvb@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb