📄 skystar2.c
字号:
diseqc_send_byte(adapter, msg[i]); mdelay(16); if (burst != -1) { if (burst) diseqc_send_byte(adapter, 0xff); else { set_tuner_tone(adapter, 1); udelay(12500); set_tuner_tone(adapter, 0); } msleep(20); } return 0;}static int flexcop_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone){ struct adapter* adapter = (struct adapter*) fe->dvb->priv; switch(tone) { case SEC_TONE_ON: set_tuner_tone(adapter, 1); break; case SEC_TONE_OFF: set_tuner_tone(adapter, 0); break; default: return -EINVAL; }; return 0;}static int flexcop_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) { struct adapter* adapter = (struct adapter*) fe->dvb->priv; send_diseqc_msg(adapter, cmd->msg_len, cmd->msg, 0); return 0; }static int flexcop_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd){ struct adapter* adapter = (struct adapter*) fe->dvb->priv; send_diseqc_msg(adapter, 0, NULL, minicmd); return 0;}static int flexcop_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) { struct adapter* adapter = (struct adapter*) fe->dvb->priv; dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__); switch (voltage) { case SEC_VOLTAGE_13: dprintk("%s: SEC_VOLTAGE_13, %x\n", __FUNCTION__, SEC_VOLTAGE_13); set_tuner_polarity(adapter, 1); return 0; case SEC_VOLTAGE_18: dprintk("%s: SEC_VOLTAGE_18, %x\n", __FUNCTION__, SEC_VOLTAGE_18); set_tuner_polarity(adapter, 2); return 0; default: return -EINVAL; } }static int flexcop_sleep(struct dvb_frontend* fe) { struct adapter* adapter = (struct adapter*) fe->dvb->priv; dprintk("%s: FE_SLEEP\n", __FUNCTION__); set_tuner_polarity(adapter, 0); if (adapter->fe_sleep) return adapter->fe_sleep(fe); return 0; }static u32 flexcop_i2c_func(struct i2c_adapter *adapter) { printk("flexcop_i2c_func\n"); return I2C_FUNC_I2C;}static struct i2c_algorithm flexcop_algo = { .name = "flexcop i2c algorithm", .id = I2C_ALGO_BIT, .master_xfer = master_xfer, .functionality = flexcop_i2c_func,};static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio){ u8 aclk = 0; u8 bclk = 0; if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; } else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; } else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; } else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; } else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; } else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; } stv0299_writereg (fe, 0x13, aclk); stv0299_writereg (fe, 0x14, bclk); stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff); stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff); stv0299_writereg (fe, 0x21, (ratio ) & 0xf0); return 0;}static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params){ u8 buf[4]; u32 div; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; struct adapter* adapter = (struct adapter*) fe->dvb->priv; div = params->frequency / 125; buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; buf[2] = 0x84; // 0xC4 buf[3] = 0x08; if (params->frequency < 1500000) buf[3] |= 0x10; if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO; return 0;}static u8 samsung_tbmu24112_inittab[] = { 0x01, 0x15, 0x02, 0x30, 0x03, 0x00, 0x04, 0x7D, 0x05, 0x35, 0x06, 0x02, 0x07, 0x00, 0x08, 0xC3, 0x0C, 0x00, 0x0D, 0x81, 0x0E, 0x23, 0x0F, 0x12, 0x10, 0x7E, 0x11, 0x84, 0x12, 0xB9, 0x13, 0x88, 0x14, 0x89, 0x15, 0xC9, 0x16, 0x00, 0x17, 0x5C, 0x18, 0x00, 0x19, 0x00, 0x1A, 0x00, 0x1C, 0x00, 0x1D, 0x00, 0x1E, 0x00, 0x1F, 0x3A, 0x20, 0x2E, 0x21, 0x80, 0x22, 0xFF, 0x23, 0xC1, 0x28, 0x00, 0x29, 0x1E, 0x2A, 0x14, 0x2B, 0x0F, 0x2C, 0x09, 0x2D, 0x05, 0x31, 0x1F, 0x32, 0x19, 0x33, 0xFE, 0x34, 0x93, 0xff, 0xff, };static struct stv0299_config samsung_tbmu24112_config = { .demod_address = 0x68, .inittab = samsung_tbmu24112_inittab, .mclk = 88000000UL, .invert = 0, .enhanced_tuning = 0, .skip_reinit = 0, .lock_output = STV0229_LOCKOUTPUT_LK, .volt13_op0_op1 = STV0299_VOLT13_OP1, .min_delay_ms = 100, .set_symbol_rate = samsung_tbmu24112_set_symbol_rate, .pll_set = samsung_tbmu24112_pll_set,};static int nxt2002_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name){ struct adapter* adapter = (struct adapter*) fe->dvb->priv; return request_firmware(fw, name, &adapter->pdev->dev);}static struct nxt2002_config samsung_tbmv_config = { .demod_address = 0x0A, .request_firmware = nxt2002_request_firmware,};static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe){ static u8 mt352_clock_config [] = { 0x89, 0x18, 0x2d }; static u8 mt352_reset [] = { 0x50, 0x80 }; static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 }; static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); udelay(2000); mt352_write(fe, mt352_reset, sizeof(mt352_reset)); mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); return 0;}int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf){ u32 div; unsigned char bs = 0; #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09; if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a; if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08; pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address pllbuf[1] = div >> 8; pllbuf[2] = div & 0xff; pllbuf[3] = 0xcc; pllbuf[4] = bs; return 0;}static struct mt352_config samsung_tdtc9251dh0_config = { .demod_address = 0x0f, .demod_init = samsung_tdtc9251dh0_demod_init, .pll_set = samsung_tdtc9251dh0_pll_set,};static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params){ u8 buf[4]; u32 div; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; struct adapter* adapter = (struct adapter*) fe->dvb->priv; div = (params->frequency + (125/2)) / 125; buf[0] = (div >> 8) & 0x7f; buf[1] = (div >> 0) & 0xff; buf[2] = 0x84 | ((div >> 10) & 0x60); buf[3] = 0x80; if (params->frequency < 1550000) buf[3] |= 0x02; if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO; return 0;}static struct mt312_config skystar23_samsung_tbdu18132_config = { .demod_address = 0x0e, .pll_set = skystar23_samsung_tbdu18132_pll_set,};static void frontend_init(struct adapter *skystar2){ switch(skystar2->pdev->device) { case 0x2103: // Technisat Skystar2 OR Technisat Airstar2 (DVB-T or ATSC) // Attempt to load the Nextwave nxt2002 for ATSC support skystar2->fe = nxt2002_attach(&samsung_tbmv_config, &skystar2->i2c_adap); if (skystar2->fe != NULL) { skystar2->fe_sleep = skystar2->fe->ops->sleep; skystar2->fe->ops->sleep = flexcop_sleep; break; } // try the skystar2 v2.6 first (stv0299/Samsung tbmu24112(sl1935)) skystar2->fe = stv0299_attach(&samsung_tbmu24112_config, &skystar2->i2c_adap); if (skystar2->fe != NULL) { skystar2->fe->ops->set_voltage = flexcop_set_voltage; skystar2->fe_sleep = skystar2->fe->ops->sleep; skystar2->fe->ops->sleep = flexcop_sleep; break;} // try the airstar2 (mt352/Samsung tdtc9251dh0(??)) skystar2->fe = mt352_attach(&samsung_tdtc9251dh0_config, &skystar2->i2c_adap); if (skystar2->fe != NULL) { skystar2->fe->ops->info.frequency_min = 474000000; skystar2->fe->ops->info.frequency_max = 858000000; break; } // try the skystar2 v2.3 (vp310/Samsung tbdu18132(tsa5059)) skystar2->fe = vp310_attach(&skystar23_samsung_tbdu18132_config, &skystar2->i2c_adap); if (skystar2->fe != NULL) { skystar2->fe->ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd; skystar2->fe->ops->diseqc_send_burst = flexcop_diseqc_send_burst; skystar2->fe->ops->set_tone = flexcop_set_tone; skystar2->fe->ops->set_voltage = flexcop_set_voltage; skystar2->fe_sleep = skystar2->fe->ops->sleep; skystar2->fe->ops->sleep = flexcop_sleep; break; } break; } if (skystar2->fe == NULL) { printk("skystar2: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", skystar2->pdev->vendor, skystar2->pdev->device, skystar2->pdev->subsystem_vendor, skystar2->pdev->subsystem_device); } else { if (dvb_register_frontend(skystar2->dvb_adapter, skystar2->fe)) { printk("skystar2: Frontend registration failed!\n"); if (skystar2->fe->ops->release) skystar2->fe->ops->release(skystar2->fe); skystar2->fe = NULL; } }}static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent){ struct adapter *adapter; struct dvb_adapter *dvb_adapter; struct dvb_demux *dvbdemux; struct dmx_demux *dmx; int ret = -ENODEV; if (!pdev) goto out; ret = driver_initialize(pdev); if (ret < 0) goto out; ret = dvb_register_adapter(&dvb_adapter, skystar2_pci_driver.name, THIS_MODULE); if (ret < 0) { printk("%s: Error registering DVB adapter\n", __FUNCTION__); goto err_halt; } adapter = pci_get_drvdata(pdev); dvb_adapter->priv = adapter; adapter->dvb_adapter = dvb_adapter; init_MUTEX(&adapter->i2c_sem); memset(&adapter->i2c_adap, 0, sizeof(struct i2c_adapter)); strcpy(adapter->i2c_adap.name, "SkyStar2"); i2c_set_adapdata(&adapter->i2c_adap, adapter);#ifdef I2C_ADAP_CLASS_TV_DIGITAL adapter->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL;#else adapter->i2c_adap.class = I2C_CLASS_TV_DIGITAL;#endif adapter->i2c_adap.algo = &flexcop_algo; adapter->i2c_adap.algo_data = NULL; adapter->i2c_adap.id = I2C_ALGO_BIT; ret = i2c_add_adapter(&adapter->i2c_adap); if (ret < 0) goto err_dvb_unregister; dvbdemux = &adapter->demux; dvbdemux->priv = adapter; dvbdemux->filternum = N_PID_SLOTS; dvbdemux->feednum = N_PID_SLOTS; dvbdemux->start_feed = dvb_start_feed; dvbdemux->stop_feed = dvb_stop_feed; dvbdemux->write_to_decoder = NULL; dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); ret = dvb_dmx_init(&adapter->demux); if (ret < 0) goto err_i2c_del; dmx = &dvbdemux->dmx; adapter->hw_frontend.source = DMX_FRONTEND_0; adapter->dmxdev.filternum = N_PID_SLOTS; adapter->dmxdev.demux = dmx; adapter->dmxdev.capabilities = 0; ret = dvb_dmxdev_init(&adapter->dmxdev, adapter->dvb_adapter); if (ret < 0) goto err_dmx_release; ret = dmx->add_frontend(dmx, &adapter->hw_frontend); if (ret < 0) goto err_dmxdev_release; adapter->mem_frontend.source = DMX_MEMORY_FE; ret = dmx->add_frontend(dmx, &adapter->mem_frontend); if (ret < 0) goto err_remove_hw_frontend; ret = dmx->connect_frontend(dmx, &adapter->hw_frontend); if (ret < 0) goto err_remove_mem_frontend; dvb_net_init(adapter->dvb_adapter, &adapter->dvbnet, &dvbdemux->dmx); frontend_init(adapter);out: return ret;err_remove_mem_frontend: dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->mem_frontend);err_remove_hw_frontend: dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->hw_frontend);err_dmxdev_release: dvb_dmxdev_release(&adapter->dmxdev);err_dmx_release: dvb_dmx_release(&adapter->demux);err_i2c_del: i2c_del_adapter(&adapter->i2c_adap);err_dvb_unregister: dvb_unregister_adapter(adapter->dvb_adapter);err_halt: driver_halt(pdev); goto out;}static void skystar2_remove(struct pci_dev *pdev){ struct adapter *adapter = pci_get_drvdata(pdev); struct dvb_demux *dvbdemux; struct dmx_demux *dmx; if (!adapter) return; dvb_net_release(&adapter->dvbnet); dvbdemux = &adapter->demux; dmx = &dvbdemux->dmx; dmx->close(dmx); dmx->remove_frontend(dmx, &adapter->hw_frontend); dmx->remove_frontend(dmx, &adapter->mem_frontend); dvb_dmxdev_release(&adapter->dmxdev); dvb_dmx_release(dvbdemux); if (adapter->fe != NULL) dvb_unregister_frontend(adapter->fe); dvb_unregister_adapter(adapter->dvb_adapter); i2c_del_adapter(&adapter->i2c_adap); driver_halt(pdev); }static struct pci_device_id skystar2_pci_tbl[] = { {0x000013d0, 0x00002103, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000},/* {0x000013d0, 0x00002200, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000}, UNDEFINED HARDWARE - mail linuxtv.org list */ //FCIII {0,},};MODULE_DEVICE_TABLE(pci, skystar2_pci_tbl);static struct pci_driver skystar2_pci_driver = { .name = "SkyStar2", .id_table = skystar2_pci_tbl, .probe = skystar2_probe, .remove = skystar2_remove,};static int skystar2_init(void){ return pci_module_init(&skystar2_pci_driver);}static void skystar2_cleanup(void){ pci_unregister_driver(&skystar2_pci_driver);}module_init(skystar2_init);module_exit(skystar2_cleanup);MODULE_DESCRIPTION("Technisat SkyStar2 DVB PCI Driver");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -