Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Brian Rogers and committed by
Mauro Carvalho Chehab
ba340b40 fa405d70

+186 -3
+91 -1
drivers/media/common/ir-keymaps.c
··· 517 517 518 518 /* ---------------------------------------------------------------------- */ 519 519 520 - /* MSI TV@nywhere remote */ 520 + /* MSI TV@nywhere MASTER remote */ 521 + 521 522 IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE] = { 522 523 /* Keys 0 to 9 */ 523 524 [ 0x00 ] = KEY_0, ··· 549 548 }; 550 549 551 550 EXPORT_SYMBOL_GPL(ir_codes_msi_tvanywhere); 551 + 552 + /* ---------------------------------------------------------------------- */ 553 + 554 + /* 555 + Keycodes for remote on the MSI TV@nywhere Plus. The controller IC on the card 556 + is marked "KS003". The controller is I2C at address 0x30, but does not seem 557 + to respond to probes until a read is performed from a valid device. 558 + I don't know why... 559 + 560 + Note: This remote may be of similar or identical design to the 561 + Pixelview remote (?). The raw codes and duplicate button codes 562 + appear to be the same. 563 + 564 + Henry Wong <henry@stuffedcow.net> 565 + Some changes to formatting and keycodes by Mark Schultz <n9xmj@yahoo.com> 566 + 567 + */ 568 + 569 + IR_KEYTAB_TYPE ir_codes_msi_tvanywhere_plus[IR_KEYTAB_SIZE] = { 570 + 571 + /* ---- Remote Button Layout ---- 572 + 573 + POWER SOURCE SCAN MUTE 574 + TV/FM 1 2 3 575 + |> 4 5 6 576 + <| 7 8 9 577 + ^^UP 0 + RECALL 578 + vvDN RECORD STOP PLAY 579 + 580 + MINIMIZE ZOOM 581 + 582 + CH+ 583 + VOL- VOL+ 584 + CH- 585 + 586 + SNAPSHOT MTS 587 + 588 + << FUNC >> RESET 589 + */ 590 + 591 + [0x01] = KEY_KP1, /* 1 */ 592 + [0x0b] = KEY_KP2, /* 2 */ 593 + [0x1b] = KEY_KP3, /* 3 */ 594 + [0x05] = KEY_KP4, /* 4 */ 595 + [0x09] = KEY_KP5, /* 5 */ 596 + [0x15] = KEY_KP6, /* 6 */ 597 + [0x06] = KEY_KP7, /* 7 */ 598 + [0x0a] = KEY_KP8, /* 8 */ 599 + [0x12] = KEY_KP9, /* 9 */ 600 + [0x02] = KEY_KP0, /* 0 */ 601 + [0x10] = KEY_KPPLUS, /* + */ 602 + [0x13] = KEY_AGAIN, /* Recall */ 603 + 604 + [0x1e] = KEY_POWER, /* Power */ 605 + [0x07] = KEY_TUNER, /* Source */ 606 + [0x1c] = KEY_SEARCH, /* Scan */ 607 + [0x18] = KEY_MUTE, /* Mute */ 608 + 609 + [0x03] = KEY_RADIO, /* TV/FM */ 610 + /* The next four keys are duplicates that appear to send the 611 + same IR code as Ch+, Ch-, >>, and << . The raw code assigned 612 + to them is the actual code + 0x20 - they will never be 613 + detected as such unless some way is discovered to distinguish 614 + these buttons from those that have the same code. */ 615 + [0x3f] = KEY_RIGHT, /* |> and Ch+ */ 616 + [0x37] = KEY_LEFT, /* <| and Ch- */ 617 + [0x2c] = KEY_UP, /* ^^Up and >> */ 618 + [0x24] = KEY_DOWN, /* vvDn and << */ 619 + 620 + [0x00] = KEY_RECORD, /* Record */ 621 + [0x08] = KEY_STOP, /* Stop */ 622 + [0x11] = KEY_PLAY, /* Play */ 623 + 624 + [0x0f] = KEY_CLOSE, /* Minimize */ 625 + [0x19] = KEY_ZOOM, /* Zoom */ 626 + [0x1a] = KEY_SHUFFLE, /* Snapshot */ 627 + [0x0d] = KEY_LANGUAGE, /* MTS */ 628 + 629 + [0x14] = KEY_VOLUMEDOWN, /* Vol- */ 630 + [0x16] = KEY_VOLUMEUP, /* Vol+ */ 631 + [0x17] = KEY_CHANNELDOWN, /* Ch- */ 632 + [0x1f] = KEY_CHANNELUP, /* Ch+ */ 633 + 634 + [0x04] = KEY_REWIND, /* << */ 635 + [0x0e] = KEY_MENU, /* Function */ 636 + [0x0c] = KEY_FASTFORWARD, /* >> */ 637 + [0x1d] = KEY_RESTART, /* Reset */ 638 + }; 639 + EXPORT_SYMBOL_GPL(ir_codes_msi_tvanywhere_plus); 552 640 553 641 /* ---------------------------------------------------------------------- */ 554 642
+40 -2
drivers/media/video/ir-kbd-i2c.c
··· 12 12 * Markus Rechberger <mrechberger@gmail.com> 13 13 * modified for DViCO Fusion HDTV 5 RT GOLD by 14 14 * Chaogui Zhang <czhang1974@gmail.com> 15 + * modified for MSI TV@nywhere Plus by 16 + * Henry Wong <henry@stuffedcow.net> 17 + * Mark Schultz <n9xmj@yahoo.com> 18 + * Brian Rogers <brian_rogers@comcast.net> 15 19 * 16 20 * This program is free software; you can redistribute it and/or modify 17 21 * it under the terms of the GNU General Public License as published by ··· 246 242 static void ir_work(struct work_struct *work) 247 243 { 248 244 struct IR_i2c *ir = container_of(work, struct IR_i2c, work); 245 + int polling_interval = 100; 246 + 247 + /* MSI TV@nywhere Plus requires more frequent polling 248 + otherwise it will miss some keypresses */ 249 + if (ir->c.adapter->id == I2C_HW_SAA7134 && ir->c.addr == 0x30) 250 + polling_interval = 50; 249 251 250 252 ir_key_poll(ir); 251 - mod_timer(&ir->timer, jiffies + msecs_to_jiffies(100)); 253 + mod_timer(&ir->timer, jiffies + msecs_to_jiffies(polling_interval)); 252 254 } 253 255 254 256 /* ----------------------------------------------------------------------- */ ··· 493 483 (1 == rc) ? "yes" : "no"); 494 484 if (1 == rc) { 495 485 ir_attach(adap, probe[i], 0, 0); 496 - break; 486 + return 0; 497 487 } 498 488 } 489 + 490 + /* Special case for MSI TV@nywhere Plus remote */ 491 + if (adap->id == I2C_HW_SAA7134) { 492 + u8 temp; 493 + 494 + /* MSI TV@nywhere Plus controller doesn't seem to 495 + respond to probes unless we read something from 496 + an existing device. Weird... */ 497 + 498 + msg.addr = 0x50; 499 + rc = i2c_transfer(adap, &msg, 1); 500 + dprintk(1, "probe 0x%02x @ %s: %s\n", 501 + msg.addr, adap->name, 502 + (1 == rc) ? "yes" : "no"); 503 + 504 + /* Now do the probe. The controller does not respond 505 + to 0-byte reads, so we use a 1-byte read instead. */ 506 + msg.addr = 0x30; 507 + msg.len = 1; 508 + msg.buf = &temp; 509 + rc = i2c_transfer(adap, &msg, 1); 510 + dprintk(1, "probe 0x%02x @ %s: %s\n", 511 + msg.addr, adap->name, 512 + (1 == rc) ? "yes" : "no"); 513 + if (1 == rc) 514 + ir_attach(adap, msg.addr, 0, 0); 515 + } 516 + 499 517 return 0; 500 518 } 501 519
+1
drivers/media/video/saa7134/saa7134-cards.c
··· 5969 5969 case SAA7134_BOARD_PINNACLE_PCTV_110i: 5970 5970 case SAA7134_BOARD_PINNACLE_PCTV_310i: 5971 5971 case SAA7134_BOARD_UPMOST_PURPLE_TV: 5972 + case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS: 5972 5973 case SAA7134_BOARD_HAUPPAUGE_HVR1110: 5973 5974 case SAA7134_BOARD_BEHOLD_607_9FM: 5974 5975 case SAA7134_BOARD_BEHOLD_M6:
+1
drivers/media/video/saa7134/saa7134-i2c.c
··· 337 337 case 0x47: 338 338 case 0x71: 339 339 case 0x2d: 340 + case 0x30: 340 341 { 341 342 struct IR_i2c *ir = i2c_get_clientdata(client); 342 343 d1printk("%s i2c IR detected (%s).\n",
+52
drivers/media/video/saa7134/saa7134-input.c
··· 118 118 119 119 /* --------------------- Chip specific I2C key builders ----------------- */ 120 120 121 + static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key, 122 + u32 *ir_raw) 123 + { 124 + unsigned char b; 125 + int gpio; 126 + 127 + /* <dev> is needed to access GPIO. Used by the saa_readl macro. */ 128 + struct saa7134_dev *dev = ir->c.adapter->algo_data; 129 + if (dev == NULL) { 130 + dprintk("get_key_msi_tvanywhere_plus: " 131 + "gir->c.adapter->algo_data is NULL!\n"); 132 + return -EIO; 133 + } 134 + 135 + /* rising SAA7134_GPIO_GPRESCAN reads the status */ 136 + 137 + saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); 138 + saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); 139 + 140 + gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2); 141 + 142 + /* GPIO&0x40 is pulsed low when a button is pressed. Don't do 143 + I2C receive if gpio&0x40 is not low. */ 144 + 145 + if (gpio & 0x40) 146 + return 0; /* No button press */ 147 + 148 + /* GPIO says there is a button press. Get it. */ 149 + 150 + if (1 != i2c_master_recv(&ir->c, &b, 1)) { 151 + i2cdprintk("read error\n"); 152 + return -EIO; 153 + } 154 + 155 + /* No button press */ 156 + 157 + if (b == 0xff) 158 + return 0; 159 + 160 + /* Button pressed */ 161 + 162 + dprintk("get_key_msi_tvanywhere_plus: Key = 0x%02X\n", b); 163 + *ir_key = b; 164 + *ir_raw = b; 165 + return 1; 166 + } 167 + 121 168 static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) 122 169 { 123 170 unsigned char b; ··· 687 640 snprintf(ir->c.name, sizeof(ir->c.name), "Purple TV"); 688 641 ir->get_key = get_key_purpletv; 689 642 ir->ir_codes = ir_codes_purpletv; 643 + break; 644 + case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS: 645 + snprintf(ir->c.name, sizeof(ir->c.name), "MSI TV@nywhere Plus"); 646 + ir->get_key = get_key_msi_tvanywhere_plus; 647 + ir->ir_codes = ir_codes_msi_tvanywhere_plus; 690 648 break; 691 649 case SAA7134_BOARD_HAUPPAUGE_HVR1110: 692 650 snprintf(ir->c.name, sizeof(ir->c.name), "HVR 1110");
+1
include/media/ir-common.h
··· 156 156 extern IR_KEYTAB_TYPE ir_codes_avermedia_a16d[IR_KEYTAB_SIZE]; 157 157 extern IR_KEYTAB_TYPE ir_codes_encore_enltv_fm53[IR_KEYTAB_SIZE]; 158 158 extern IR_KEYTAB_TYPE ir_codes_real_audio_220_32_keys[IR_KEYTAB_SIZE]; 159 + extern IR_KEYTAB_TYPE ir_codes_msi_tvanywhere_plus[IR_KEYTAB_SIZE]; 159 160 #endif 160 161 161 162 /*