18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for the NXP SAA7164 PCIe bridge 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "saa7164.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "tda10048.h" 118c2ecf20Sopenharmony_ci#include "tda18271.h" 128c2ecf20Sopenharmony_ci#include "s5h1411.h" 138c2ecf20Sopenharmony_ci#include "si2157.h" 148c2ecf20Sopenharmony_ci#include "si2168.h" 158c2ecf20Sopenharmony_ci#include "lgdt3306a.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define DRIVER_NAME "saa7164" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* addr is in the card struct, get it from there */ 228c2ecf20Sopenharmony_cistatic struct tda10048_config hauppauge_hvr2200_1_config = { 238c2ecf20Sopenharmony_ci .demod_address = 0x10 >> 1, 248c2ecf20Sopenharmony_ci .output_mode = TDA10048_SERIAL_OUTPUT, 258c2ecf20Sopenharmony_ci .fwbulkwritelen = TDA10048_BULKWRITE_200, 268c2ecf20Sopenharmony_ci .inversion = TDA10048_INVERSION_ON, 278c2ecf20Sopenharmony_ci .dtv6_if_freq_khz = TDA10048_IF_3300, 288c2ecf20Sopenharmony_ci .dtv7_if_freq_khz = TDA10048_IF_3500, 298c2ecf20Sopenharmony_ci .dtv8_if_freq_khz = TDA10048_IF_4000, 308c2ecf20Sopenharmony_ci .clk_freq_khz = TDA10048_CLK_16000, 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_cistatic struct tda10048_config hauppauge_hvr2200_2_config = { 338c2ecf20Sopenharmony_ci .demod_address = 0x12 >> 1, 348c2ecf20Sopenharmony_ci .output_mode = TDA10048_SERIAL_OUTPUT, 358c2ecf20Sopenharmony_ci .fwbulkwritelen = TDA10048_BULKWRITE_200, 368c2ecf20Sopenharmony_ci .inversion = TDA10048_INVERSION_ON, 378c2ecf20Sopenharmony_ci .dtv6_if_freq_khz = TDA10048_IF_3300, 388c2ecf20Sopenharmony_ci .dtv7_if_freq_khz = TDA10048_IF_3500, 398c2ecf20Sopenharmony_ci .dtv8_if_freq_khz = TDA10048_IF_4000, 408c2ecf20Sopenharmony_ci .clk_freq_khz = TDA10048_CLK_16000, 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic struct tda18271_std_map hauppauge_tda18271_std_map = { 448c2ecf20Sopenharmony_ci .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 3, 458c2ecf20Sopenharmony_ci .if_lvl = 6, .rfagc_top = 0x37 }, 468c2ecf20Sopenharmony_ci .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 0, 478c2ecf20Sopenharmony_ci .if_lvl = 6, .rfagc_top = 0x37 }, 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic struct tda18271_config hauppauge_hvr22x0_tuner_config = { 518c2ecf20Sopenharmony_ci .std_map = &hauppauge_tda18271_std_map, 528c2ecf20Sopenharmony_ci .gate = TDA18271_GATE_ANALOG, 538c2ecf20Sopenharmony_ci .role = TDA18271_MASTER, 548c2ecf20Sopenharmony_ci}; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic struct tda18271_config hauppauge_hvr22x0s_tuner_config = { 578c2ecf20Sopenharmony_ci .std_map = &hauppauge_tda18271_std_map, 588c2ecf20Sopenharmony_ci .gate = TDA18271_GATE_ANALOG, 598c2ecf20Sopenharmony_ci .role = TDA18271_SLAVE, 608c2ecf20Sopenharmony_ci .output_opt = TDA18271_OUTPUT_LT_OFF, 618c2ecf20Sopenharmony_ci .rf_cal_on_startup = 1 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic struct s5h1411_config hauppauge_s5h1411_config = { 658c2ecf20Sopenharmony_ci .output_mode = S5H1411_SERIAL_OUTPUT, 668c2ecf20Sopenharmony_ci .gpio = S5H1411_GPIO_ON, 678c2ecf20Sopenharmony_ci .qam_if = S5H1411_IF_4000, 688c2ecf20Sopenharmony_ci .vsb_if = S5H1411_IF_3250, 698c2ecf20Sopenharmony_ci .inversion = S5H1411_INVERSION_ON, 708c2ecf20Sopenharmony_ci .status_mode = S5H1411_DEMODLOCKING, 718c2ecf20Sopenharmony_ci .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic struct lgdt3306a_config hauppauge_hvr2255a_config = { 758c2ecf20Sopenharmony_ci .i2c_addr = 0xb2 >> 1, 768c2ecf20Sopenharmony_ci .qam_if_khz = 4000, 778c2ecf20Sopenharmony_ci .vsb_if_khz = 3250, 788c2ecf20Sopenharmony_ci .deny_i2c_rptr = 1, /* Disabled */ 798c2ecf20Sopenharmony_ci .spectral_inversion = 0, /* Disabled */ 808c2ecf20Sopenharmony_ci .mpeg_mode = LGDT3306A_MPEG_SERIAL, 818c2ecf20Sopenharmony_ci .tpclk_edge = LGDT3306A_TPCLK_RISING_EDGE, 828c2ecf20Sopenharmony_ci .tpvalid_polarity = LGDT3306A_TP_VALID_HIGH, 838c2ecf20Sopenharmony_ci .xtalMHz = 25, /* 24 or 25 */ 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic struct lgdt3306a_config hauppauge_hvr2255b_config = { 878c2ecf20Sopenharmony_ci .i2c_addr = 0x1c >> 1, 888c2ecf20Sopenharmony_ci .qam_if_khz = 4000, 898c2ecf20Sopenharmony_ci .vsb_if_khz = 3250, 908c2ecf20Sopenharmony_ci .deny_i2c_rptr = 1, /* Disabled */ 918c2ecf20Sopenharmony_ci .spectral_inversion = 0, /* Disabled */ 928c2ecf20Sopenharmony_ci .mpeg_mode = LGDT3306A_MPEG_SERIAL, 938c2ecf20Sopenharmony_ci .tpclk_edge = LGDT3306A_TPCLK_RISING_EDGE, 948c2ecf20Sopenharmony_ci .tpvalid_polarity = LGDT3306A_TP_VALID_HIGH, 958c2ecf20Sopenharmony_ci .xtalMHz = 25, /* 24 or 25 */ 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic struct si2157_config hauppauge_hvr2255_tuner_config = { 998c2ecf20Sopenharmony_ci .inversion = 1, 1008c2ecf20Sopenharmony_ci .if_port = 1, 1018c2ecf20Sopenharmony_ci}; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic int si2157_attach(struct saa7164_port *port, struct i2c_adapter *adapter, 1048c2ecf20Sopenharmony_ci struct dvb_frontend *fe, u8 addr8bit, struct si2157_config *cfg) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci struct i2c_board_info bi; 1078c2ecf20Sopenharmony_ci struct i2c_client *tuner; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci cfg->fe = fe; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci memset(&bi, 0, sizeof(bi)); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci strscpy(bi.type, "si2157", I2C_NAME_SIZE); 1148c2ecf20Sopenharmony_ci bi.platform_data = cfg; 1158c2ecf20Sopenharmony_ci bi.addr = addr8bit >> 1; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci request_module(bi.type); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci tuner = i2c_new_client_device(adapter, &bi); 1208c2ecf20Sopenharmony_ci if (!i2c_client_has_driver(tuner)) 1218c2ecf20Sopenharmony_ci return -ENODEV; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (!try_module_get(tuner->dev.driver->owner)) { 1248c2ecf20Sopenharmony_ci i2c_unregister_device(tuner); 1258c2ecf20Sopenharmony_ci return -ENODEV; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci port->i2c_client_tuner = tuner; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci return 0; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic int saa7164_dvb_stop_port(struct saa7164_port *port) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci struct saa7164_dev *dev = port->dev; 1368c2ecf20Sopenharmony_ci int ret; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci ret = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); 1398c2ecf20Sopenharmony_ci if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { 1408c2ecf20Sopenharmony_ci printk(KERN_ERR "%s() stop transition failed, ret = 0x%x\n", 1418c2ecf20Sopenharmony_ci __func__, ret); 1428c2ecf20Sopenharmony_ci ret = -EIO; 1438c2ecf20Sopenharmony_ci } else { 1448c2ecf20Sopenharmony_ci dprintk(DBGLVL_DVB, "%s() Stopped\n", __func__); 1458c2ecf20Sopenharmony_ci ret = 0; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci return ret; 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic int saa7164_dvb_acquire_port(struct saa7164_port *port) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci struct saa7164_dev *dev = port->dev; 1548c2ecf20Sopenharmony_ci int ret; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci ret = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE); 1578c2ecf20Sopenharmony_ci if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { 1588c2ecf20Sopenharmony_ci printk(KERN_ERR "%s() acquire transition failed, ret = 0x%x\n", 1598c2ecf20Sopenharmony_ci __func__, ret); 1608c2ecf20Sopenharmony_ci ret = -EIO; 1618c2ecf20Sopenharmony_ci } else { 1628c2ecf20Sopenharmony_ci dprintk(DBGLVL_DVB, "%s() Acquired\n", __func__); 1638c2ecf20Sopenharmony_ci ret = 0; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci return ret; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic int saa7164_dvb_pause_port(struct saa7164_port *port) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci struct saa7164_dev *dev = port->dev; 1728c2ecf20Sopenharmony_ci int ret; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci ret = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE); 1758c2ecf20Sopenharmony_ci if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) { 1768c2ecf20Sopenharmony_ci printk(KERN_ERR "%s() pause transition failed, ret = 0x%x\n", 1778c2ecf20Sopenharmony_ci __func__, ret); 1788c2ecf20Sopenharmony_ci ret = -EIO; 1798c2ecf20Sopenharmony_ci } else { 1808c2ecf20Sopenharmony_ci dprintk(DBGLVL_DVB, "%s() Paused\n", __func__); 1818c2ecf20Sopenharmony_ci ret = 0; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci return ret; 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci/* Firmware is very windows centric, meaning you have to transition 1888c2ecf20Sopenharmony_ci * the part through AVStream / KS Windows stages, forwards or backwards. 1898c2ecf20Sopenharmony_ci * States are: stopped, acquired (h/w), paused, started. 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_cistatic int saa7164_dvb_stop_streaming(struct saa7164_port *port) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct saa7164_dev *dev = port->dev; 1948c2ecf20Sopenharmony_ci struct saa7164_buffer *buf; 1958c2ecf20Sopenharmony_ci struct list_head *p, *q; 1968c2ecf20Sopenharmony_ci int ret; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci ret = saa7164_dvb_pause_port(port); 2018c2ecf20Sopenharmony_ci ret = saa7164_dvb_acquire_port(port); 2028c2ecf20Sopenharmony_ci ret = saa7164_dvb_stop_port(port); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci /* Mark the hardware buffers as free */ 2058c2ecf20Sopenharmony_ci mutex_lock(&port->dmaqueue_lock); 2068c2ecf20Sopenharmony_ci list_for_each_safe(p, q, &port->dmaqueue.list) { 2078c2ecf20Sopenharmony_ci buf = list_entry(p, struct saa7164_buffer, list); 2088c2ecf20Sopenharmony_ci buf->flags = SAA7164_BUFFER_FREE; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci mutex_unlock(&port->dmaqueue_lock); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return ret; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic int saa7164_dvb_start_port(struct saa7164_port *port) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci struct saa7164_dev *dev = port->dev; 2188c2ecf20Sopenharmony_ci int ret = 0, result; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci saa7164_buffer_cfg_port(port); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci /* Acquire the hardware */ 2258c2ecf20Sopenharmony_ci result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE); 2268c2ecf20Sopenharmony_ci if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { 2278c2ecf20Sopenharmony_ci printk(KERN_ERR "%s() acquire transition failed, res = 0x%x\n", 2288c2ecf20Sopenharmony_ci __func__, result); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* Stop the hardware, regardless */ 2318c2ecf20Sopenharmony_ci result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); 2328c2ecf20Sopenharmony_ci if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { 2338c2ecf20Sopenharmony_ci printk(KERN_ERR "%s() acquire/forced stop transition failed, res = 0x%x\n", 2348c2ecf20Sopenharmony_ci __func__, result); 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci ret = -EIO; 2378c2ecf20Sopenharmony_ci goto out; 2388c2ecf20Sopenharmony_ci } else 2398c2ecf20Sopenharmony_ci dprintk(DBGLVL_DVB, "%s() Acquired\n", __func__); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci /* Pause the hardware */ 2428c2ecf20Sopenharmony_ci result = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE); 2438c2ecf20Sopenharmony_ci if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { 2448c2ecf20Sopenharmony_ci printk(KERN_ERR "%s() pause transition failed, res = 0x%x\n", 2458c2ecf20Sopenharmony_ci __func__, result); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* Stop the hardware, regardless */ 2488c2ecf20Sopenharmony_ci result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); 2498c2ecf20Sopenharmony_ci if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { 2508c2ecf20Sopenharmony_ci printk(KERN_ERR "%s() pause/forced stop transition failed, res = 0x%x\n", 2518c2ecf20Sopenharmony_ci __func__, result); 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci ret = -EIO; 2558c2ecf20Sopenharmony_ci goto out; 2568c2ecf20Sopenharmony_ci } else 2578c2ecf20Sopenharmony_ci dprintk(DBGLVL_DVB, "%s() Paused\n", __func__); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /* Start the hardware */ 2608c2ecf20Sopenharmony_ci result = saa7164_api_transition_port(port, SAA_DMASTATE_RUN); 2618c2ecf20Sopenharmony_ci if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { 2628c2ecf20Sopenharmony_ci printk(KERN_ERR "%s() run transition failed, result = 0x%x\n", 2638c2ecf20Sopenharmony_ci __func__, result); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci /* Stop the hardware, regardless */ 2668c2ecf20Sopenharmony_ci result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); 2678c2ecf20Sopenharmony_ci if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { 2688c2ecf20Sopenharmony_ci printk(KERN_ERR "%s() run/forced stop transition failed, res = 0x%x\n", 2698c2ecf20Sopenharmony_ci __func__, result); 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci ret = -EIO; 2738c2ecf20Sopenharmony_ci } else 2748c2ecf20Sopenharmony_ci dprintk(DBGLVL_DVB, "%s() Running\n", __func__); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ciout: 2778c2ecf20Sopenharmony_ci return ret; 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic int saa7164_dvb_start_feed(struct dvb_demux_feed *feed) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci struct dvb_demux *demux = feed->demux; 2838c2ecf20Sopenharmony_ci struct saa7164_port *port = (struct saa7164_port *) demux->priv; 2848c2ecf20Sopenharmony_ci struct saa7164_dvb *dvb = &port->dvb; 2858c2ecf20Sopenharmony_ci struct saa7164_dev *dev = port->dev; 2868c2ecf20Sopenharmony_ci int ret = 0; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (!demux->dmx.frontend) 2918c2ecf20Sopenharmony_ci return -EINVAL; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (dvb) { 2948c2ecf20Sopenharmony_ci mutex_lock(&dvb->lock); 2958c2ecf20Sopenharmony_ci if (dvb->feeding++ == 0) { 2968c2ecf20Sopenharmony_ci /* Start transport */ 2978c2ecf20Sopenharmony_ci ret = saa7164_dvb_start_port(port); 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci mutex_unlock(&dvb->lock); 3008c2ecf20Sopenharmony_ci dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n", 3018c2ecf20Sopenharmony_ci __func__, port->nr, dvb->feeding); 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci return ret; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic int saa7164_dvb_stop_feed(struct dvb_demux_feed *feed) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci struct dvb_demux *demux = feed->demux; 3108c2ecf20Sopenharmony_ci struct saa7164_port *port = (struct saa7164_port *) demux->priv; 3118c2ecf20Sopenharmony_ci struct saa7164_dvb *dvb = &port->dvb; 3128c2ecf20Sopenharmony_ci struct saa7164_dev *dev = port->dev; 3138c2ecf20Sopenharmony_ci int ret = 0; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (dvb) { 3188c2ecf20Sopenharmony_ci mutex_lock(&dvb->lock); 3198c2ecf20Sopenharmony_ci if (--dvb->feeding == 0) { 3208c2ecf20Sopenharmony_ci /* Stop transport */ 3218c2ecf20Sopenharmony_ci ret = saa7164_dvb_stop_streaming(port); 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci mutex_unlock(&dvb->lock); 3248c2ecf20Sopenharmony_ci dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n", 3258c2ecf20Sopenharmony_ci __func__, port->nr, dvb->feeding); 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci return ret; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistatic int dvb_register(struct saa7164_port *port) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci struct saa7164_dvb *dvb = &port->dvb; 3348c2ecf20Sopenharmony_ci struct saa7164_dev *dev = port->dev; 3358c2ecf20Sopenharmony_ci struct saa7164_buffer *buf; 3368c2ecf20Sopenharmony_ci int result, i; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci BUG_ON(port->type != SAA7164_MPEG_DVB); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* Sanity check that the PCI configuration space is active */ 3438c2ecf20Sopenharmony_ci if (port->hwcfg.BARLocation == 0) { 3448c2ecf20Sopenharmony_ci result = -ENOMEM; 3458c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: dvb_register_adapter failed (errno = %d), NO PCI configuration\n", 3468c2ecf20Sopenharmony_ci DRIVER_NAME, result); 3478c2ecf20Sopenharmony_ci goto fail_adapter; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* Init and establish defaults */ 3518c2ecf20Sopenharmony_ci port->hw_streamingparams.bitspersample = 8; 3528c2ecf20Sopenharmony_ci port->hw_streamingparams.samplesperline = 188; 3538c2ecf20Sopenharmony_ci port->hw_streamingparams.numberoflines = 3548c2ecf20Sopenharmony_ci (SAA7164_TS_NUMBER_OF_LINES * 188) / 188; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci port->hw_streamingparams.pitch = 188; 3578c2ecf20Sopenharmony_ci port->hw_streamingparams.linethreshold = 0; 3588c2ecf20Sopenharmony_ci port->hw_streamingparams.pagetablelistvirt = NULL; 3598c2ecf20Sopenharmony_ci port->hw_streamingparams.pagetablelistphys = NULL; 3608c2ecf20Sopenharmony_ci port->hw_streamingparams.numpagetables = 2 + 3618c2ecf20Sopenharmony_ci ((SAA7164_TS_NUMBER_OF_LINES * 188) / PAGE_SIZE); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci port->hw_streamingparams.numpagetableentries = port->hwcfg.buffercount; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci /* Allocate the PCI resources */ 3668c2ecf20Sopenharmony_ci for (i = 0; i < port->hwcfg.buffercount; i++) { 3678c2ecf20Sopenharmony_ci buf = saa7164_buffer_alloc(port, 3688c2ecf20Sopenharmony_ci port->hw_streamingparams.numberoflines * 3698c2ecf20Sopenharmony_ci port->hw_streamingparams.pitch); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (!buf) { 3728c2ecf20Sopenharmony_ci result = -ENOMEM; 3738c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: dvb_register_adapter failed (errno = %d), unable to allocate buffers\n", 3748c2ecf20Sopenharmony_ci DRIVER_NAME, result); 3758c2ecf20Sopenharmony_ci goto fail_adapter; 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci mutex_lock(&port->dmaqueue_lock); 3798c2ecf20Sopenharmony_ci list_add_tail(&buf->list, &port->dmaqueue.list); 3808c2ecf20Sopenharmony_ci mutex_unlock(&port->dmaqueue_lock); 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* register adapter */ 3848c2ecf20Sopenharmony_ci result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE, 3858c2ecf20Sopenharmony_ci &dev->pci->dev, adapter_nr); 3868c2ecf20Sopenharmony_ci if (result < 0) { 3878c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: dvb_register_adapter failed (errno = %d)\n", 3888c2ecf20Sopenharmony_ci DRIVER_NAME, result); 3898c2ecf20Sopenharmony_ci goto fail_adapter; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci dvb->adapter.priv = port; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* register frontend */ 3948c2ecf20Sopenharmony_ci result = dvb_register_frontend(&dvb->adapter, dvb->frontend); 3958c2ecf20Sopenharmony_ci if (result < 0) { 3968c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: dvb_register_frontend failed (errno = %d)\n", 3978c2ecf20Sopenharmony_ci DRIVER_NAME, result); 3988c2ecf20Sopenharmony_ci goto fail_frontend; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* register demux stuff */ 4028c2ecf20Sopenharmony_ci dvb->demux.dmx.capabilities = 4038c2ecf20Sopenharmony_ci DMX_TS_FILTERING | DMX_SECTION_FILTERING | 4048c2ecf20Sopenharmony_ci DMX_MEMORY_BASED_FILTERING; 4058c2ecf20Sopenharmony_ci dvb->demux.priv = port; 4068c2ecf20Sopenharmony_ci dvb->demux.filternum = 256; 4078c2ecf20Sopenharmony_ci dvb->demux.feednum = 256; 4088c2ecf20Sopenharmony_ci dvb->demux.start_feed = saa7164_dvb_start_feed; 4098c2ecf20Sopenharmony_ci dvb->demux.stop_feed = saa7164_dvb_stop_feed; 4108c2ecf20Sopenharmony_ci result = dvb_dmx_init(&dvb->demux); 4118c2ecf20Sopenharmony_ci if (result < 0) { 4128c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: dvb_dmx_init failed (errno = %d)\n", 4138c2ecf20Sopenharmony_ci DRIVER_NAME, result); 4148c2ecf20Sopenharmony_ci goto fail_dmx; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci dvb->dmxdev.filternum = 256; 4188c2ecf20Sopenharmony_ci dvb->dmxdev.demux = &dvb->demux.dmx; 4198c2ecf20Sopenharmony_ci dvb->dmxdev.capabilities = 0; 4208c2ecf20Sopenharmony_ci result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); 4218c2ecf20Sopenharmony_ci if (result < 0) { 4228c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: dvb_dmxdev_init failed (errno = %d)\n", 4238c2ecf20Sopenharmony_ci DRIVER_NAME, result); 4248c2ecf20Sopenharmony_ci goto fail_dmxdev; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci dvb->fe_hw.source = DMX_FRONTEND_0; 4288c2ecf20Sopenharmony_ci result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); 4298c2ecf20Sopenharmony_ci if (result < 0) { 4308c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", 4318c2ecf20Sopenharmony_ci DRIVER_NAME, result); 4328c2ecf20Sopenharmony_ci goto fail_fe_hw; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci dvb->fe_mem.source = DMX_MEMORY_FE; 4368c2ecf20Sopenharmony_ci result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); 4378c2ecf20Sopenharmony_ci if (result < 0) { 4388c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", 4398c2ecf20Sopenharmony_ci DRIVER_NAME, result); 4408c2ecf20Sopenharmony_ci goto fail_fe_mem; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); 4448c2ecf20Sopenharmony_ci if (result < 0) { 4458c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: connect_frontend failed (errno = %d)\n", 4468c2ecf20Sopenharmony_ci DRIVER_NAME, result); 4478c2ecf20Sopenharmony_ci goto fail_fe_conn; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci /* register network adapter */ 4518c2ecf20Sopenharmony_ci dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); 4528c2ecf20Sopenharmony_ci return 0; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cifail_fe_conn: 4558c2ecf20Sopenharmony_ci dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); 4568c2ecf20Sopenharmony_cifail_fe_mem: 4578c2ecf20Sopenharmony_ci dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); 4588c2ecf20Sopenharmony_cifail_fe_hw: 4598c2ecf20Sopenharmony_ci dvb_dmxdev_release(&dvb->dmxdev); 4608c2ecf20Sopenharmony_cifail_dmxdev: 4618c2ecf20Sopenharmony_ci dvb_dmx_release(&dvb->demux); 4628c2ecf20Sopenharmony_cifail_dmx: 4638c2ecf20Sopenharmony_ci dvb_unregister_frontend(dvb->frontend); 4648c2ecf20Sopenharmony_cifail_frontend: 4658c2ecf20Sopenharmony_ci dvb_frontend_detach(dvb->frontend); 4668c2ecf20Sopenharmony_ci dvb_unregister_adapter(&dvb->adapter); 4678c2ecf20Sopenharmony_cifail_adapter: 4688c2ecf20Sopenharmony_ci return result; 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ciint saa7164_dvb_unregister(struct saa7164_port *port) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci struct saa7164_dvb *dvb = &port->dvb; 4748c2ecf20Sopenharmony_ci struct saa7164_dev *dev = port->dev; 4758c2ecf20Sopenharmony_ci struct saa7164_buffer *b; 4768c2ecf20Sopenharmony_ci struct list_head *c, *n; 4778c2ecf20Sopenharmony_ci struct i2c_client *client; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci dprintk(DBGLVL_DVB, "%s()\n", __func__); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci BUG_ON(port->type != SAA7164_MPEG_DVB); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci /* Remove any allocated buffers */ 4848c2ecf20Sopenharmony_ci mutex_lock(&port->dmaqueue_lock); 4858c2ecf20Sopenharmony_ci list_for_each_safe(c, n, &port->dmaqueue.list) { 4868c2ecf20Sopenharmony_ci b = list_entry(c, struct saa7164_buffer, list); 4878c2ecf20Sopenharmony_ci list_del(c); 4888c2ecf20Sopenharmony_ci saa7164_buffer_dealloc(b); 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci mutex_unlock(&port->dmaqueue_lock); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci if (dvb->frontend == NULL) 4938c2ecf20Sopenharmony_ci return 0; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci /* remove I2C client for tuner */ 4968c2ecf20Sopenharmony_ci client = port->i2c_client_tuner; 4978c2ecf20Sopenharmony_ci if (client) { 4988c2ecf20Sopenharmony_ci module_put(client->dev.driver->owner); 4998c2ecf20Sopenharmony_ci i2c_unregister_device(client); 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* remove I2C client for demodulator */ 5038c2ecf20Sopenharmony_ci client = port->i2c_client_demod; 5048c2ecf20Sopenharmony_ci if (client) { 5058c2ecf20Sopenharmony_ci module_put(client->dev.driver->owner); 5068c2ecf20Sopenharmony_ci i2c_unregister_device(client); 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci dvb_net_release(&dvb->net); 5108c2ecf20Sopenharmony_ci dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); 5118c2ecf20Sopenharmony_ci dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); 5128c2ecf20Sopenharmony_ci dvb_dmxdev_release(&dvb->dmxdev); 5138c2ecf20Sopenharmony_ci dvb_dmx_release(&dvb->demux); 5148c2ecf20Sopenharmony_ci dvb_unregister_frontend(dvb->frontend); 5158c2ecf20Sopenharmony_ci dvb_frontend_detach(dvb->frontend); 5168c2ecf20Sopenharmony_ci dvb_unregister_adapter(&dvb->adapter); 5178c2ecf20Sopenharmony_ci return 0; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci/* All the DVB attach calls go here, this function gets modified 5218c2ecf20Sopenharmony_ci * for each new card. 5228c2ecf20Sopenharmony_ci */ 5238c2ecf20Sopenharmony_ciint saa7164_dvb_register(struct saa7164_port *port) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci struct saa7164_dev *dev = port->dev; 5268c2ecf20Sopenharmony_ci struct saa7164_dvb *dvb = &port->dvb; 5278c2ecf20Sopenharmony_ci struct saa7164_i2c *i2c_bus = NULL; 5288c2ecf20Sopenharmony_ci struct si2168_config si2168_config; 5298c2ecf20Sopenharmony_ci struct si2157_config si2157_config; 5308c2ecf20Sopenharmony_ci struct i2c_adapter *adapter; 5318c2ecf20Sopenharmony_ci struct i2c_board_info info; 5328c2ecf20Sopenharmony_ci struct i2c_client *client_demod; 5338c2ecf20Sopenharmony_ci struct i2c_client *client_tuner; 5348c2ecf20Sopenharmony_ci int ret; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci dprintk(DBGLVL_DVB, "%s()\n", __func__); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci /* init frontend */ 5398c2ecf20Sopenharmony_ci switch (dev->board) { 5408c2ecf20Sopenharmony_ci case SAA7164_BOARD_HAUPPAUGE_HVR2200: 5418c2ecf20Sopenharmony_ci case SAA7164_BOARD_HAUPPAUGE_HVR2200_2: 5428c2ecf20Sopenharmony_ci case SAA7164_BOARD_HAUPPAUGE_HVR2200_3: 5438c2ecf20Sopenharmony_ci case SAA7164_BOARD_HAUPPAUGE_HVR2200_4: 5448c2ecf20Sopenharmony_ci case SAA7164_BOARD_HAUPPAUGE_HVR2200_5: 5458c2ecf20Sopenharmony_ci i2c_bus = &dev->i2c_bus[port->nr + 1]; 5468c2ecf20Sopenharmony_ci switch (port->nr) { 5478c2ecf20Sopenharmony_ci case 0: 5488c2ecf20Sopenharmony_ci port->dvb.frontend = dvb_attach(tda10048_attach, 5498c2ecf20Sopenharmony_ci &hauppauge_hvr2200_1_config, 5508c2ecf20Sopenharmony_ci &i2c_bus->i2c_adap); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci if (port->dvb.frontend != NULL) { 5538c2ecf20Sopenharmony_ci /* TODO: addr is in the card struct */ 5548c2ecf20Sopenharmony_ci dvb_attach(tda18271_attach, port->dvb.frontend, 5558c2ecf20Sopenharmony_ci 0xc0 >> 1, &i2c_bus->i2c_adap, 5568c2ecf20Sopenharmony_ci &hauppauge_hvr22x0_tuner_config); 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci break; 5608c2ecf20Sopenharmony_ci case 1: 5618c2ecf20Sopenharmony_ci port->dvb.frontend = dvb_attach(tda10048_attach, 5628c2ecf20Sopenharmony_ci &hauppauge_hvr2200_2_config, 5638c2ecf20Sopenharmony_ci &i2c_bus->i2c_adap); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci if (port->dvb.frontend != NULL) { 5668c2ecf20Sopenharmony_ci /* TODO: addr is in the card struct */ 5678c2ecf20Sopenharmony_ci dvb_attach(tda18271_attach, port->dvb.frontend, 5688c2ecf20Sopenharmony_ci 0xc0 >> 1, &i2c_bus->i2c_adap, 5698c2ecf20Sopenharmony_ci &hauppauge_hvr22x0s_tuner_config); 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci break; 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci break; 5758c2ecf20Sopenharmony_ci case SAA7164_BOARD_HAUPPAUGE_HVR2250: 5768c2ecf20Sopenharmony_ci case SAA7164_BOARD_HAUPPAUGE_HVR2250_2: 5778c2ecf20Sopenharmony_ci case SAA7164_BOARD_HAUPPAUGE_HVR2250_3: 5788c2ecf20Sopenharmony_ci i2c_bus = &dev->i2c_bus[port->nr + 1]; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci port->dvb.frontend = dvb_attach(s5h1411_attach, 5818c2ecf20Sopenharmony_ci &hauppauge_s5h1411_config, 5828c2ecf20Sopenharmony_ci &i2c_bus->i2c_adap); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci if (port->dvb.frontend != NULL) { 5858c2ecf20Sopenharmony_ci if (port->nr == 0) { 5868c2ecf20Sopenharmony_ci /* Master TDA18271 */ 5878c2ecf20Sopenharmony_ci /* TODO: addr is in the card struct */ 5888c2ecf20Sopenharmony_ci dvb_attach(tda18271_attach, port->dvb.frontend, 5898c2ecf20Sopenharmony_ci 0xc0 >> 1, &i2c_bus->i2c_adap, 5908c2ecf20Sopenharmony_ci &hauppauge_hvr22x0_tuner_config); 5918c2ecf20Sopenharmony_ci } else { 5928c2ecf20Sopenharmony_ci /* Slave TDA18271 */ 5938c2ecf20Sopenharmony_ci dvb_attach(tda18271_attach, port->dvb.frontend, 5948c2ecf20Sopenharmony_ci 0xc0 >> 1, &i2c_bus->i2c_adap, 5958c2ecf20Sopenharmony_ci &hauppauge_hvr22x0s_tuner_config); 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci break; 6008c2ecf20Sopenharmony_ci case SAA7164_BOARD_HAUPPAUGE_HVR2255proto: 6018c2ecf20Sopenharmony_ci case SAA7164_BOARD_HAUPPAUGE_HVR2255: 6028c2ecf20Sopenharmony_ci i2c_bus = &dev->i2c_bus[2]; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci if (port->nr == 0) { 6058c2ecf20Sopenharmony_ci port->dvb.frontend = dvb_attach(lgdt3306a_attach, 6068c2ecf20Sopenharmony_ci &hauppauge_hvr2255a_config, &i2c_bus->i2c_adap); 6078c2ecf20Sopenharmony_ci } else { 6088c2ecf20Sopenharmony_ci port->dvb.frontend = dvb_attach(lgdt3306a_attach, 6098c2ecf20Sopenharmony_ci &hauppauge_hvr2255b_config, &i2c_bus->i2c_adap); 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (port->dvb.frontend != NULL) { 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci if (port->nr == 0) { 6158c2ecf20Sopenharmony_ci si2157_attach(port, &dev->i2c_bus[0].i2c_adap, 6168c2ecf20Sopenharmony_ci port->dvb.frontend, 0xc0, 6178c2ecf20Sopenharmony_ci &hauppauge_hvr2255_tuner_config); 6188c2ecf20Sopenharmony_ci } else { 6198c2ecf20Sopenharmony_ci si2157_attach(port, &dev->i2c_bus[1].i2c_adap, 6208c2ecf20Sopenharmony_ci port->dvb.frontend, 0xc0, 6218c2ecf20Sopenharmony_ci &hauppauge_hvr2255_tuner_config); 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci break; 6258c2ecf20Sopenharmony_ci case SAA7164_BOARD_HAUPPAUGE_HVR2205: 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci if (port->nr == 0) { 6288c2ecf20Sopenharmony_ci /* attach frontend */ 6298c2ecf20Sopenharmony_ci memset(&si2168_config, 0, sizeof(si2168_config)); 6308c2ecf20Sopenharmony_ci si2168_config.i2c_adapter = &adapter; 6318c2ecf20Sopenharmony_ci si2168_config.fe = &port->dvb.frontend; 6328c2ecf20Sopenharmony_ci si2168_config.ts_mode = SI2168_TS_SERIAL; 6338c2ecf20Sopenharmony_ci memset(&info, 0, sizeof(struct i2c_board_info)); 6348c2ecf20Sopenharmony_ci strscpy(info.type, "si2168", I2C_NAME_SIZE); 6358c2ecf20Sopenharmony_ci info.addr = 0xc8 >> 1; 6368c2ecf20Sopenharmony_ci info.platform_data = &si2168_config; 6378c2ecf20Sopenharmony_ci request_module(info.type); 6388c2ecf20Sopenharmony_ci client_demod = i2c_new_client_device(&dev->i2c_bus[2].i2c_adap, &info); 6398c2ecf20Sopenharmony_ci if (!i2c_client_has_driver(client_demod)) 6408c2ecf20Sopenharmony_ci goto frontend_detach; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (!try_module_get(client_demod->dev.driver->owner)) { 6438c2ecf20Sopenharmony_ci i2c_unregister_device(client_demod); 6448c2ecf20Sopenharmony_ci goto frontend_detach; 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci port->i2c_client_demod = client_demod; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci /* attach tuner */ 6498c2ecf20Sopenharmony_ci memset(&si2157_config, 0, sizeof(si2157_config)); 6508c2ecf20Sopenharmony_ci si2157_config.if_port = 1; 6518c2ecf20Sopenharmony_ci si2157_config.fe = port->dvb.frontend; 6528c2ecf20Sopenharmony_ci memset(&info, 0, sizeof(struct i2c_board_info)); 6538c2ecf20Sopenharmony_ci strscpy(info.type, "si2157", I2C_NAME_SIZE); 6548c2ecf20Sopenharmony_ci info.addr = 0xc0 >> 1; 6558c2ecf20Sopenharmony_ci info.platform_data = &si2157_config; 6568c2ecf20Sopenharmony_ci request_module(info.type); 6578c2ecf20Sopenharmony_ci client_tuner = i2c_new_client_device(&dev->i2c_bus[0].i2c_adap, &info); 6588c2ecf20Sopenharmony_ci if (!i2c_client_has_driver(client_tuner)) { 6598c2ecf20Sopenharmony_ci module_put(client_demod->dev.driver->owner); 6608c2ecf20Sopenharmony_ci i2c_unregister_device(client_demod); 6618c2ecf20Sopenharmony_ci goto frontend_detach; 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci if (!try_module_get(client_tuner->dev.driver->owner)) { 6648c2ecf20Sopenharmony_ci i2c_unregister_device(client_tuner); 6658c2ecf20Sopenharmony_ci module_put(client_demod->dev.driver->owner); 6668c2ecf20Sopenharmony_ci i2c_unregister_device(client_demod); 6678c2ecf20Sopenharmony_ci goto frontend_detach; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci port->i2c_client_tuner = client_tuner; 6708c2ecf20Sopenharmony_ci } else { 6718c2ecf20Sopenharmony_ci /* attach frontend */ 6728c2ecf20Sopenharmony_ci memset(&si2168_config, 0, sizeof(si2168_config)); 6738c2ecf20Sopenharmony_ci si2168_config.i2c_adapter = &adapter; 6748c2ecf20Sopenharmony_ci si2168_config.fe = &port->dvb.frontend; 6758c2ecf20Sopenharmony_ci si2168_config.ts_mode = SI2168_TS_SERIAL; 6768c2ecf20Sopenharmony_ci memset(&info, 0, sizeof(struct i2c_board_info)); 6778c2ecf20Sopenharmony_ci strscpy(info.type, "si2168", I2C_NAME_SIZE); 6788c2ecf20Sopenharmony_ci info.addr = 0xcc >> 1; 6798c2ecf20Sopenharmony_ci info.platform_data = &si2168_config; 6808c2ecf20Sopenharmony_ci request_module(info.type); 6818c2ecf20Sopenharmony_ci client_demod = i2c_new_client_device(&dev->i2c_bus[2].i2c_adap, &info); 6828c2ecf20Sopenharmony_ci if (!i2c_client_has_driver(client_demod)) 6838c2ecf20Sopenharmony_ci goto frontend_detach; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci if (!try_module_get(client_demod->dev.driver->owner)) { 6868c2ecf20Sopenharmony_ci i2c_unregister_device(client_demod); 6878c2ecf20Sopenharmony_ci goto frontend_detach; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci port->i2c_client_demod = client_demod; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci /* attach tuner */ 6928c2ecf20Sopenharmony_ci memset(&si2157_config, 0, sizeof(si2157_config)); 6938c2ecf20Sopenharmony_ci si2157_config.fe = port->dvb.frontend; 6948c2ecf20Sopenharmony_ci si2157_config.if_port = 1; 6958c2ecf20Sopenharmony_ci memset(&info, 0, sizeof(struct i2c_board_info)); 6968c2ecf20Sopenharmony_ci strscpy(info.type, "si2157", I2C_NAME_SIZE); 6978c2ecf20Sopenharmony_ci info.addr = 0xc0 >> 1; 6988c2ecf20Sopenharmony_ci info.platform_data = &si2157_config; 6998c2ecf20Sopenharmony_ci request_module(info.type); 7008c2ecf20Sopenharmony_ci client_tuner = i2c_new_client_device(&dev->i2c_bus[1].i2c_adap, &info); 7018c2ecf20Sopenharmony_ci if (!i2c_client_has_driver(client_tuner)) { 7028c2ecf20Sopenharmony_ci module_put(client_demod->dev.driver->owner); 7038c2ecf20Sopenharmony_ci i2c_unregister_device(client_demod); 7048c2ecf20Sopenharmony_ci goto frontend_detach; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci if (!try_module_get(client_tuner->dev.driver->owner)) { 7078c2ecf20Sopenharmony_ci i2c_unregister_device(client_tuner); 7088c2ecf20Sopenharmony_ci module_put(client_demod->dev.driver->owner); 7098c2ecf20Sopenharmony_ci i2c_unregister_device(client_demod); 7108c2ecf20Sopenharmony_ci goto frontend_detach; 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci port->i2c_client_tuner = client_tuner; 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci break; 7168c2ecf20Sopenharmony_ci default: 7178c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: The frontend isn't supported\n", 7188c2ecf20Sopenharmony_ci dev->name); 7198c2ecf20Sopenharmony_ci break; 7208c2ecf20Sopenharmony_ci } 7218c2ecf20Sopenharmony_ci if (NULL == dvb->frontend) { 7228c2ecf20Sopenharmony_ci printk(KERN_ERR "%s() Frontend initialization failed\n", 7238c2ecf20Sopenharmony_ci __func__); 7248c2ecf20Sopenharmony_ci return -1; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci /* register everything */ 7288c2ecf20Sopenharmony_ci ret = dvb_register(port); 7298c2ecf20Sopenharmony_ci if (ret < 0) { 7308c2ecf20Sopenharmony_ci if (dvb->frontend->ops.release) 7318c2ecf20Sopenharmony_ci dvb->frontend->ops.release(dvb->frontend); 7328c2ecf20Sopenharmony_ci return ret; 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci return 0; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_cifrontend_detach: 7388c2ecf20Sopenharmony_ci printk(KERN_ERR "%s() Frontend/I2C initialization failed\n", __func__); 7398c2ecf20Sopenharmony_ci return -1; 7408c2ecf20Sopenharmony_ci} 741