diff options
Diffstat (limited to 'drivers/media/video/cx88/cx88-cards.c')
-rw-r--r-- | drivers/media/video/cx88/cx88-cards.c | 219 |
1 files changed, 184 insertions, 35 deletions
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 6a136ddbccf8..a4eb6a87a761 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c | |||
@@ -27,10 +27,26 @@ | |||
27 | 27 | ||
28 | #include "cx88.h" | 28 | #include "cx88.h" |
29 | 29 | ||
30 | static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; | ||
31 | static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; | ||
32 | static unsigned int card[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; | ||
33 | |||
34 | module_param_array(tuner, int, NULL, 0444); | ||
35 | module_param_array(radio, int, NULL, 0444); | ||
36 | module_param_array(card, int, NULL, 0444); | ||
37 | |||
38 | MODULE_PARM_DESC(tuner,"tuner type"); | ||
39 | MODULE_PARM_DESC(radio,"radio tuner type"); | ||
40 | MODULE_PARM_DESC(card,"card type"); | ||
41 | |||
42 | static unsigned int latency = UNSET; | ||
43 | module_param(latency,int,0444); | ||
44 | MODULE_PARM_DESC(latency,"pci latency timer"); | ||
45 | |||
30 | /* ------------------------------------------------------------------ */ | 46 | /* ------------------------------------------------------------------ */ |
31 | /* board config info */ | 47 | /* board config info */ |
32 | 48 | ||
33 | struct cx88_board cx88_boards[] = { | 49 | static const struct cx88_board cx88_boards[] = { |
34 | [CX88_BOARD_UNKNOWN] = { | 50 | [CX88_BOARD_UNKNOWN] = { |
35 | .name = "UNKNOWN/GENERIC", | 51 | .name = "UNKNOWN/GENERIC", |
36 | .tuner_type = UNSET, | 52 | .tuner_type = UNSET, |
@@ -575,35 +591,34 @@ struct cx88_board cx88_boards[] = { | |||
575 | .tuner_addr = ADDR_UNSET, | 591 | .tuner_addr = ADDR_UNSET, |
576 | .radio_addr = ADDR_UNSET, | 592 | .radio_addr = ADDR_UNSET, |
577 | .tda9887_conf = TDA9887_PRESENT, | 593 | .tda9887_conf = TDA9887_PRESENT, |
594 | /* GPIO[2] = audio source for analog audio out connector | ||
595 | * 0 = analog audio input connector | ||
596 | * 1 = CX88 audio DACs | ||
597 | * | ||
598 | * GPIO[7] = input to CX88's audio/chroma ADC | ||
599 | * 0 = FM 10.7 MHz IF | ||
600 | * 1 = Sound 4.5 MHz IF | ||
601 | * | ||
602 | * GPIO[1,5,6] = Oren 51132 pins 27,35,28 respectively | ||
603 | * | ||
604 | * GPIO[16] = Remote control input | ||
605 | */ | ||
578 | .input = {{ | 606 | .input = {{ |
579 | .type = CX88_VMUX_TELEVISION, | 607 | .type = CX88_VMUX_TELEVISION, |
580 | .vmux = 0, | 608 | .vmux = 0, |
581 | .gpio0 = 0x00008484, | 609 | .gpio0 = 0x00008484, |
582 | .gpio1 = 0x00000000, | ||
583 | .gpio2 = 0x00000000, | ||
584 | .gpio3 = 0x00000000, | ||
585 | },{ | 610 | },{ |
586 | .type = CX88_VMUX_COMPOSITE1, | 611 | .type = CX88_VMUX_COMPOSITE1, |
587 | .vmux = 1, | 612 | .vmux = 1, |
588 | .gpio0 = 0x00008400, | 613 | .gpio0 = 0x00008400, |
589 | .gpio1 = 0x00000000, | ||
590 | .gpio2 = 0x00000000, | ||
591 | .gpio3 = 0x00000000, | ||
592 | },{ | 614 | },{ |
593 | .type = CX88_VMUX_SVIDEO, | 615 | .type = CX88_VMUX_SVIDEO, |
594 | .vmux = 2, | 616 | .vmux = 2, |
595 | .gpio0 = 0x00008400, | 617 | .gpio0 = 0x00008400, |
596 | .gpio1 = 0x00000000, | ||
597 | .gpio2 = 0x00000000, | ||
598 | .gpio3 = 0x00000000, | ||
599 | }}, | 618 | }}, |
600 | .radio = { | 619 | .radio = { |
601 | .type = CX88_RADIO, | 620 | .type = CX88_RADIO, |
602 | .vmux = 2, | 621 | .gpio0 = 0x00008404, |
603 | .gpio0 = 0x00008400, | ||
604 | .gpio1 = 0x00000000, | ||
605 | .gpio2 = 0x00000000, | ||
606 | .gpio3 = 0x00000000, | ||
607 | }, | 622 | }, |
608 | .mpeg = CX88_MPEG_DVB, | 623 | .mpeg = CX88_MPEG_DVB, |
609 | }, | 624 | }, |
@@ -1356,12 +1371,11 @@ struct cx88_board cx88_boards[] = { | |||
1356 | }}, | 1371 | }}, |
1357 | }, | 1372 | }, |
1358 | }; | 1373 | }; |
1359 | const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards); | ||
1360 | 1374 | ||
1361 | /* ------------------------------------------------------------------ */ | 1375 | /* ------------------------------------------------------------------ */ |
1362 | /* PCI subsystem IDs */ | 1376 | /* PCI subsystem IDs */ |
1363 | 1377 | ||
1364 | struct cx88_subid cx88_subids[] = { | 1378 | static const struct cx88_subid cx88_subids[] = { |
1365 | { | 1379 | { |
1366 | .subvendor = 0x0070, | 1380 | .subvendor = 0x0070, |
1367 | .subdevice = 0x3400, | 1381 | .subdevice = 0x3400, |
@@ -1667,7 +1681,6 @@ struct cx88_subid cx88_subids[] = { | |||
1667 | .card = CX88_BOARD_ADSTECH_PTV_390, | 1681 | .card = CX88_BOARD_ADSTECH_PTV_390, |
1668 | }, | 1682 | }, |
1669 | }; | 1683 | }; |
1670 | const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); | ||
1671 | 1684 | ||
1672 | /* ----------------------------------------------------------------------- */ | 1685 | /* ----------------------------------------------------------------------- */ |
1673 | /* some leadtek specific stuff */ | 1686 | /* some leadtek specific stuff */ |
@@ -1688,12 +1701,12 @@ static void leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data) | |||
1688 | return; | 1701 | return; |
1689 | } | 1702 | } |
1690 | 1703 | ||
1691 | core->has_radio = 1; | 1704 | core->board.tuner_type = (eeprom_data[6] == 0x13) ? |
1692 | core->tuner_type = (eeprom_data[6] == 0x13) ? 43 : 38; | 1705 | TUNER_PHILIPS_FM1236_MK3 : TUNER_PHILIPS_FM1216ME_MK3; |
1693 | 1706 | ||
1694 | printk(KERN_INFO "%s: Leadtek Winfast 2000XP Expert config: " | 1707 | printk(KERN_INFO "%s: Leadtek Winfast 2000XP Expert config: " |
1695 | "tuner=%d, eeprom[0]=0x%02x\n", | 1708 | "tuner=%d, eeprom[0]=0x%02x\n", |
1696 | core->name, core->tuner_type, eeprom_data[0]); | 1709 | core->name, core->board.tuner_type, eeprom_data[0]); |
1697 | } | 1710 | } |
1698 | 1711 | ||
1699 | static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) | 1712 | static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) |
@@ -1701,9 +1714,9 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) | |||
1701 | struct tveeprom tv; | 1714 | struct tveeprom tv; |
1702 | 1715 | ||
1703 | tveeprom_hauppauge_analog(&core->i2c_client, &tv, eeprom_data); | 1716 | tveeprom_hauppauge_analog(&core->i2c_client, &tv, eeprom_data); |
1704 | core->tuner_type = tv.tuner_type; | 1717 | core->board.tuner_type = tv.tuner_type; |
1705 | core->tuner_formats = tv.tuner_formats; | 1718 | core->tuner_formats = tv.tuner_formats; |
1706 | core->has_radio = tv.has_radio; | 1719 | core->board.radio.type = tv.has_radio ? CX88_RADIO : 0; |
1707 | 1720 | ||
1708 | /* Make sure we support the board model */ | 1721 | /* Make sure we support the board model */ |
1709 | switch (tv.model) | 1722 | switch (tv.model) |
@@ -1793,8 +1806,9 @@ static void gdi_eeprom(struct cx88_core *core, u8 *eeprom_data) | |||
1793 | name ? name : "unknown"); | 1806 | name ? name : "unknown"); |
1794 | if (NULL == name) | 1807 | if (NULL == name) |
1795 | return; | 1808 | return; |
1796 | core->tuner_type = gdi_tuner[eeprom_data[0x0d]].id; | 1809 | core->board.tuner_type = gdi_tuner[eeprom_data[0x0d]].id; |
1797 | core->has_radio = gdi_tuner[eeprom_data[0x0d]].fm; | 1810 | core->board.radio.type = gdi_tuner[eeprom_data[0x0d]].fm ? |
1811 | CX88_RADIO : 0; | ||
1798 | } | 1812 | } |
1799 | 1813 | ||
1800 | /* ----------------------------------------------------------------------- */ | 1814 | /* ----------------------------------------------------------------------- */ |
@@ -1833,7 +1847,7 @@ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core) | |||
1833 | 1847 | ||
1834 | /* ----------------------------------------------------------------------- */ | 1848 | /* ----------------------------------------------------------------------- */ |
1835 | 1849 | ||
1836 | void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) | 1850 | static void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) |
1837 | { | 1851 | { |
1838 | int i; | 1852 | int i; |
1839 | 1853 | ||
@@ -1854,14 +1868,14 @@ void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) | |||
1854 | } | 1868 | } |
1855 | printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n", | 1869 | printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n", |
1856 | core->name); | 1870 | core->name); |
1857 | for (i = 0; i < cx88_bcount; i++) | 1871 | for (i = 0; i < ARRAY_SIZE(cx88_boards); i++) |
1858 | printk("%s: card=%d -> %s\n", | 1872 | printk("%s: card=%d -> %s\n", |
1859 | core->name, i, cx88_boards[i].name); | 1873 | core->name, i, cx88_boards[i].name); |
1860 | } | 1874 | } |
1861 | 1875 | ||
1862 | void cx88_card_setup_pre_i2c(struct cx88_core *core) | 1876 | static void cx88_card_setup_pre_i2c(struct cx88_core *core) |
1863 | { | 1877 | { |
1864 | switch (core->board) { | 1878 | switch (core->boardnr) { |
1865 | case CX88_BOARD_HAUPPAUGE_HVR1300: | 1879 | case CX88_BOARD_HAUPPAUGE_HVR1300: |
1866 | /* Bring the 702 demod up before i2c scanning/attach or devices are hidden */ | 1880 | /* Bring the 702 demod up before i2c scanning/attach or devices are hidden */ |
1867 | /* We leave here with the 702 on the bus */ | 1881 | /* We leave here with the 702 on the bus */ |
@@ -1875,7 +1889,7 @@ void cx88_card_setup_pre_i2c(struct cx88_core *core) | |||
1875 | } | 1889 | } |
1876 | } | 1890 | } |
1877 | 1891 | ||
1878 | void cx88_card_setup(struct cx88_core *core) | 1892 | static void cx88_card_setup(struct cx88_core *core) |
1879 | { | 1893 | { |
1880 | static u8 eeprom[256]; | 1894 | static u8 eeprom[256]; |
1881 | 1895 | ||
@@ -1884,7 +1898,7 @@ void cx88_card_setup(struct cx88_core *core) | |||
1884 | tveeprom_read(&core->i2c_client,eeprom,sizeof(eeprom)); | 1898 | tveeprom_read(&core->i2c_client,eeprom,sizeof(eeprom)); |
1885 | } | 1899 | } |
1886 | 1900 | ||
1887 | switch (core->board) { | 1901 | switch (core->boardnr) { |
1888 | case CX88_BOARD_HAUPPAUGE: | 1902 | case CX88_BOARD_HAUPPAUGE: |
1889 | case CX88_BOARD_HAUPPAUGE_ROSLYN: | 1903 | case CX88_BOARD_HAUPPAUGE_ROSLYN: |
1890 | if (0 == core->i2c_rc) | 1904 | if (0 == core->i2c_rc) |
@@ -1928,7 +1942,7 @@ void cx88_card_setup(struct cx88_core *core) | |||
1928 | msleep(1); | 1942 | msleep(1); |
1929 | cx_set(MO_GP0_IO, 0x00000101); | 1943 | cx_set(MO_GP0_IO, 0x00000101); |
1930 | if (0 == core->i2c_rc && | 1944 | if (0 == core->i2c_rc && |
1931 | core->board == CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID) | 1945 | core->boardnr == CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID) |
1932 | dvico_fusionhdtv_hybrid_init(core); | 1946 | dvico_fusionhdtv_hybrid_init(core); |
1933 | break; | 1947 | break; |
1934 | case CX88_BOARD_KWORLD_DVB_T: | 1948 | case CX88_BOARD_KWORLD_DVB_T: |
@@ -1966,13 +1980,148 @@ void cx88_card_setup(struct cx88_core *core) | |||
1966 | } | 1980 | } |
1967 | break; | 1981 | break; |
1968 | } | 1982 | } |
1969 | if (cx88_boards[core->board].radio.type == CX88_RADIO) | ||
1970 | core->has_radio = 1; | ||
1971 | } | 1983 | } |
1972 | 1984 | ||
1973 | /* ------------------------------------------------------------------ */ | 1985 | /* ------------------------------------------------------------------ */ |
1974 | 1986 | ||
1975 | EXPORT_SYMBOL(cx88_boards); | 1987 | static int cx88_pci_quirks(const char *name, struct pci_dev *pci) |
1988 | { | ||
1989 | unsigned int lat = UNSET; | ||
1990 | u8 ctrl = 0; | ||
1991 | u8 value; | ||
1992 | |||
1993 | /* check pci quirks */ | ||
1994 | if (pci_pci_problems & PCIPCI_TRITON) { | ||
1995 | printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n", | ||
1996 | name); | ||
1997 | ctrl |= CX88X_EN_TBFX; | ||
1998 | } | ||
1999 | if (pci_pci_problems & PCIPCI_NATOMA) { | ||
2000 | printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n", | ||
2001 | name); | ||
2002 | ctrl |= CX88X_EN_TBFX; | ||
2003 | } | ||
2004 | if (pci_pci_problems & PCIPCI_VIAETBF) { | ||
2005 | printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n", | ||
2006 | name); | ||
2007 | ctrl |= CX88X_EN_TBFX; | ||
2008 | } | ||
2009 | if (pci_pci_problems & PCIPCI_VSFX) { | ||
2010 | printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n", | ||
2011 | name); | ||
2012 | ctrl |= CX88X_EN_VSFX; | ||
2013 | } | ||
2014 | #ifdef PCIPCI_ALIMAGIK | ||
2015 | if (pci_pci_problems & PCIPCI_ALIMAGIK) { | ||
2016 | printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n", | ||
2017 | name); | ||
2018 | lat = 0x0A; | ||
2019 | } | ||
2020 | #endif | ||
2021 | |||
2022 | /* check insmod options */ | ||
2023 | if (UNSET != latency) | ||
2024 | lat = latency; | ||
2025 | |||
2026 | /* apply stuff */ | ||
2027 | if (ctrl) { | ||
2028 | pci_read_config_byte(pci, CX88X_DEVCTRL, &value); | ||
2029 | value |= ctrl; | ||
2030 | pci_write_config_byte(pci, CX88X_DEVCTRL, value); | ||
2031 | } | ||
2032 | if (UNSET != lat) { | ||
2033 | printk(KERN_INFO "%s: setting pci latency timer to %d\n", | ||
2034 | name, latency); | ||
2035 | pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency); | ||
2036 | } | ||
2037 | return 0; | ||
2038 | } | ||
2039 | |||
2040 | int cx88_get_resources(const struct cx88_core *core, struct pci_dev *pci) | ||
2041 | { | ||
2042 | if (request_mem_region(pci_resource_start(pci,0), | ||
2043 | pci_resource_len(pci,0), | ||
2044 | core->name)) | ||
2045 | return 0; | ||
2046 | printk(KERN_ERR | ||
2047 | "%s/%d: Can't get MMIO memory @ 0x%llx, subsystem: %04x:%04x\n", | ||
2048 | core->name, PCI_FUNC(pci->devfn), | ||
2049 | (unsigned long long)pci_resource_start(pci, 0), | ||
2050 | pci->subsystem_vendor, pci->subsystem_device); | ||
2051 | return -EBUSY; | ||
2052 | } | ||
2053 | |||
2054 | /* Allocate and initialize the cx88 core struct. One should hold the | ||
2055 | * devlist mutex before calling this. */ | ||
2056 | struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) | ||
2057 | { | ||
2058 | struct cx88_core *core; | ||
2059 | int i; | ||
2060 | |||
2061 | core = kzalloc(sizeof(*core), GFP_KERNEL); | ||
2062 | |||
2063 | atomic_inc(&core->refcount); | ||
2064 | core->pci_bus = pci->bus->number; | ||
2065 | core->pci_slot = PCI_SLOT(pci->devfn); | ||
2066 | core->pci_irqmask = PCI_INT_RISC_RD_BERRINT | PCI_INT_RISC_WR_BERRINT | | ||
2067 | PCI_INT_BRDG_BERRINT | PCI_INT_SRC_DMA_BERRINT | | ||
2068 | PCI_INT_DST_DMA_BERRINT | PCI_INT_IPB_DMA_BERRINT; | ||
2069 | mutex_init(&core->lock); | ||
2070 | |||
2071 | core->nr = nr; | ||
2072 | sprintf(core->name, "cx88[%d]", core->nr); | ||
2073 | if (0 != cx88_get_resources(core, pci)) { | ||
2074 | kfree(core); | ||
2075 | return NULL; | ||
2076 | } | ||
2077 | |||
2078 | /* PCI stuff */ | ||
2079 | cx88_pci_quirks(core->name, pci); | ||
2080 | core->lmmio = ioremap(pci_resource_start(pci, 0), | ||
2081 | pci_resource_len(pci, 0)); | ||
2082 | core->bmmio = (u8 __iomem *)core->lmmio; | ||
2083 | |||
2084 | /* board config */ | ||
2085 | core->boardnr = UNSET; | ||
2086 | if (card[core->nr] < ARRAY_SIZE(cx88_boards)) | ||
2087 | core->boardnr = card[core->nr]; | ||
2088 | for (i = 0; UNSET == core->boardnr && i < ARRAY_SIZE(cx88_subids); i++) | ||
2089 | if (pci->subsystem_vendor == cx88_subids[i].subvendor && | ||
2090 | pci->subsystem_device == cx88_subids[i].subdevice) | ||
2091 | core->boardnr = cx88_subids[i].card; | ||
2092 | if (UNSET == core->boardnr) { | ||
2093 | core->boardnr = CX88_BOARD_UNKNOWN; | ||
2094 | cx88_card_list(core, pci); | ||
2095 | } | ||
2096 | |||
2097 | memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board)); | ||
2098 | |||
2099 | printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", | ||
2100 | core->name,pci->subsystem_vendor, | ||
2101 | pci->subsystem_device, core->board.name, | ||
2102 | core->boardnr, card[core->nr] == core->boardnr ? | ||
2103 | "insmod option" : "autodetected"); | ||
2104 | |||
2105 | if (tuner[core->nr] != UNSET) | ||
2106 | core->board.tuner_type = tuner[core->nr]; | ||
2107 | if (radio[core->nr] != UNSET) | ||
2108 | core->board.radio_type = radio[core->nr]; | ||
2109 | |||
2110 | printk(KERN_INFO "%s: TV tuner type %d, Radio tuner type %d\n", | ||
2111 | core->name, core->board.tuner_type, core->board.radio_type); | ||
2112 | |||
2113 | /* init hardware */ | ||
2114 | cx88_reset(core); | ||
2115 | cx88_card_setup_pre_i2c(core); | ||
2116 | cx88_i2c_init(core, pci); | ||
2117 | cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL); | ||
2118 | cx88_card_setup(core); | ||
2119 | cx88_ir_init(core, pci); | ||
2120 | |||
2121 | return core; | ||
2122 | } | ||
2123 | |||
2124 | /* ------------------------------------------------------------------ */ | ||
1976 | 2125 | ||
1977 | /* | 2126 | /* |
1978 | * Local variables: | 2127 | * Local variables: |