V4L/DVB (9168): Add support for MSI TV@nywhere Plus remote

The IR controller has a couple quirks. It won't respond until some other
device on the bus is probed. To work around that, probe 0x50 first.
Then, since it won't respond to a zero-byte read, probe with a one-byte
read.

Signed-off-by: Brian Rogers <brian_rogers@comcast.net>
[mchehab.redhat.com: Fix merge conflicts and remove an unused var]
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Brian Rogers 2008-10-13 08:37:06 -03:00 committed by Mauro Carvalho Chehab
parent fa405d7094
commit ba340b40a5
6 changed files with 186 additions and 3 deletions

View file

@ -517,7 +517,8 @@ EXPORT_SYMBOL_GPL(ir_codes_adstech_dvb_t_pci);
/* ---------------------------------------------------------------------- */
/* 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,
@ -551,6 +552,95 @@ 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@stuffedcow.net>
Some changes to formatting and keycodes by Mark Schultz <n9xmj@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);
/* ---------------------------------------------------------------------- */
/* Cinergy 1400 DVB-T */
IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE] = {
[ 0x01 ] = KEY_POWER,

View file

@ -12,6 +12,10 @@
* 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
@ -242,9 +246,15 @@ static void ir_timer(unsigned long data)
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));
}
/* ----------------------------------------------------------------------- */
@ -483,9 +493,37 @@ static int ir_probe(struct i2c_adapter *adap)
(1 == rc) ? "yes" : "no");
if (1 == rc) {
ir_attach(adap, probe[i], 0, 0);
break;
return 0;
}
}
/* 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;
}

View file

@ -5969,6 +5969,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_PINNACLE_PCTV_110i:
case SAA7134_BOARD_PINNACLE_PCTV_310i:
case SAA7134_BOARD_UPMOST_PURPLE_TV:
case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS:
case SAA7134_BOARD_HAUPPAUGE_HVR1110:
case SAA7134_BOARD_BEHOLD_607_9FM:
case SAA7134_BOARD_BEHOLD_M6:

View file

@ -337,6 +337,7 @@ static int attach_inform(struct i2c_client *client)
case 0x47:
case 0x71:
case 0x2d:
case 0x30:
{
struct IR_i2c *ir = i2c_get_clientdata(client);
d1printk("%s i2c IR detected (%s).\n",

View file

@ -118,6 +118,53 @@ static int build_key(struct saa7134_dev *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 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 != i2c_master_recv(&ir->c, &b, 1)) {
i2cdprintk("read error\n");
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)
{
unsigned char b;
@ -641,6 +688,11 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
ir->get_key = get_key_purpletv;
ir->ir_codes = ir_codes_purpletv;
break;
case SAA7134_BOARD_MSI_TVATANYWHERE_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;
case SAA7134_BOARD_HAUPPAUGE_HVR1110:
snprintf(ir->c.name, sizeof(ir->c.name), "HVR 1110");
ir->get_key = get_key_hvr1110;

View file

@ -156,6 +156,7 @@ extern IR_KEYTAB_TYPE ir_codes_powercolor_real_angel[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_avermedia_a16d[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_encore_enltv_fm53[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_real_audio_220_32_keys[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_msi_tvanywhere_plus[IR_KEYTAB_SIZE];
#endif
/*