📄 skystar2.c
字号:
if (!request_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0), skystar2_pci_driver.name)) return -EBUSY; pci_read_config_byte(pdev, PCI_CLASS_REVISION, &adapter->card_revision); dprintk("%s: card revision %x \n", __FUNCTION__, adapter->card_revision); if (pci_enable_device(pdev)) return -EIO; pci_read_config_word(pdev, 4, &var); if ((var & 4) == 0) pci_set_master(pdev); adapter->io_port = pdev->resource[1].start; adapter->io_mem = (unsigned long) ioremap(pdev->resource[0].start, 0x800); if (adapter->io_mem == 0) { dprintk("%s: can not map io memory\n", __FUNCTION__); return 2; } dprintk("%s: io memory maped at %lx\n", __FUNCTION__, adapter->io_mem); return 1;}/*static int sll_reset_flexcop(struct adapter *adapter){ write_reg_dw(adapter, 0x208, 0); write_reg_dw(adapter, 0x210, 0xb2ff); return 0;}*/static void decide_how_many_hw_filters(struct adapter *adapter){ int hw_filters; int mod_option_hw_filters; // FlexCop IIb & III have 6+32 hw filters // FlexCop II has 6 hw filters, every other should have at least 6 switch (adapter->b2c2_revision) { case 0x82: /* II */ hw_filters = 6; break; case 0xc3: /* IIB */ hw_filters = 6 + 32; break; case 0xc0: /* III */ hw_filters = 6 + 32; break; default: hw_filters = 6; break; } printk("%s: the chip has %i hardware filters", __FILE__, hw_filters); mod_option_hw_filters = 0; if (enable_hw_filters >= 1) mod_option_hw_filters += 6; if (enable_hw_filters >= 2) mod_option_hw_filters += 32; if (mod_option_hw_filters >= hw_filters) { adapter->useable_hw_filters = hw_filters; } else { adapter->useable_hw_filters = mod_option_hw_filters; printk(", but only %d will be used because of module option", mod_option_hw_filters); } printk("\n"); dprintk("%s: useable_hardware_filters set to %i\n", __FILE__, adapter->useable_hw_filters);}static int driver_initialize(struct pci_dev *pdev){ struct adapter *adapter; u32 tmp; if (!(adapter = kmalloc(sizeof(struct adapter), GFP_KERNEL))) { dprintk("%s: out of memory!\n", __FUNCTION__); return -ENOMEM; } memset(adapter, 0, sizeof(struct adapter)); pci_set_drvdata(pdev, adapter); adapter->pdev = pdev; adapter->irq = pdev->irq; if ((claim_adapter(adapter)) != 1) { free_adapter_object(adapter); return -ENODEV; } irq_dma_enable_disable_irq(adapter, 0); if (request_irq(pdev->irq, isr, 0x4000000, "Skystar2", adapter) != 0) { dprintk("%s: unable to allocate irq=%d !\n", __FUNCTION__, pdev->irq); free_adapter_object(adapter); return -ENODEV; } read_reg_dw(adapter, 0x208); write_reg_dw(adapter, 0x208, 0); write_reg_dw(adapter, 0x210, 0xb2ff); write_reg_dw(adapter, 0x208, 0x40); init_dma_queue(adapter); if ((adapter->dma_status & 0x30000000) == 0) { free_adapter_object(adapter); return -ENODEV; } adapter->b2c2_revision = (read_reg_dw(adapter, 0x204) >> 0x18); switch (adapter->b2c2_revision) { case 0x82: printk("%s: FlexCopII(rev.130) chip found\n", __FILE__); break; case 0xc3: printk("%s: FlexCopIIB(rev.195) chip found\n", __FILE__); break; case 0xc0: printk("%s: FlexCopIII(rev.192) chip found\n", __FILE__); break; default: printk("%s: The revision of the FlexCop chip on your card is %d\n", __FILE__, adapter->b2c2_revision); printk("%s: This driver works only with FlexCopII(rev.130), FlexCopIIB(rev.195) and FlexCopIII(rev.192).\n", __FILE__); free_adapter_object(adapter); pci_set_drvdata(pdev, NULL); release_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1)); release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); return -ENODEV; } decide_how_many_hw_filters(adapter); init_pids(adapter); tmp = read_reg_dw(adapter, 0x204); write_reg_dw(adapter, 0x204, 0); mdelay(20); write_reg_dw(adapter, 0x204, tmp); mdelay(10); tmp = read_reg_dw(adapter, 0x308); write_reg_dw(adapter, 0x308, 0x4000 | tmp); adapter->dw_sram_type = 0x10000; sll_detect_sram_size(adapter); dprintk("%s sram length = %d, sram type= %x\n", __FUNCTION__, sram_length(adapter), adapter->dw_sram_type); sram_set_media_dest(adapter, 1); sram_set_net_dest(adapter, 1); ctrl_enable_smc(adapter, 0); sram_set_cai_dest(adapter, 2); sram_set_cao_dest(adapter, 2); dma_enable_disable_irq(adapter, 1, 0, 0); if (eeprom_get_mac_addr(adapter, 0, adapter->mac_addr) != 0) { printk("%s MAC address = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n", __FUNCTION__, adapter->mac_addr[0], adapter->mac_addr[1], adapter->mac_addr[2], adapter->mac_addr[3], adapter->mac_addr[4], adapter->mac_addr[5], adapter->mac_addr[6], adapter->mac_addr[7] ); ca_set_mac_dst_addr_filter(adapter, adapter->mac_addr); ctrl_enable_mac(adapter, 1); } adapter->lock = SPIN_LOCK_UNLOCKED; return 0;}static void driver_halt(struct pci_dev *pdev){ struct adapter *adapter; adapter = pci_get_drvdata(pdev); irq_dma_enable_disable_irq(adapter, 0); ctrl_enable_receive_data(adapter, 0); free_adapter_object(adapter); pci_set_drvdata(pdev, NULL); release_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1)); release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));}static int dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed){ struct dvb_demux *dvbdmx = dvbdmxfeed->demux; struct adapter *adapter = (struct adapter *) dvbdmx->priv; dprintk("%s: PID=%d, type=%d\n", __FUNCTION__, dvbdmxfeed->pid, dvbdmxfeed->type); open_stream(adapter, dvbdmxfeed->pid); return 0;}static int dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed){ struct dvb_demux *dvbdmx = dvbdmxfeed->demux; struct adapter *adapter = (struct adapter *) dvbdmx->priv; dprintk("%s: PID=%d, type=%d\n", __FUNCTION__, dvbdmxfeed->pid, dvbdmxfeed->type); close_stream(adapter, dvbdmxfeed->pid); return 0;}/* lnb control */static void set_tuner_tone(struct adapter *adapter, u8 tone){ u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; u16 ax; dprintk("%s: %u\n", __FUNCTION__, tone); switch (tone) { case 1: ax = wz_half_period_for_45_mhz[0]; break; case 2: ax = wz_half_period_for_45_mhz[1]; break; case 3: ax = wz_half_period_for_45_mhz[2]; break; case 4: ax = wz_half_period_for_45_mhz[3]; break; default: ax = 0; } if (ax != 0) { write_reg_dw(adapter, 0x200, ((ax << 0x0f) + (ax & 0x7fff)) | 0x40000000); } else { write_reg_dw(adapter, 0x200, 0x40ff8000); }}static void set_tuner_polarity(struct adapter *adapter, u8 polarity){ u32 var; dprintk("%s : polarity = %u \n", __FUNCTION__, polarity); var = read_reg_dw(adapter, 0x204); if (polarity == 0) { dprintk("%s: LNB power off\n", __FUNCTION__); var = var | 1; }; if (polarity == 1) { var = var & ~1; var = var & ~4; }; if (polarity == 2) { var = var & ~1; var = var | 4; } write_reg_dw(adapter, 0x204, var);}static void diseqc_send_bit(struct adapter *adapter, int data){ set_tuner_tone(adapter, 1); udelay(data ? 500 : 1000); set_tuner_tone(adapter, 0); udelay(data ? 1000 : 500);}static void diseqc_send_byte(struct adapter *adapter, int data){ int i, par = 1, d; for (i = 7; i >= 0; i--) { d = (data >> i) & 1; par ^= d; diseqc_send_bit(adapter, d); } diseqc_send_bit(adapter, par);}static int send_diseqc_msg(struct adapter *adapter, int len, u8 *msg, unsigned long burst){ int i; set_tuner_tone(adapter, 0); mdelay(16); for (i = 0; i < len; i++) 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); } dvb_delay(20); } return 0;}int soft_diseqc(struct adapter *adapter, unsigned int cmd, void *arg){ switch (cmd) { case FE_SET_TONE: switch ((fe_sec_tone_mode_t) arg) { case SEC_TONE_ON: set_tuner_tone(adapter, 1); break; case SEC_TONE_OFF: set_tuner_tone(adapter, 0); break; default: return -EINVAL; }; break; case FE_DISEQC_SEND_MASTER_CMD: { struct dvb_diseqc_master_cmd *cmd = arg; send_diseqc_msg(adapter, cmd->msg_len, cmd->msg, 0); break; } case FE_DISEQC_SEND_BURST: send_diseqc_msg(adapter, 0, NULL, (unsigned long) arg); break; default: return -EOPNOTSUPP; }; return 0;}static int flexcop_diseqc_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg){ struct adapter *adapter = fe->before_after_data; struct dvb_frontend_info info; fe->ioctl(fe, FE_GET_INFO, &info); // we must use different DiSEqC hw if (strcmp(info.name, "Zarlink MT312") == 0) { //VP310 using mt312 driver for tuning only: diseqc not wired //use FCII instead if (!soft_diseqc(adapter, cmd, arg)) return 0; } switch (cmd) { case FE_SLEEP: { dprintk("%s: FE_SLEEP\n", __FUNCTION__); set_tuner_polarity(adapter, 0); // return -EOPNOTSUPP, to make DVB core also send "FE_SLEEP" command to frontend. return -EOPNOTSUPP; } case FE_SET_VOLTAGE: { dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__); switch ((fe_sec_voltage_t) arg) { 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; }; } default: return -EOPNOTSUPP; }; return 0;}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; int ret; if (pdev == NULL) return -ENODEV; if (driver_initialize(pdev) != 0) return -ENODEV; dvb_register_adapter(&dvb_adapter, skystar2_pci_driver.name); if (dvb_adapter == NULL) { printk("%s: Error registering DVB adapter\n", __FUNCTION__); driver_halt(pdev); return -ENODEV; } adapter = (struct adapter *) pci_get_drvdata(pdev); adapter->dvb_adapter = dvb_adapter; init_MUTEX(&adapter->i2c_sem); adapter->i2c_bus = dvb_register_i2c_bus(master_xfer, adapter, adapter->dvb_adapter, 0); if (!adapter->i2c_bus) return -ENOMEM; dvb_add_frontend_ioctls(adapter->dvb_adapter, flexcop_diseqc_ioctl, NULL, adapter); dvbdemux = &adapter->demux; dvbdemux->priv = (void *) 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 = 0; dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); dvb_dmx_init(&adapter->demux); adapter->hw_frontend.source = DMX_FRONTEND_0; adapter->dmxdev.filternum = N_PID_SLOTS; adapter->dmxdev.demux = &dvbdemux->dmx; adapter->dmxdev.capabilities = 0; dvb_dmxdev_init(&adapter->dmxdev, adapter->dvb_adapter); ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &adapter->hw_frontend); if (ret < 0) return ret; adapter->mem_frontend.source = DMX_MEMORY_FE; ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &adapter->mem_frontend); if (ret < 0) return ret; ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &adapter->hw_frontend); if (ret < 0) return ret; dvb_net_init(adapter->dvb_adapter, &adapter->dvbnet, &dvbdemux->dmx); return 0;}static void skystar2_remove(struct pci_dev *pdev){ struct adapter *adapter; struct dvb_demux *dvbdemux; if (pdev == NULL) return; adapter = pci_get_drvdata(pdev); if (adapter != NULL) { dvb_net_release(&adapter->dvbnet); dvbdemux = &adapter->demux; dvbdemux->dmx.close(&dvbdemux->dmx); dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->hw_frontend); dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->mem_frontend); dvb_dmxdev_release(&adapter->dmxdev); dvb_dmx_release(&adapter->demux); if (adapter->dvb_adapter != NULL) { dvb_remove_frontend_ioctls(adapter->dvb_adapter, flexcop_diseqc_ioctl, NULL); if (adapter->i2c_bus != NULL) dvb_unregister_i2c_bus(master_xfer, adapter->i2c_bus->adapter, adapter->i2c_bus->id); dvb_unregister_adapter(adapter->dvb_adapter); } 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}, //FCIII {0,},};static struct pci_driver skystar2_pci_driver = { .name = "Technisat SkyStar2 driver", .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_PARM(debug, "i");MODULE_PARM_DESC(debug, "enable verbose debug messages: supported values: 1 and 2");MODULE_PARM(enable_hw_filters, "i");MODULE_PARM_DESC(enable_hw_filters, "enable hardware filters: supported values: 0 (none), 1, 2");MODULE_DESCRIPTION("Technisat SkyStar2 DVB PCI Driver");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -