📄 ivtv-driver.c
字号:
itv->vbi.sliced_decoder_line_size = 51; itv->vbi.sliced_decoder_sav_odd_field = 0xAB; itv->vbi.sliced_decoder_sav_even_field = 0xEC; } if (hw & IVTV_HW_SAA717X) { itv->vbi.raw_decoder_line_size = 1443; itv->vbi.raw_decoder_sav_odd_field = 0x25; itv->vbi.raw_decoder_sav_even_field = 0x62; itv->vbi.sliced_decoder_line_size = 51; itv->vbi.sliced_decoder_sav_odd_field = 0xAB; itv->vbi.sliced_decoder_sav_even_field = 0xEC; }}static int __devinit ivtv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id){ int retval = 0; int yuv_buf_size; int vbi_buf_size; struct ivtv *itv; spin_lock(&ivtv_cards_lock); /* Make sure we've got a place for this card */ if (ivtv_cards_active == IVTV_MAX_CARDS) { printk(KERN_ERR "ivtv: Maximum number of cards detected (%d)\n", ivtv_cards_active); spin_unlock(&ivtv_cards_lock); return -ENOMEM; } itv = kzalloc(sizeof(struct ivtv), GFP_ATOMIC); if (itv == 0) { spin_unlock(&ivtv_cards_lock); return -ENOMEM; } ivtv_cards[ivtv_cards_active] = itv; itv->dev = dev; itv->num = ivtv_cards_active++; snprintf(itv->name, sizeof(itv->name) - 1, "ivtv%d", itv->num); IVTV_INFO("Initializing card #%d\n", itv->num); spin_unlock(&ivtv_cards_lock); ivtv_process_options(itv); if (itv->options.cardtype == -1) { retval = -ENODEV; goto err; } if (ivtv_init_struct1(itv)) { retval = -ENOMEM; goto err; } IVTV_DEBUG_INFO("base addr: 0x%08x\n", itv->base_addr); /* PCI Device Setup */ if ((retval = ivtv_setup_pci(itv, dev, pci_id)) != 0) { if (retval == -EIO) goto free_workqueue; else if (retval == -ENXIO) goto free_mem; } /* save itv in the pci struct for later use */ pci_set_drvdata(dev, itv); /* map io memory */ IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", itv->base_addr + IVTV_ENCODER_OFFSET, IVTV_ENCODER_SIZE); itv->enc_mem = ioremap_nocache(itv->base_addr + IVTV_ENCODER_OFFSET, IVTV_ENCODER_SIZE); if (!itv->enc_mem) { IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n"); IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n"); retval = -ENOMEM; goto free_mem; } if (itv->has_cx23415) { IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); itv->dec_mem = ioremap_nocache(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); if (!itv->dec_mem) { IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n"); IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n"); retval = -ENOMEM; goto free_mem; } } else { itv->dec_mem = itv->enc_mem; } /* map registers memory */ IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); itv->reg_mem = ioremap_nocache(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); if (!itv->reg_mem) { IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n"); IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n"); retval = -ENOMEM; goto free_io; } /* Check yuv output filter table */ if (itv->has_cx23415) ivtv_yuv_filter_check(itv); ivtv_gpio_init(itv); /* active i2c */ IVTV_DEBUG_INFO("activating i2c...\n"); if (init_ivtv_i2c(itv)) { IVTV_ERR("Could not initialize i2c\n"); goto free_io; } IVTV_DEBUG_INFO("Active card count: %d.\n", ivtv_cards_active); if (itv->card->hw_all & IVTV_HW_TVEEPROM) {#ifdef CONFIG_VIDEO_TVEEPROM_MODULE ivtv_request_module(itv, "tveeprom");#endif /* Based on the model number the cardtype may be changed. The PCI IDs are not always reliable. */ ivtv_process_eeprom(itv); } if (itv->std == 0) { itv->std = V4L2_STD_NTSC_M; } if (itv->options.tuner == -1) { int i; for (i = 0; i < IVTV_CARD_MAX_TUNERS; i++) { if ((itv->std & itv->card->tuners[i].std) == 0) continue; itv->options.tuner = itv->card->tuners[i].tuner; break; } } /* if no tuner was found, then pick the first tuner in the card list */ if (itv->options.tuner == -1 && itv->card->tuners[0].std) { itv->std = itv->card->tuners[0].std; itv->options.tuner = itv->card->tuners[0].tuner; } if (itv->options.radio == -1) itv->options.radio = (itv->card->radio_input.audio_type != 0); /* The card is now fully identified, continue with card-specific initialization. */ ivtv_init_struct2(itv); ivtv_load_and_init_modules(itv); if (itv->std & V4L2_STD_525_60) { itv->is_60hz = 1; itv->is_out_60hz = 1; } else { itv->is_50hz = 1; itv->is_out_50hz = 1; } itv->params.video_gop_size = itv->is_60hz ? 15 : 12; itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_MPG] = 0x08000; itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_PCM] = 0x01200; itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_MPG] = 0x10000; /* 0x15180 == 720 * 480 / 4, 0x19500 == 720 * 576 / 4 */ yuv_buf_size = itv->is_60hz ? 0x15180 : 0x19500; itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_YUV] = yuv_buf_size / 2; itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_YUV] = yuv_buf_size / 8; /* Setup VBI Raw Size. Should be big enough to hold PAL. It is possible to switch between PAL and NTSC, so we need to take the largest size here. */ /* 1456 is multiple of 16, real size = 1444 */ itv->vbi.raw_size = 1456; /* We use a buffer size of 1/2 of the total size needed for a frame. This is actually very useful, since we now receive a field at a time and that makes 'compressing' the raw data down to size by stripping off the SAV codes a lot easier. Note: having two different buffer sizes prevents standard switching on the fly. We need to find a better solution... */ vbi_buf_size = itv->vbi.raw_size * (itv->is_60hz ? 24 : 36) / 2; itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_VBI] = vbi_buf_size; itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_VBI] = sizeof(struct v4l2_sliced_vbi_data) * 36; if (itv->options.radio > 0) itv->v4l2_cap |= V4L2_CAP_RADIO; if (itv->options.tuner > -1 && itv->tunerid == 0) { struct tuner_setup setup; setup.addr = ADDR_UNSET; setup.type = itv->options.tuner; setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup); } /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) are not. */ itv->tuner_std = itv->std; if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std); } retval = ivtv_streams_setup(itv); if (retval) { IVTV_ERR("Error %d setting up streams\n", retval); goto free_i2c; } IVTV_DEBUG_IRQ("Masking interrupts\n"); /* clear interrupt mask, effectively disabling interrupts */ ivtv_set_irq_mask(itv, 0xffffffff); /* Register IRQ */ retval = request_irq(itv->dev->irq, ivtv_irq_handler, IRQF_SHARED | IRQF_DISABLED, itv->name, (void *)itv); if (retval) { IVTV_ERR("Failed to register irq %d\n", retval); goto free_streams; } retval = ivtv_streams_register(itv); if (retval) { IVTV_ERR("Error %d registering devices\n", retval); goto free_irq; } IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name); return 0; free_irq: free_irq(itv->dev->irq, (void *)itv); free_streams: ivtv_streams_cleanup(itv); free_i2c: exit_ivtv_i2c(itv); free_io: ivtv_iounmap(itv); free_mem: release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); if (itv->has_cx23415) release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); free_workqueue: destroy_workqueue(itv->irq_work_queues); err: if (retval == 0) retval = -ENODEV; IVTV_ERR("Error %d on initialization\n", retval); spin_lock(&ivtv_cards_lock); kfree(ivtv_cards[ivtv_cards_active]); ivtv_cards[ivtv_cards_active] = NULL; spin_unlock(&ivtv_cards_lock); return retval;}int ivtv_init_on_first_open(struct ivtv *itv){ struct v4l2_frequency vf; int fw_retry_count = 3; int video_input; if (test_bit(IVTV_F_I_FAILED, &itv->i_flags)) return -ENXIO; if (test_and_set_bit(IVTV_F_I_INITED, &itv->i_flags)) return 0; while (--fw_retry_count > 0) { /* load firmware */ if (ivtv_firmware_init(itv) == 0) break; if (fw_retry_count > 1) IVTV_WARN("Retry loading firmware\n"); } if (fw_retry_count == 0) { set_bit(IVTV_F_I_FAILED, &itv->i_flags); return -ENXIO; } /* Try and get firmware versions */ IVTV_DEBUG_INFO("Getting firmware version..\n"); ivtv_firmware_versions(itv); if (itv->card->hw_all & IVTV_HW_CX25840) { struct v4l2_control ctrl; /* CX25840_CID_ENABLE_PVR150_WORKAROUND */ ctrl.id = V4L2_CID_PRIVATE_BASE; ctrl.value = itv->pvr150_workaround; itv->video_dec_func(itv, VIDIOC_S_CTRL, &ctrl); } vf.tuner = 0; vf.type = V4L2_TUNER_ANALOG_TV; vf.frequency = 6400; /* the tuner 'baseline' frequency */ /* Set initial frequency. For PAL/SECAM broadcasts no 'default' channel exists AFAIK. */ if (itv->std == V4L2_STD_NTSC_M_JP) { vf.frequency = 1460; /* ch. 1 91250*16/1000 */ } else if (itv->std & V4L2_STD_NTSC_M) { vf.frequency = 1076; /* ch. 4 67250*16/1000 */ } video_input = itv->active_input; itv->active_input++; /* Force update of input */ ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_INPUT, &video_input); /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code in one place. */ itv->std++; /* Force full standard initialization */ itv->std_out = itv->std; ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_FREQUENCY, &vf); if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) { ivtv_init_mpeg_decoder(itv); } ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_STD, &itv->tuner_std); /* On a cx23416 this seems to be able to enable DMA to the chip? */ if (!itv->has_cx23415) write_reg_sync(0x03, IVTV_REG_DMACONTROL); /* Default interrupts enabled. For the PVR350 this includes the decoder VSYNC interrupt, which is always on. It is not only used during decoding but also by the OSD. Some old PVR250 cards had a cx23415, so testing for that is too general. Instead test if the card has video output capability. */ if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC); ivtv_set_osd_alpha(itv); } else ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT); return 0;}static void ivtv_remove(struct pci_dev *pci_dev){ struct ivtv *itv = pci_get_drvdata(pci_dev); IVTV_DEBUG_INFO("Removing Card #%d\n", itv->num); if (test_bit(IVTV_F_I_INITED, &itv->i_flags)) { /* Stop all captures */ IVTV_DEBUG_INFO("Stopping all streams\n"); if (atomic_read(&itv->capturing) > 0) ivtv_stop_all_captures(itv); /* Stop all decoding */ IVTV_DEBUG_INFO("Stopping decoding\n"); if (atomic_read(&itv->decoding) > 0) { int type; if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) type = IVTV_DEC_STREAM_TYPE_YUV; else type = IVTV_DEC_STREAM_TYPE_MPG; ivtv_stop_v4l2_decode_stream(&itv->streams[type], VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); } ivtv_halt_firmware(itv); } /* Interrupts */ ivtv_set_irq_mask(itv, 0xffffffff); del_timer_sync(&itv->dma_timer); /* Stop all Work Queues */ flush_workqueue(itv->irq_work_queues); destroy_workqueue(itv->irq_work_queues); ivtv_streams_cleanup(itv); ivtv_udma_free(itv); exit_ivtv_i2c(itv); free_irq(itv->dev->irq, (void *)itv); ivtv_iounmap(itv); release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); if (itv->has_cx23415) release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); pci_disable_device(itv->dev); IVTV_INFO("Removed %s, card #%d\n", itv->card_name, itv->num);}/* define a pci_driver for card detection */static struct pci_driver ivtv_pci_driver = { .name = "ivtv", .id_table = ivtv_pci_tbl, .probe = ivtv_probe, .remove = ivtv_remove,};static int module_start(void){ printk(KERN_INFO "ivtv: Start initialization, version %s\n", IVTV_VERSION); memset(ivtv_cards, 0, sizeof(ivtv_cards)); /* Validate parameters */ if (ivtv_first_minor < 0 || ivtv_first_minor >= IVTV_MAX_CARDS) { printk(KERN_ERR "ivtv: Exiting, ivtv_first_minor must be between 0 and %d\n", IVTV_MAX_CARDS - 1); return -1; } if (ivtv_debug < 0 || ivtv_debug > 2047) { ivtv_debug = 0; printk(KERN_INFO "ivtv: Debug value must be >= 0 and <= 2047\n"); } if (pci_register_driver(&ivtv_pci_driver)) { printk(KERN_ERR "ivtv: Error detecting PCI card\n"); return -ENODEV; } printk(KERN_INFO "ivtv: End initialization\n"); return 0;}static void module_cleanup(void){ int i, j; pci_unregister_driver(&ivtv_pci_driver); spin_lock(&ivtv_cards_lock); for (i = 0; i < ivtv_cards_active; i++) { if (ivtv_cards[i] == NULL) continue; for (j = 0; j < IVTV_VBI_FRAMES; j++) { kfree(ivtv_cards[i]->vbi.sliced_mpeg_data[j]); } kfree(ivtv_cards[i]); } spin_unlock(&ivtv_cards_lock);}/* Note: These symbols are exported because they are used by the ivtvfb framebuffer module and an infrared module for the IR-blaster. */EXPORT_SYMBOL(ivtv_set_irq_mask);EXPORT_SYMBOL(ivtv_cards_active);EXPORT_SYMBOL(ivtv_cards);EXPORT_SYMBOL(ivtv_cards_lock);EXPORT_SYMBOL(ivtv_api);EXPORT_SYMBOL(ivtv_vapi);EXPORT_SYMBOL(ivtv_vapi_result);EXPORT_SYMBOL(ivtv_clear_irq_mask);EXPORT_SYMBOL(ivtv_debug);EXPORT_SYMBOL(ivtv_reset_ir_gpio);EXPORT_SYMBOL(ivtv_udma_setup);EXPORT_SYMBOL(ivtv_udma_unmap);EXPORT_SYMBOL(ivtv_udma_alloc);EXPORT_SYMBOL(ivtv_udma_prepare);EXPORT_SYMBOL(ivtv_init_on_first_open);module_init(module_start);module_exit(module_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -