📄 cx88-video.c
字号:
}static void cx8800_vid_irq(struct cx8800_dev *dev){ u32 status, mask, count; status = cx_read(MO_VID_INTSTAT); mask = cx_read(MO_VID_INTMSK); if (0 == (status & mask)) return; cx_write(MO_VID_INTSTAT, status); if (irq_debug || (status & mask & ~0xff)) cx88_print_irqbits(dev->name, "irq vid", cx88_vid_irqs, status, mask); /* risc op code error */ if (status & (1 << 16)) { printk(KERN_WARNING "%s: video risc op code error\n",dev->name); cx_clear(MO_VID_DMACNTRL, 0x11); cx_clear(VID_CAPTURE_CONTROL, 0x06); cx88_sram_channel_dump(dev, &cx88_sram_channels[SRAM_CH21]); } /* risc1 y */ if (status & 0x01) { spin_lock(&dev->slock); count = cx_read(MO_VIDY_GPCNT); cx8800_wakeup(dev, &dev->vidq, count); spin_unlock(&dev->slock); } /* risc1 vbi */ if (status & 0x08) { spin_lock(&dev->slock); count = cx_read(MO_VBI_GPCNT); cx8800_wakeup(dev, &dev->vbiq, count); spin_unlock(&dev->slock); } /* risc2 y */ if (status & 0x10) { dprintk(2,"stopper video\n"); spin_lock(&dev->slock); restart_video_queue(dev,&dev->vidq); spin_unlock(&dev->slock); } /* risc2 vbi */ if (status & 0x80) { dprintk(2,"stopper vbi\n"); spin_lock(&dev->slock); cx8800_restart_vbi_queue(dev,&dev->vbiq); spin_unlock(&dev->slock); }}static irqreturn_t cx8800_irq(int irq, void *dev_id, struct pt_regs *regs){ struct cx8800_dev *dev = dev_id; u32 status, mask; int loop, handled = 0; for (loop = 0; loop < 10; loop++) { status = cx_read(MO_PCI_INTSTAT); mask = cx_read(MO_PCI_INTMSK); if (0 == (status & mask)) goto out; handled = 1; cx_write(MO_PCI_INTSTAT, status); if (irq_debug || (status & mask & ~0x1f)) cx88_print_irqbits(dev->name, "irq pci", cx88_pci_irqs, status, mask); if (status & 1) cx8800_vid_irq(dev); }; if (10 == loop) { printk(KERN_WARNING "%s: irq loop -- clearing mask\n", dev->name); cx_write(MO_PCI_INTMSK,0); } out: return IRQ_RETVAL(handled);}/* ----------------------------------------------------------- *//* exported stuff */static struct file_operations video_fops ={ .owner = THIS_MODULE, .open = video_open, .release = video_release, .read = video_read, .poll = video_poll, .mmap = video_mmap, .ioctl = video_ioctl, .llseek = no_llseek,};struct video_device cx8800_video_template ={ .name = "cx8800-video", .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES, .hardware = 0, .fops = &video_fops, .minor = -1,};struct video_device cx8800_vbi_template ={ .name = "cx8800-vbi", .type = VID_TYPE_TELETEXT|VID_TYPE_TUNER, .hardware = 0, .fops = &video_fops, .minor = -1,};static struct file_operations radio_fops ={ .owner = THIS_MODULE, .open = video_open, .release = video_release, .ioctl = radio_ioctl, .llseek = no_llseek,};struct video_device cx8800_radio_template ={ .name = "cx8800-radio", .type = VID_TYPE_TUNER, .hardware = 0, .fops = &radio_fops, .minor = -1,};/* ----------------------------------------------------------- */static void cx8800_shutdown(struct cx8800_dev *dev){ /* disable RISC controller + IRQs */ cx_write(MO_DEV_CNTRL2, 0); /* stop dma transfers */ cx_write(MO_VID_DMACNTRL, 0x0); cx_write(MO_AUD_DMACNTRL, 0x0); cx_write(MO_TS_DMACNTRL, 0x0); cx_write(MO_VIP_DMACNTRL, 0x0); cx_write(MO_GPHST_DMACNTRL, 0x0); /* stop interupts */ cx_write(MO_PCI_INTMSK, 0x0); cx_write(MO_VID_INTMSK, 0x0); cx_write(MO_AUD_INTMSK, 0x0); cx_write(MO_TS_INTMSK, 0x0); cx_write(MO_VIP_INTMSK, 0x0); cx_write(MO_GPHST_INTMSK, 0x0); /* stop capturing */ cx_write(VID_CAPTURE_CONTROL, 0);}static int cx8800_reset(struct cx8800_dev *dev){ dprintk(1,"cx8800_reset\n"); cx8800_shutdown(dev); /* clear irq status */ cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int cx_write(MO_INT1_STAT, 0xFFFFFFFF); // Clear RISC int /* wait a bit */ set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ/10); /* init sram */ cx88_sram_channel_setup(dev, &cx88_sram_channels[SRAM_CH21], 720*4, 0); cx88_sram_channel_setup(dev, &cx88_sram_channels[SRAM_CH22], 128, 0); cx88_sram_channel_setup(dev, &cx88_sram_channels[SRAM_CH23], 128, 0); cx88_sram_channel_setup(dev, &cx88_sram_channels[SRAM_CH24], 128, 0); cx88_sram_channel_setup(dev, &cx88_sram_channels[SRAM_CH25], 128, 0); cx88_sram_channel_setup(dev, &cx88_sram_channels[SRAM_CH26], 128, 0); /* misc init ... */ cx_write(MO_INPUT_FORMAT, ((1 << 13) | // agc enable (1 << 12) | // agc gain (1 << 11) | // adaptibe agc (0 << 10) | // chroma agc (0 << 9) | // ckillen (7))); /* setup image format */ cx_andor(MO_COLOR_CTRL, 0x4000, 0x4000); /* setup FIFO Threshholds */ cx_write(MO_PDMA_STHRSH, 0x0807); cx_write(MO_PDMA_DTHRSH, 0x0807); /* fixes flashing of image */ cx_write(MO_AGC_SYNC_TIP1, 0x0380000F); cx_write(MO_AGC_BACK_VBI, 0x00E00555); cx_write(MO_VID_INTSTAT, 0xFFFFFFFF); // Clear PIV int cx_write(MO_PCI_INTSTAT, 0xFFFFFFFF); // Clear PCI int cx_write(MO_INT1_STAT, 0xFFFFFFFF); // Clear RISC int return 0;}static struct video_device *vdev_init(struct cx8800_dev *dev, 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 = &dev->pci->dev; vfd->release = video_device_release; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, type, cx88_boards[dev->board].name); return vfd;}static void cx8800_unregister_video(struct cx8800_dev *dev){ if (dev->radio_dev) { if (-1 != dev->radio_dev->minor) video_unregister_device(dev->radio_dev); else video_device_release(dev->radio_dev); dev->radio_dev = NULL; } if (dev->vbi_dev) { if (-1 != dev->vbi_dev->minor) video_unregister_device(dev->vbi_dev); else video_device_release(dev->vbi_dev); dev->vbi_dev = NULL; } if (dev->video_dev) { if (-1 != dev->video_dev->minor) video_unregister_device(dev->video_dev); else video_device_release(dev->video_dev); dev->video_dev = NULL; }}static int __devinit cx8800_initdev(struct pci_dev *pci_dev, const struct pci_device_id *pci_id){ struct cx8800_dev *dev; unsigned int i; int err; dev = kmalloc(sizeof(*dev),GFP_KERNEL); if (NULL == dev) return -ENOMEM; memset(dev,0,sizeof(*dev)); /* pci init */ dev->pci = pci_dev; if (pci_enable_device(pci_dev)) { err = -EIO; goto fail1; } sprintf(dev->name,"cx%x[%d]",pci_dev->device,cx8800_devcount); /* pci quirks */ cx88_pci_quirks(dev->name, dev->pci, &latency); if (UNSET != latency) { printk(KERN_INFO "%s: setting pci latency timer to %d\n", dev->name,latency); pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency); } /* print pci info */ pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, " "latency: %d, mmio: 0x%lx\n", dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq, dev->pci_lat,pci_resource_start(pci_dev,0)); pci_set_master(pci_dev); if (!pci_dma_supported(pci_dev,0xffffffff)) { printk("%s: Oops: no 32bit PCI DMA ???\n",dev->name); err = -EIO; goto fail1; } /* board config */ dev->board = card[cx8800_devcount]; for (i = 0; UNSET == dev->board && i < cx88_idcount; i++) if (pci_dev->subsystem_vendor == cx88_subids[i].subvendor && pci_dev->subsystem_device == cx88_subids[i].subdevice) dev->board = cx88_subids[i].card; if (UNSET == dev->board) { dev->board = CX88_BOARD_UNKNOWN; cx88_card_list(dev); } printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", dev->name,pci_dev->subsystem_vendor, pci_dev->subsystem_device,cx88_boards[dev->board].name, dev->board, card[cx8800_devcount] == dev->board ? "insmod option" : "autodetected"); dev->tuner_type = tuner[cx8800_devcount]; if (UNSET == dev->tuner_type) dev->tuner_type = cx88_boards[dev->board].tuner_type; /* get mmio */ if (!request_mem_region(pci_resource_start(pci_dev,0), pci_resource_len(pci_dev,0), dev->name)) { err = -EBUSY; printk(KERN_ERR "%s: can't get MMIO memory @ 0x%lx\n", dev->name,pci_resource_start(pci_dev,0)); goto fail1; } dev->lmmio = ioremap(pci_resource_start(pci_dev,0), pci_resource_len(pci_dev,0)); dev->bmmio = (u8*)dev->lmmio; /* initialize driver struct */ init_MUTEX(&dev->lock); dev->slock = SPIN_LOCK_UNLOCKED; dev->tvnorm = tvnorms; /* init video dma queues */ INIT_LIST_HEAD(&dev->vidq.active); INIT_LIST_HEAD(&dev->vidq.queued); dev->vidq.timeout.function = cx8800_vid_timeout; dev->vidq.timeout.data = (unsigned long)dev; init_timer(&dev->vidq.timeout); cx88_risc_stopper(dev->pci,&dev->vidq.stopper, MO_VID_DMACNTRL,0x11,0x00); /* init vbi dma queues */ INIT_LIST_HEAD(&dev->vbiq.active); INIT_LIST_HEAD(&dev->vbiq.queued); dev->vbiq.timeout.function = cx8800_vbi_timeout; dev->vbiq.timeout.data = (unsigned long)dev; init_timer(&dev->vbiq.timeout); cx88_risc_stopper(dev->pci,&dev->vbiq.stopper, MO_VID_DMACNTRL,0x88,0x00); /* initialize hardware */ cx8800_reset(dev); /* get irq */ err = request_irq(pci_dev->irq, cx8800_irq, SA_SHIRQ | SA_INTERRUPT, dev->name, dev); if (err < 0) { printk(KERN_ERR "%s: can't get IRQ %d\n", dev->name,pci_dev->irq); goto fail2; } /* register i2c bus + load i2c helpers */ cx8800_i2c_init(dev); cx88_card_setup(dev); /* load and configure helper modules */ if (TUNER_ABSENT != dev->tuner_type) request_module("tuner"); if (cx88_boards[dev->board].needs_tda9887) request_module("tda9887"); if (dev->tuner_type != UNSET) cx8800_call_i2c_clients(dev,TUNER_SET_TYPE,&dev->tuner_type); /* register v4l devices */ dev->video_dev = vdev_init(dev,&cx8800_video_template,"video"); err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, video_nr[cx8800_devcount]); if (err < 0) { printk(KERN_INFO "%s: can't register video device\n", dev->name); goto fail3; } printk(KERN_INFO "%s: registered device video%d [v4l2]\n", dev->name,dev->video_dev->minor & 0x1f); dev->vbi_dev = vdev_init(dev,&cx8800_vbi_template,"vbi"); err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, vbi_nr[cx8800_devcount]); if (err < 0) { printk(KERN_INFO "%s: can't register vbi device\n", dev->name); goto fail3; } printk(KERN_INFO "%s: registered device vbi%d\n", dev->name,dev->vbi_dev->minor & 0x1f); if (dev->has_radio) { dev->radio_dev = vdev_init(dev,&cx8800_radio_template,"radio"); err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, radio_nr[cx8800_devcount]); if (err < 0) { printk(KERN_INFO "%s: can't register radio device\n", dev->name); goto fail3; } printk(KERN_INFO "%s: registered device radio%d\n", dev->name,dev->radio_dev->minor & 0x1f); } /* everything worked */ list_add_tail(&dev->devlist,&cx8800_devlist); pci_set_drvdata(pci_dev,dev); cx8800_devcount++; /* initial device configuration */ down(&dev->lock); init_controls(dev); set_tvnorm(dev,tvnorms); video_mux(dev,0); up(&dev->lock); /* start tvaudio thread */ init_completion(&dev->texit); dev->tpid = kernel_thread(cx88_audio_thread, dev, 0); return 0; fail3: cx8800_unregister_video(dev); if (0 == dev->i2c_rc) i2c_bit_del_bus(&dev->i2c_adap); free_irq(pci_dev->irq, dev); fail2: release_mem_region(pci_resource_start(pci_dev,0), pci_resource_len(pci_dev,0)); fail1: kfree(dev); return err;}static void __devexit cx8800_finidev(struct pci_dev *pci_dev){ struct cx8800_dev *dev = pci_get_drvdata(pci_dev); /* stop thread */ dev->shutdown = 1; if (dev->tpid >= 0) wait_for_completion(&dev->texit); cx8800_shutdown(dev); pci_disable_device(pci_dev); /* unregister stuff */ if (0 == dev->i2c_rc) i2c_bit_del_bus(&dev->i2c_adap); free_irq(pci_dev->irq, dev); release_mem_region(pci_resource_start(pci_dev,0), pci_resource_len(pci_dev,0)); cx8800_unregister_video(dev); pci_set_drvdata(pci_dev, NULL); /* free memory */ btcx_riscmem_free(dev->pci,&dev->vidq.stopper); list_del(&dev->devlist); cx8800_devcount--; kfree(dev);}static int cx8800_suspend(struct pci_dev *pci_dev, u32 state){ struct cx8800_dev *dev = pci_get_drvdata(pci_dev); printk("%s: suspend %d\n", dev->name, state); cx8800_shutdown(dev); del_timer(&dev->vidq.timeout); pci_save_state(pci_dev, dev->state.pci_cfg); if (0 != pci_set_power_state(pci_dev, state)) { pci_disable_device(pci_dev); dev->state.disabled = 1; } return 0;}static int cx8800_resume(struct pci_dev *pci_dev){ struct cx8800_dev *dev = pci_get_drvdata(pci_dev); printk("%s: resume\n", dev->name); if (dev->state.disabled) { pci_enable_device(pci_dev); dev->state.disabled = 0; } pci_set_power_state(pci_dev, 0); pci_restore_state(pci_dev, dev->state.pci_cfg); /* re-initialize hardware */ cx8800_reset(dev); /* restart video capture */ spin_lock(&dev->slock); restart_video_queue(dev,&dev->vidq); spin_unlock(&dev->slock); return 0;}/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -