📄 av7110.c
字号:
return 0;}static struct l64781_config grundig_29504_401_config = { .demod_address = 0x55,};static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status){ int ret = 0; int synced = (status & FE_HAS_LOCK) ? 1 : 0; av7110->fe_status = status; if (av7110->fe_synced == synced) return 0; if (av7110->playing) { av7110->fe_synced = synced; return 0; } if (mutex_lock_interruptible(&av7110->pid_mutex)) return -ERESTARTSYS; if (synced) { ret = SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO], av7110->pids[DMX_PES_AUDIO], av7110->pids[DMX_PES_TELETEXT], 0, av7110->pids[DMX_PES_PCR]); if (!ret) ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); } else { ret = SetPIDs(av7110, 0, 0, 0, 0, 0); if (!ret) { ret = av7110_fw_cmd(av7110, COMTYPE_PID_FILTER, FlushTSQueue, 0); if (!ret) ret = av7110_wait_msgstate(av7110, GPMQBusy); } } if (!ret) av7110->fe_synced = synced; mutex_unlock(&av7110->pid_mutex); return ret;}static int av7110_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* params){ struct av7110* av7110 = fe->dvb->priv; int ret = av7110_fe_lock_fix(av7110, 0); if (!ret) { av7110->saved_fe_params = *params; ret = av7110->fe_set_frontend(fe, params); } return ret;}static int av7110_fe_init(struct dvb_frontend* fe){ struct av7110* av7110 = fe->dvb->priv; int ret = av7110_fe_lock_fix(av7110, 0); if (!ret) ret = av7110->fe_init(fe); return ret;}static int av7110_fe_read_status(struct dvb_frontend* fe, fe_status_t* status){ struct av7110* av7110 = fe->dvb->priv; /* call the real implementation */ int ret = av7110->fe_read_status(fe, status); if (!ret) if (((*status ^ av7110->fe_status) & FE_HAS_LOCK) && (*status & FE_HAS_LOCK)) ret = av7110_fe_lock_fix(av7110, *status); return ret;}static int av7110_fe_diseqc_reset_overload(struct dvb_frontend* fe){ struct av7110* av7110 = fe->dvb->priv; int ret = av7110_fe_lock_fix(av7110, 0); if (!ret) ret = av7110->fe_diseqc_reset_overload(fe); return ret;}static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd){ struct av7110* av7110 = fe->dvb->priv; int ret = av7110_fe_lock_fix(av7110, 0); if (!ret) { av7110->saved_master_cmd = *cmd; ret = av7110->fe_diseqc_send_master_cmd(fe, cmd); } return ret;}static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd){ struct av7110* av7110 = fe->dvb->priv; int ret = av7110_fe_lock_fix(av7110, 0); if (!ret) { av7110->saved_minicmd = minicmd; ret = av7110->fe_diseqc_send_burst(fe, minicmd); } return ret;}static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone){ struct av7110* av7110 = fe->dvb->priv; int ret = av7110_fe_lock_fix(av7110, 0); if (!ret) { av7110->saved_tone = tone; ret = av7110->fe_set_tone(fe, tone); } return ret;}static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage){ struct av7110* av7110 = fe->dvb->priv; int ret = av7110_fe_lock_fix(av7110, 0); if (!ret) { av7110->saved_voltage = voltage; ret = av7110->fe_set_voltage(fe, voltage); } return ret;}static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned long cmd){ struct av7110* av7110 = fe->dvb->priv; int ret = av7110_fe_lock_fix(av7110, 0); if (!ret) ret = av7110->fe_dishnetwork_send_legacy_command(fe, cmd); return ret;}static void dvb_s_recover(struct av7110* av7110){ av7110_fe_init(av7110->fe); av7110_fe_set_voltage(av7110->fe, av7110->saved_voltage); if (av7110->saved_master_cmd.msg_len) { msleep(20); av7110_fe_diseqc_send_master_cmd(av7110->fe, &av7110->saved_master_cmd); } msleep(20); av7110_fe_diseqc_send_burst(av7110->fe, av7110->saved_minicmd); msleep(20); av7110_fe_set_tone(av7110->fe, av7110->saved_tone); av7110_fe_set_frontend(av7110->fe, &av7110->saved_fe_params);}static u8 read_pwm(struct av7110* av7110){ u8 b = 0xff; u8 pwm; struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 }, { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} }; if ((i2c_transfer(&av7110->i2c_adap, msg, 2) != 2) || (pwm == 0xff)) pwm = 0x48; return pwm;}static int frontend_init(struct av7110 *av7110){ int ret; if (av7110->dev->pci->subsystem_vendor == 0x110a) { switch(av7110->dev->pci->subsystem_device) { case 0x0000: // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??)) av7110->fe = dvb_attach(ves1820_attach, &philips_cd1516_config, &av7110->i2c_adap, read_pwm(av7110)); if (av7110->fe) { av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params; } break; } } else if (av7110->dev->pci->subsystem_vendor == 0x13c2) { switch(av7110->dev->pci->subsystem_device) { case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X case 0x0003: // Hauppauge/TT WinTV Nexus-S Rev 2.X case 0x1002: // Hauppauge/TT WinTV DVB-S rev1.3SE // try the ALPS BSRV2 first of all av7110->fe = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &av7110->i2c_adap); if (av7110->fe) { av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; av7110->fe->ops.set_tone = av7110_set_tone; av7110->recover = dvb_s_recover; break; } // try the ALPS BSRU6 now av7110->fe = dvb_attach(stv0299_attach, &alps_bsru6_config, &av7110->i2c_adap); if (av7110->fe) { av7110->fe->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; av7110->fe->tuner_priv = &av7110->i2c_adap; av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; av7110->fe->ops.set_tone = av7110_set_tone; av7110->recover = dvb_s_recover; break; } // Try the grundig 29504-451 av7110->fe = dvb_attach(tda8083_attach, &grundig_29504_451_config, &av7110->i2c_adap); if (av7110->fe) { av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; av7110->fe->ops.set_tone = av7110_set_tone; av7110->recover = dvb_s_recover; break; } /* Try DVB-C cards */ switch(av7110->dev->pci->subsystem_device) { case 0x0000: /* Siemens DVB-C (full-length card) VES1820/Philips CD1516 */ av7110->fe = dvb_attach(ves1820_attach, &philips_cd1516_config, &av7110->i2c_adap, read_pwm(av7110)); if (av7110->fe) { av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params; } break; case 0x0003: /* Hauppauge DVB-C 2.1 VES1820/ALPS TDBE2 */ av7110->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110)); if (av7110->fe) { av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; } break; } break; case 0x0001: // Hauppauge/TT Nexus-T premium rev1.X // try ALPS TDLB7 first, then Grundig 29504-401 av7110->fe = dvb_attach(sp8870_attach, &alps_tdlb7_config, &av7110->i2c_adap); if (av7110->fe) { av7110->fe->ops.tuner_ops.set_params = alps_tdlb7_tuner_set_params; break; } /* fall-thru */ case 0x0008: // Hauppauge/TT DVB-T // Grundig 29504-401 av7110->fe = dvb_attach(l64781_attach, &grundig_29504_401_config, &av7110->i2c_adap); if (av7110->fe) av7110->fe->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params; break; case 0x0002: // Hauppauge/TT DVB-C premium rev2.X av7110->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110)); if (av7110->fe) { av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; } break; case 0x0004: // Galaxis DVB-S rev1.3 /* ALPS BSRV2 */ av7110->fe = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &av7110->i2c_adap); if (av7110->fe) { av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; av7110->fe->ops.set_tone = av7110_set_tone; av7110->recover = dvb_s_recover; } break; case 0x0006: /* Fujitsu-Siemens DVB-S rev 1.6 */ /* Grundig 29504-451 */ av7110->fe = dvb_attach(tda8083_attach, &grundig_29504_451_config, &av7110->i2c_adap); if (av7110->fe) { av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; av7110->fe->ops.set_tone = av7110_set_tone; av7110->recover = dvb_s_recover; } break; case 0x000A: // Hauppauge/TT Nexus-CA rev1.X av7110->fe = dvb_attach(stv0297_attach, &nexusca_stv0297_config, &av7110->i2c_adap); if (av7110->fe) { av7110->fe->ops.tuner_ops.set_params = nexusca_stv0297_tuner_set_params; /* set TDA9819 into DVB mode */ saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD) saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF) /* tuner on this needs a slower i2c bus speed */ av7110->dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; break; } break; case 0x000E: /* Hauppauge/TT Nexus-S rev 2.3 */ /* ALPS BSBE1 */ av7110->fe = dvb_attach(stv0299_attach, &alps_bsbe1_config, &av7110->i2c_adap); if (av7110->fe) { av7110->fe->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params; av7110->fe->tuner_priv = &av7110->i2c_adap; if (dvb_attach(lnbp21_attach, av7110->fe, &av7110->i2c_adap, 0, 0) == NULL) { printk("dvb-ttpci: LNBP21 not found!\n"); if (av7110->fe->ops.release) av7110->fe->ops.release(av7110->fe); av7110->fe = NULL; } else { av7110->fe->ops.dishnetwork_send_legacy_command = NULL; av7110->recover = dvb_s_recover; } } break; } } if (!av7110->fe) { /* FIXME: propagate the failure code from the lower layers */ ret = -ENOMEM; printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", av7110->dev->pci->vendor, av7110->dev->pci->device, av7110->dev->pci->subsystem_vendor, av7110->dev->pci->subsystem_device); } else { FE_FUNC_OVERRIDE(av7110->fe->ops.init, av7110->fe_init, av7110_fe_init); FE_FUNC_OVERRIDE(av7110->fe->ops.read_status, av7110->fe_read_status, av7110_fe_read_status); FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_reset_overload, av7110->fe_diseqc_reset_overload, av7110_fe_diseqc_reset_overload); FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd); FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst); FE_FUNC_OVERRIDE(av7110->fe->ops.set_tone, av7110->fe_set_tone, av7110_fe_set_tone); FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage); FE_FUNC_OVERRIDE(av7110->fe->ops.dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command); FE_FUNC_OVERRIDE(av7110->fe->ops.set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend); ret = dvb_register_frontend(&av7110->dvb_adapter, av7110->fe); if (ret < 0) { printk("av7110: Frontend registration failed!\n"); dvb_frontend_detach(av7110->fe); av7110->fe = NULL; } } return ret;}/* Budgetpatch note: * Original hardware design by Roberto Deza: * There is a DVB_Wiki at * http://212.227.36.83/linuxtv/wiki/index.php/Main_Page * where is described this 'DVB TT Budget Patch', on Card Modding: * http://212.227.36.83/linuxtv/wiki/index.php/DVB_TT_Budget_Patch * On the short description there is also a link to a external file, * with more details: * http://perso.wanadoo.es/jesussolano/Ttf_tsc1.zip * * New software triggering design by Emard that works on * original Roberto Deza's hardware: * * rps1 code for budgetpatch will copy internal HS event to GPIO3 pin. * GPIO3 is in budget-patch hardware connectd to port B VSYNC * HS is an internal event of 7146, accessible with RPS * and temporarily raised high every n lines * (n in defined in the RPS_THRESH1 counter threshold) * I think HS is raised high on the beginning of the n-th line * and remains high until this n-th line that triggered * it is completely received. When the receiption of n-th line * ends, HS is lowered. * * To transmit data over DMA, 7146 needs changing state at * port B VSYNC pin. Any changing of port B VSYNC will * cause some DMA data transfer, with more or less packets loss. * It depends on the phase and frequency of VSYNC and * the way of 7146 is instructed to trigger on port B (defined * in DD1_INIT register, 3rd nibble from the right valid * numbers are 0-7, see datasheet) * * The correct triggering can minimize packet loss, * dvbtraffic should give this stable bandwidths: * 22k transponder = 33814 kbit/s * 27.5k transponder = 38045 kbit/s * by experiment it is found that the best results * (stable bandwidths and almost no packet loss) * are obtained using DD1_INIT triggering number 2 * (Va at rising edge of VS Fa = HS x VS-failing forced toggle) * and a VSYNC phase that occurs in the middle of DMA transfer * (about byte 188*512=96256 in the DMA window). * * Phase of HS is still not clear to me how to control, * It just happens to be so. It can be seen if one enables * RPS_IRQ and print Event Counter 1 in vpeirq(). Every * time RPS_INTERRUPT is called, the Event Counter 1 will * increment. That's how the 7146 is programmed to do event * counting in this budget-patch.c * I *think* HPS setting has something to do with the phase * of HS but I cant be 100% sure in that. * * hardware debug note: a working budget card (including budget patch) * with vpeirq() interrupt setup in mode "0x90" (every 64K) will * generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes * and that means 3*25=75 Hz of interrupt freqency, as seen by * watch cat /proc/interrupts * * If this frequency is 3x lower (and data received in the DMA * buffer don't start with 0x47, but in the middle of packets, * whose lengths appear to be like 188 292 188 104 etc. * this means VSYNC line is not connected in the hardware. * (check soldering pcb and pins) * The same behaviour of missing VSYNC can be duplicated on budget * cards, by seting DD1_INIT trigger mode 7 in 3rd nibble. */static int __devinit av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *pci_ext){ const int length = TS_WIDTH * TS_HEIGHT; struct pci_dev *pdev = dev->pci; struct av7110 *av7110; struct task_struct *thread; int ret, count = 0; dprintk(4, "dev: %p\n", dev); /* Set RPS_IRQ to 1 to track rps1 activity. * Enabling this won't send any interrupt to PC CPU. */#define RPS_IRQ 0 if (budgetpatch == 1) { budgetpatch = 0; /* autodetect the presence of budget patch * this only works if saa7146 has been recently * reset with with MASK_31 to MC1 * * will wait for VBI_B event (vertical blank at port B) * and will reset GPIO3 after VBI_B is detected. * (GPIO3 should be raised high by CPU to * test if GPIO3 will generate vertical blank signal * in budget patch GPIO3 is connected to VSYNC_B */ /* RESET SAA7146 */ saa7146_write(dev, MC1, MASK_31); /* autodetection success seems to be time-dependend after reset */ /* Fix VSYNC level */ saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); /* set vsync_b triggering */ saa7146_write(dev,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -