📄 cx88-core.c
字号:
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;}int cx88_start_audio_dma(struct cx88_core *core){ /* setup fifo + format */ cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], 128, 0); cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], 128, 0); cx_write(MO_AUDD_LNGTH, 128); /* fifo bpl size */ cx_write(MO_AUDR_LNGTH, 128); /* fifo bpl size */ /* start dma */ cx_write(MO_AUD_DMACNTRL, 0x0003); /* Up and Down fifo enable */ return 0;}int cx88_stop_audio_dma(struct cx88_core *core){ /* stop dma */ cx_write(MO_AUD_DMACNTRL, 0x0000); return 0;}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 = WW_BG; } else if (V4L2_STD_PAL_DK & norm->id) { core->tvaudio = WW_DK; } else if (V4L2_STD_PAL_I & norm->id) { core->tvaudio = WW_I; } else if (V4L2_STD_SECAM_L & norm->id) { core->tvaudio = WW_L; } else if (V4L2_STD_SECAM_DK & norm->id) { core->tvaudio = WW_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); *//* This should be needed only on cx88-alsa. It seems that some cx88 chips have bugs and does require DMA enabled for it to work. */ cx88_start_audio_dma(core); 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); // 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); // 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))); // this is needed as well to set all tvnorm parameter cx88_set_scale(core, 320, 240, V4L2_FIELD_INTERLACED); // audio set_tvaudio(core); // tell i2c chips cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm->id); // 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)); atomic_inc(&core->refcount); core->pci_bus = pci->bus->number; core->pci_slot = PCI_SLOT(pci->devfn); core->pci_irqmask = 0x00fc00; init_MUTEX(&core->lock); core->nr = cx88_devcount++; sprintf(core->name,"cx88[%d]",core->nr); if (0 != get_ressources(core,pci)) { printk(KERN_ERR "CORE %s No more PCI ressources for " "subsystem: %04x:%04x, board: %s\n", core->name,pci->subsystem_vendor, pci->subsystem_device, cx88_boards[core->board].name); 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 "CORE %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]; core->radio_type = radio[core->nr]; if (UNSET == core->tuner_type) core->tuner_type = cx88_boards[core->board].tuner_type; if (UNSET == core->radio_type) core->radio_type = cx88_boards[core->board].radio_type; if (!core->tuner_addr) core->tuner_addr = cx88_boards[core->board].tuner_addr; if (!core->radio_addr) core->radio_addr = cx88_boards[core->board].radio_addr; printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n", core->tuner_type, core->tuner_addr<<1, core->radio_type, core->radio_addr<<1); core->tda9887_conf = cx88_boards[core->board].tda9887_conf; /* init hardware */ cx88_reset(core); cx88_i2c_init(core,pci); cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL); cx88_card_setup(core); cx88_ir_init(core,pci); 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); cx88_ir_fini(core); 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_print_irqbits);EXPORT_SYMBOL(cx88_core_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_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);EXPORT_SYMBOL(cx88_start_audio_dma);EXPORT_SYMBOL(cx88_stop_audio_dma);/* * Local variables: * c-basic-offset: 8 * End: * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -