📄 cx88-core.c
字号:
static int set_pll(struct cx88_core *core, int prescale, u32 ofreq){ static u32 pre[] = { 0, 0, 0, 3, 2, 1 }; u64 pll; u32 reg; int i; if (prescale < 2) prescale = 2; if (prescale > 5) prescale = 5; pll = ofreq * 8 * prescale * (u64)(1 << 20); do_div(pll,xtal); reg = (pll & 0x3ffffff) | (pre[prescale] << 26); if (((reg >> 20) & 0x3f) < 14) { printk("%s/0: pll out of range\n",core->name); return -1; } dprintk(1,"set_pll: MO_PLL_REG 0x%08x [old=0x%08x,freq=%d]\n", reg, cx_read(MO_PLL_REG), ofreq); cx_write(MO_PLL_REG, reg); for (i = 0; i < 100; i++) { reg = cx_read(MO_DEVICE_STATUS); if (reg & (1<<2)) { dprintk(1,"pll locked [pre=%d,ofreq=%d]\n", prescale,ofreq); return 0; } dprintk(1,"pll not locked yet, waiting ...\n"); msleep(10); } dprintk(1,"pll NOT locked [pre=%d,ofreq=%d]\n",prescale,ofreq); return -1;}static int set_tvaudio(struct cx88_core *core){ struct cx88_tvnorm *norm = core->tvnorm; if (CX88_VMUX_TELEVISION != INPUT(core->input)->type) return 0; if (V4L2_STD_PAL_BG & norm->id) { core->tvaudio = nicam ? WW_NICAM_BGDKL : WW_A2_BG; } else if (V4L2_STD_PAL_DK & norm->id) { core->tvaudio = nicam ? WW_NICAM_BGDKL : WW_A2_DK; } else if (V4L2_STD_PAL_I & norm->id) { core->tvaudio = WW_NICAM_I; } else if (V4L2_STD_SECAM_L & norm->id) { core->tvaudio = WW_SYSTEM_L_AM; } else if (V4L2_STD_SECAM_DK & norm->id) { core->tvaudio = WW_A2_DK; } else if ((V4L2_STD_NTSC_M & norm->id) || (V4L2_STD_PAL_M & norm->id)) { core->tvaudio = WW_BTSC; } else if (V4L2_STD_NTSC_M_JP & norm->id) { core->tvaudio = WW_EIAJ; } else { printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n", core->name, norm->name); core->tvaudio = 0; return 0; } cx_andor(MO_AFECFG_IO, 0x1f, 0x0); cx88_set_tvaudio(core); // cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO); cx_write(MO_AUDD_LNGTH, 128/8); /* fifo size */ cx_write(MO_AUDR_LNGTH, 128/8); /* fifo size */ cx_write(MO_AUD_DMACNTRL, 0x03); /* need audio fifo */ return 0;}int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm){ u32 fsc8; u32 adc_clock; u32 vdec_clock; u32 step_db,step_dr; u64 tmp64; u32 bdelay,agcdelay,htotal; core->tvnorm = norm; fsc8 = norm_fsc8(norm); adc_clock = xtal; vdec_clock = fsc8; step_db = fsc8; step_dr = fsc8; if (norm->id & V4L2_STD_SECAM) { step_db = 4250000 * 8; step_dr = 4406250 * 8; } dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n", norm->name, fsc8, adc_clock, vdec_clock, step_db, step_dr); set_pll(core,2,vdec_clock); dprintk(1,"set_tvnorm: MO_INPUT_FORMAT 0x%08x [old=0x%08x]\n", norm->cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f); cx_andor(MO_INPUT_FORMAT, 0xf, norm->cxiformat);#if 1 // FIXME: as-is from DScaler dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n", norm->cxoformat, cx_read(MO_OUTPUT_FORMAT)); cx_write(MO_OUTPUT_FORMAT, norm->cxoformat);#endif // MO_SCONV_REG = adc clock / video dec clock * 2^17 tmp64 = adc_clock * (u64)(1 << 17); do_div(tmp64, vdec_clock); dprintk(1,"set_tvnorm: MO_SCONV_REG 0x%08x [old=0x%08x]\n", (u32)tmp64, cx_read(MO_SCONV_REG)); cx_write(MO_SCONV_REG, (u32)tmp64); // MO_SUB_STEP = 8 * fsc / video dec clock * 2^22 tmp64 = step_db * (u64)(1 << 22); do_div(tmp64, vdec_clock); dprintk(1,"set_tvnorm: MO_SUB_STEP 0x%08x [old=0x%08x]\n", (u32)tmp64, cx_read(MO_SUB_STEP)); cx_write(MO_SUB_STEP, (u32)tmp64); // MO_SUB_STEP_DR = 8 * 4406250 / video dec clock * 2^22 tmp64 = step_dr * (u64)(1 << 22); do_div(tmp64, vdec_clock); dprintk(1,"set_tvnorm: MO_SUB_STEP_DR 0x%08x [old=0x%08x]\n", (u32)tmp64, cx_read(MO_SUB_STEP_DR)); cx_write(MO_SUB_STEP_DR, (u32)tmp64); // bdelay + agcdelay bdelay = vdec_clock * 65 / 20000000 + 21; agcdelay = vdec_clock * 68 / 20000000 + 15; dprintk(1,"set_tvnorm: MO_AGC_BURST 0x%08x [old=0x%08x,bdelay=%d,agcdelay=%d]\n", (bdelay << 8) | agcdelay, cx_read(MO_AGC_BURST), bdelay, agcdelay); cx_write(MO_AGC_BURST, (bdelay << 8) | agcdelay); // htotal tmp64 = norm_htotal(norm) * (u64)vdec_clock; do_div(tmp64, fsc8); htotal = (u32)tmp64 | (norm_notchfilter(norm) << 11); dprintk(1,"set_tvnorm: MO_HTOTAL 0x%08x [old=0x%08x,htotal=%d]\n", htotal, cx_read(MO_HTOTAL), (u32)tmp64); cx_write(MO_HTOTAL, htotal); // vbi stuff cx_write(MO_VBI_PACKET, ((1 << 11) | /* (norm_vdelay(norm) << 11) | */ norm_vbipack(norm))); // audio set_tvaudio(core); // tell i2c chips#ifdef V4L2_I2C_CLIENTS cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm->id);#else { struct video_channel c; memset(&c,0,sizeof(c)); c.channel = core->input; c.norm = VIDEO_MODE_PAL; if ((norm->id & (V4L2_STD_NTSC_M|V4L2_STD_NTSC_M_JP))) c.norm = VIDEO_MODE_NTSC; if (norm->id & V4L2_STD_SECAM) c.norm = VIDEO_MODE_SECAM; cx88_call_i2c_clients(core,VIDIOCSCHAN,&c); }#endif // done return 0;}/* ------------------------------------------------------------------ */static int cx88_pci_quirks(char *name, struct pci_dev *pci){ unsigned int lat = UNSET; u8 ctrl = 0; u8 value; /* check pci quirks */ if (pci_pci_problems & PCIPCI_TRITON) { printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n", name); ctrl |= CX88X_EN_TBFX; } if (pci_pci_problems & PCIPCI_NATOMA) { printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n", name); ctrl |= CX88X_EN_TBFX; } if (pci_pci_problems & PCIPCI_VIAETBF) { printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n", name); ctrl |= CX88X_EN_TBFX; } if (pci_pci_problems & PCIPCI_VSFX) { printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n", name); ctrl |= CX88X_EN_VSFX; }#ifdef PCIPCI_ALIMAGIK if (pci_pci_problems & PCIPCI_ALIMAGIK) { printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n", name); lat = 0x0A; }#endif /* check insmod options */ if (UNSET != latency) lat = latency; /* apply stuff */ if (ctrl) { pci_read_config_byte(pci, CX88X_DEVCTRL, &value); value |= ctrl; pci_write_config_byte(pci, CX88X_DEVCTRL, value); } if (UNSET != lat) { printk(KERN_INFO "%s: setting pci latency timer to %d\n", name, latency); pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency); } return 0;}/* ------------------------------------------------------------------ */struct video_device *cx88_vdev_init(struct cx88_core *core, struct pci_dev *pci, struct video_device *template, char *type){ struct video_device *vfd; vfd = video_device_alloc(); if (NULL == vfd) return NULL; *vfd = *template; vfd->minor = -1; vfd->dev = &pci->dev; vfd->release = video_device_release; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", core->name, type, cx88_boards[core->board].name); return vfd;}static int get_ressources(struct cx88_core *core, struct pci_dev *pci){ if (request_mem_region(pci_resource_start(pci,0), pci_resource_len(pci,0), core->name)) return 0; printk(KERN_ERR "%s: can't get MMIO memory @ 0x%lx\n", core->name,pci_resource_start(pci,0)); return -EBUSY;}struct cx88_core* cx88_core_get(struct pci_dev *pci){ struct cx88_core *core; struct list_head *item; int i; down(&devlist); list_for_each(item,&cx88_devlist) { core = list_entry(item, struct cx88_core, devlist); if (pci->bus->number != core->pci_bus) continue; if (PCI_SLOT(pci->devfn) != core->pci_slot) continue; if (0 != get_ressources(core,pci)) goto fail_unlock; atomic_inc(&core->refcount); up(&devlist); return core; } core = kmalloc(sizeof(*core),GFP_KERNEL); if (NULL == core) goto fail_unlock; memset(core,0,sizeof(*core)); core->pci_bus = pci->bus->number; core->pci_slot = PCI_SLOT(pci->devfn); atomic_inc(&core->refcount); core->nr = cx88_devcount++; sprintf(core->name,"cx88[%d]",core->nr); if (0 != get_ressources(core,pci)) { cx88_devcount--; goto fail_free; } list_add_tail(&core->devlist,&cx88_devlist); /* PCI stuff */ cx88_pci_quirks(core->name, pci); core->lmmio = ioremap(pci_resource_start(pci,0), pci_resource_len(pci,0)); core->bmmio = (u8 __iomem *)core->lmmio; /* board config */ core->board = UNSET; if (card[core->nr] < cx88_bcount) core->board = card[core->nr]; for (i = 0; UNSET == core->board && i < cx88_idcount; i++) if (pci->subsystem_vendor == cx88_subids[i].subvendor && pci->subsystem_device == cx88_subids[i].subdevice) core->board = cx88_subids[i].card; if (UNSET == core->board) { core->board = CX88_BOARD_UNKNOWN; cx88_card_list(core,pci); } printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", core->name,pci->subsystem_vendor, pci->subsystem_device,cx88_boards[core->board].name, core->board, card[core->nr] == core->board ? "insmod option" : "autodetected"); core->tuner_type = tuner[core->nr]; if (UNSET == core->tuner_type) core->tuner_type = cx88_boards[core->board].tuner_type; core->tda9887_conf = cx88_boards[core->board].tda9887_conf; /* init hardware */ cx88_reset(core); cx88_i2c_init(core,pci); cx88_card_setup(core); up(&devlist); return core;fail_free: kfree(core);fail_unlock: up(&devlist); return NULL;}void cx88_core_put(struct cx88_core *core, struct pci_dev *pci){ release_mem_region(pci_resource_start(pci,0), pci_resource_len(pci,0)); if (!atomic_dec_and_test(&core->refcount)) return; down(&devlist); if (0 == core->i2c_rc) i2c_bit_del_bus(&core->i2c_adap); list_del(&core->devlist); iounmap(core->lmmio); cx88_devcount--; up(&devlist); kfree(core);}/* ------------------------------------------------------------------ */EXPORT_SYMBOL(cx88_print_ioctl);EXPORT_SYMBOL(cx88_pci_irqs);EXPORT_SYMBOL(cx88_vid_irqs);EXPORT_SYMBOL(cx88_mpeg_irqs);EXPORT_SYMBOL(cx88_print_irqbits);EXPORT_SYMBOL(cx88_irq);EXPORT_SYMBOL(cx88_wakeup);EXPORT_SYMBOL(cx88_reset);EXPORT_SYMBOL(cx88_shutdown);EXPORT_SYMBOL(cx88_risc_buffer);EXPORT_SYMBOL(cx88_risc_databuffer);EXPORT_SYMBOL(cx88_risc_stopper);EXPORT_SYMBOL(cx88_free_buffer);EXPORT_SYMBOL(cx88_risc_disasm);EXPORT_SYMBOL(cx88_sram_channels);EXPORT_SYMBOL(cx88_sram_channel_setup);EXPORT_SYMBOL(cx88_sram_channel_dump);EXPORT_SYMBOL(cx88_set_tvnorm);EXPORT_SYMBOL(cx88_set_scale);EXPORT_SYMBOL(cx88_vdev_init);EXPORT_SYMBOL(cx88_core_get);EXPORT_SYMBOL(cx88_core_put);/* * Local variables: * c-basic-offset: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -