From c976bc82339437e840f7dbf0b8c89c09d3fcd75e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 22 Jul 2007 12:52:40 -0300 Subject: [PATCH] V4L/DVB (5922): ivtv, cx25840: postpone fw load until first use The firmware is now loaded when the driver is actually used for the first time. This allows the driver to be compiled in-kernel instead of as a module. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Makefile | 3 +- drivers/media/video/cx25840/cx25840-core.c | 21 ++- drivers/media/video/cx25840/cx25840-core.h | 1 + drivers/media/video/ivtv/ivtv-driver.c | 193 ++++++++++----------- drivers/media/video/ivtv/ivtv-driver.h | 5 + drivers/media/video/ivtv/ivtv-fileops.c | 9 + 6 files changed, 129 insertions(+), 103 deletions(-) diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 8f7205b558..c5286bfba4 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -64,7 +64,6 @@ obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o obj-$(CONFIG_VIDEO_MEYE) += meye.o obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ obj-$(CONFIG_VIDEO_CX88) += cx88/ -obj-$(CONFIG_VIDEO_IVTV) += ivtv/ obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o @@ -117,6 +116,8 @@ obj-$(CONFIG_USB_KONICAWC) += usbvideo/ obj-$(CONFIG_USB_VICAM) += usbvideo/ obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/ +obj-$(CONFIG_VIDEO_IVTV) += ivtv/ + obj-$(CONFIG_VIDEO_VIVI) += vivi.o EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 67bda9f9a4..9c12bd39cf 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -625,6 +625,22 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, struct v4l2_tuner *vt = arg; struct v4l2_routing *route = arg; + /* ignore these commands */ + switch (cmd) { + case TUNER_SET_TYPE_ADDR: + return 0; + } + + if (!state->is_initialized) { + v4l_dbg(1, cx25840_debug, client, "cmd %08x triggered fw load\n", cmd); + /* initialize on first use */ + state->is_initialized = 1; + if (state->is_cx25836) + cx25836_initialize(client); + else + cx25840_initialize(client, 1); + } + switch (cmd) { #ifdef CONFIG_VIDEO_ADV_DEBUG /* ioctls to allow direct access to the @@ -906,11 +922,6 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, i2c_attach_client(client); - if (state->is_cx25836) - cx25836_initialize(client); - else - cx25840_initialize(client, 1); - return 0; } diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h index f4b56d2fd6..8c1fbd9b87 100644 --- a/drivers/media/video/cx25840/cx25840-core.h +++ b/drivers/media/video/cx25840/cx25840-core.h @@ -46,6 +46,7 @@ struct cx25840_state { u32 id; u32 rev; int is_cx25836; + int is_initialized; }; /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 81cbaf7dd5..00bdcc2e8f 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -814,7 +814,6 @@ static void ivtv_request_module(struct ivtv *itv, const char *name) static void ivtv_load_and_init_modules(struct ivtv *itv) { - struct v4l2_control ctrl; u32 hw = itv->card->hw_all; int i; @@ -896,11 +895,6 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) } if (hw & IVTV_HW_CX25840) { - /* 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); - itv->vbi.raw_decoder_line_size = 1444; itv->vbi.raw_decoder_sav_odd_field = 0x20; itv->vbi.raw_decoder_sav_even_field = 0x60; @@ -946,12 +940,9 @@ static int __devinit ivtv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) { int retval = 0; - int video_input; int yuv_buf_size; int vbi_buf_size; - int fw_retry_count = 3; struct ivtv *itv; - struct v4l2_frequency vf; spin_lock(&ivtv_cards_lock); @@ -1038,22 +1029,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev, goto free_io; } - 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) { - IVTV_ERR("Error initializing firmware\n"); - goto free_i2c; - } - - /* Try and get firmware versions */ - IVTV_DEBUG_INFO("Getting firmware version..\n"); - ivtv_firmware_versions(itv); - /* Check yuv output filter table */ if (itv->has_cx23415) ivtv_yuv_filter_check(itv); @@ -1157,44 +1132,16 @@ static int __devinit ivtv_probe(struct pci_dev *dev, ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup); } - 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 */ - } - /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) are not. */ itv->tuner_std = itv->std; - 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); - retval = ivtv_streams_setup(itv); if (retval) { IVTV_ERR("Error %d setting up streams\n", retval); goto free_i2c; } - 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); - IVTV_DEBUG_IRQ("Masking interrupts\n"); /* clear interrupt mask, effectively disabling interrupts */ ivtv_set_irq_mask(itv, 0xffffffff); @@ -1206,26 +1153,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev, IVTV_ERR("Failed to register irq %d\n", retval); goto free_streams; } - - /* 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); - else - ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT); - - if (itv->has_cx23415) - ivtv_set_osd_alpha(itv); - IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name); - return 0; free_irq: @@ -1255,55 +1183,126 @@ static int __devinit ivtv_probe(struct pci_dev *dev, return retval; } +int ivtv_init_on_first_open(struct ivtv *itv) +{ + struct v4l2_frequency vf; + int fw_retry_count = 3; + int video_input; + + 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) { + IVTV_ERR("Error initializing firmware\n"); + return -1; + } + + /* 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); - /* 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); + 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_DEBUG_INFO("Disabling interrupts\n"); ivtv_set_irq_mask(itv, 0xffffffff); del_timer_sync(&itv->dma_timer); /* Stop all Work Queues */ - IVTV_DEBUG_INFO("Stop Work Queues\n"); flush_workqueue(itv->irq_work_queues); destroy_workqueue(itv->irq_work_queues); - IVTV_DEBUG_INFO("Stopping Firmware\n"); - ivtv_halt_firmware(itv); - - IVTV_DEBUG_INFO("Unregistering v4l devices\n"); ivtv_streams_cleanup(itv); - IVTV_DEBUG_INFO("Freeing dma resources\n"); ivtv_udma_free(itv); exit_ivtv_i2c(itv); - IVTV_DEBUG_INFO(" Releasing irq\n"); free_irq(itv->dev->irq, (void *)itv); ivtv_iounmap(itv); - IVTV_DEBUG_INFO(" Releasing mem\n"); 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) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 8fe9d9c7a1..6e53a1f04f 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -398,6 +398,8 @@ struct ivtv_mailbox_data { #define IVTV_F_I_WORK_HANDLER_PIO 18 /* there is work to be done for PIO */ #define IVTV_F_I_PIO 19 /* PIO in progress */ #define IVTV_F_I_DEC_PAUSED 20 /* the decoder is paused */ +#define IVTV_F_I_INITED 21 /* set after first open */ +#define IVTV_F_I_FAILED 22 /* set if first open failed */ /* Event notifications */ #define IVTV_F_I_EV_DEC_STOPPED 28 /* decoder stopped event */ @@ -838,6 +840,9 @@ int ivtv_waitq(wait_queue_head_t *waitq); struct tveeprom; /* forward reference */ void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv); +/* First-open initialization: load firmware, init cx25840, etc. */ +int ivtv_init_on_first_open(struct ivtv *itv); + /* This is a PCI post thing, where if the pci register is not read, then the write doesn't always take effect right away. By reading back the register any pending PCI writes will be performed (in order), and so diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 66ea3cbc36..4988608416 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -850,6 +850,15 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp) return -ENXIO; } + if (!test_and_set_bit(IVTV_F_I_INITED, &itv->i_flags)) + if (ivtv_init_on_first_open(itv)) + set_bit(IVTV_F_I_FAILED, &itv->i_flags); + + if (test_bit(IVTV_F_I_FAILED, &itv->i_flags)) { + printk(KERN_WARNING "ivtv: failed to initialize on minor %d\n", minor); + return -ENXIO; + } + if (y == IVTV_DEC_STREAM_TYPE_MPG && test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags)) return -EBUSY; -- 2.39.5