Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=18e16f9c954c6a931ee97584014c826255e0bdaa
Commit:     18e16f9c954c6a931ee97584014c826255e0bdaa
Parent:     34ca7d3791c6a467ff6810a149bdf78be086c23a
Author:     Hans Verkuil <[EMAIL PROTECTED]>
AuthorDate: Sat Oct 13 05:54:48 2007 -0300
Committer:  Mauro Carvalho Chehab <[EMAIL PROTECTED]>
CommitDate: Mon Oct 22 12:01:47 2007 -0200

    V4L/DVB (6342): ivtv: fix circular locking (bug 9037)
    
    If you try to access the video device from within an udev rule,
    then you get into a circular locking situation.
    
    Changed the driver to postpone the registration of the devices until
    everything else has been fully initialized, so that the newly created
    device can be used immediately.
    
    Signed-off-by: Hans Verkuil <[EMAIL PROTECTED]>
    Signed-off-by: Mauro Carvalho Chehab <[EMAIL PROTECTED]>
---
 drivers/media/video/ivtv/ivtv-driver.c  |   11 ++--
 drivers/media/video/ivtv/ivtv-streams.c |  100 ++++++++++++++++++-------------
 drivers/media/video/ivtv/ivtv-streams.h |    1 +
 3 files changed, 65 insertions(+), 47 deletions(-)

diff --git a/drivers/media/video/ivtv/ivtv-driver.c 
b/drivers/media/video/ivtv/ivtv-driver.c
index fd7a932..6d2dd87 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -1003,8 +1003,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
 
        IVTV_DEBUG_INFO("base addr: 0x%08x\n", itv->base_addr);
 
-       mutex_lock(&itv->serialize_lock);
-
        /* PCI Device Setup */
        if ((retval = ivtv_setup_pci(itv, dev, pci_id)) != 0) {
                if (retval == -EIO)
@@ -1064,7 +1062,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
        IVTV_DEBUG_INFO("activating i2c...\n");
        if (init_ivtv_i2c(itv)) {
                IVTV_ERR("Could not initialize i2c\n");
-               goto free_irq;
+               goto free_io;
        }
 
        IVTV_DEBUG_INFO("Active card count: %d.\n", ivtv_cards_active);
@@ -1176,7 +1174,11 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
                IVTV_ERR("Failed to register irq %d\n", retval);
                goto free_streams;
        }
-       mutex_unlock(&itv->serialize_lock);
+       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;
 
@@ -1195,7 +1197,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
                release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, 
IVTV_DECODER_SIZE);
       free_workqueue:
        destroy_workqueue(itv->irq_work_queues);
-       mutex_unlock(&itv->serialize_lock);
       err:
        if (retval == 0)
                retval = -ENODEV;
diff --git a/drivers/media/video/ivtv/ivtv-streams.c 
b/drivers/media/video/ivtv/ivtv-streams.c
index ff4cb16..6c954b3 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -166,10 +166,9 @@ static void ivtv_stream_init(struct ivtv *itv, int type)
        ivtv_queue_init(&s->q_io);
 }
 
-static int ivtv_reg_dev(struct ivtv *itv, int type)
+static int ivtv_prep_dev(struct ivtv *itv, int type)
 {
        struct ivtv_stream *s = &itv->streams[type];
-       int vfl_type = ivtv_stream_info[type].vfl_type;
        int minor_offset = ivtv_stream_info[type].minor_offset;
        int minor;
 
@@ -187,15 +186,12 @@ static int ivtv_reg_dev(struct ivtv *itv, int type)
        if (type >= IVTV_DEC_STREAM_TYPE_MPG && !(itv->v4l2_cap & 
V4L2_CAP_VIDEO_OUTPUT))
                return 0;
 
-       if (minor_offset >= 0)
-               /* card number + user defined offset + device offset */
-               minor = itv->num + ivtv_first_minor + minor_offset;
-       else
-               minor = -1;
+       /* card number + user defined offset + device offset */
+       minor = itv->num + ivtv_first_minor + minor_offset;
 
        /* User explicitly selected 0 buffers for these streams, so don't
           create them. */
-       if (minor >= 0 && ivtv_stream_info[type].dma != PCI_DMA_NONE &&
+       if (ivtv_stream_info[type].dma != PCI_DMA_NONE &&
            itv->options.kilobytes[type] == 0) {
                IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name);
                return 0;
@@ -223,21 +219,53 @@ static int ivtv_reg_dev(struct ivtv *itv, int type)
        s->v4l2dev->fops = ivtv_stream_info[type].fops;
        s->v4l2dev->release = video_device_release;
 
-       if (minor >= 0) {
-               /* Register device. First try the desired minor, then any free 
one. */
-               if (video_register_device(s->v4l2dev, vfl_type, minor) &&
-                   video_register_device(s->v4l2dev, vfl_type, -1)) {
-                       IVTV_ERR("Couldn't register v4l2 device for %s minor 
%d\n",
-                                       s->name, minor);
-                       video_device_release(s->v4l2dev);
-                       s->v4l2dev = NULL;
-                       return -ENOMEM;
-               }
+       return 0;
+}
+
+/* Initialize v4l2 variables and prepare v4l2 devices */
+int ivtv_streams_setup(struct ivtv *itv)
+{
+       int type;
+
+       /* Setup V4L2 Devices */
+       for (type = 0; type < IVTV_MAX_STREAMS; type++) {
+               /* Prepare device */
+               if (ivtv_prep_dev(itv, type))
+                       break;
+
+               if (itv->streams[type].v4l2dev == NULL)
+                       continue;
+
+               /* Allocate Stream */
+               if (ivtv_stream_alloc(&itv->streams[type]))
+                       break;
        }
-       else {
-               /* Don't register a 'hidden' stream (OSD) */
-               IVTV_INFO("Created framebuffer stream for %s\n", s->name);
+       if (type == IVTV_MAX_STREAMS)
                return 0;
+
+       /* One or more streams could not be initialized. Clean 'em all up. */
+       ivtv_streams_cleanup(itv);
+       return -ENOMEM;
+}
+
+static int ivtv_reg_dev(struct ivtv *itv, int type)
+{
+       struct ivtv_stream *s = &itv->streams[type];
+       int vfl_type = ivtv_stream_info[type].vfl_type;
+       int minor;
+
+       if (s->v4l2dev == NULL)
+               return 0;
+
+       minor = s->v4l2dev->minor;
+       /* Register device. First try the desired minor, then any free one. */
+       if (video_register_device(s->v4l2dev, vfl_type, minor) &&
+                       video_register_device(s->v4l2dev, vfl_type, -1)) {
+               IVTV_ERR("Couldn't register v4l2 device for %s minor %d\n",
+                               s->name, minor);
+               video_device_release(s->v4l2dev);
+               s->v4l2dev = NULL;
+               return -ENOMEM;
        }
 
        switch (vfl_type) {
@@ -262,27 +290,18 @@ static int ivtv_reg_dev(struct ivtv *itv, int type)
        return 0;
 }
 
-/* Initialize v4l2 variables and register v4l2 devices */
-int ivtv_streams_setup(struct ivtv *itv)
+/* Register v4l2 devices */
+int ivtv_streams_register(struct ivtv *itv)
 {
        int type;
+       int err = 0;
 
-       /* Setup V4L2 Devices */
-       for (type = 0; type < IVTV_MAX_STREAMS; type++) {
-               /* Register Device */
-               if (ivtv_reg_dev(itv, type))
-                       break;
-
-               if (itv->streams[type].v4l2dev == NULL)
-                       continue;
+       /* Register V4L2 devices */
+       for (type = 0; type < IVTV_MAX_STREAMS; type++)
+               err |= ivtv_reg_dev(itv, type);
 
-               /* Allocate Stream */
-               if (ivtv_stream_alloc(&itv->streams[type]))
-                       break;
-       }
-       if (type == IVTV_MAX_STREAMS) {
+       if (err == 0)
                return 0;
-       }
 
        /* One or more streams could not be initialized. Clean 'em all up. */
        ivtv_streams_cleanup(itv);
@@ -303,11 +322,8 @@ void ivtv_streams_cleanup(struct ivtv *itv)
                        continue;
 
                ivtv_stream_free(&itv->streams[type]);
-               /* Free Device */
-               if (vdev->minor == -1) /* 'Hidden' never registered stream 
(OSD) */
-                       video_device_release(vdev);
-               else    /* All others, just unregister. */
-                       video_unregister_device(vdev);
+               /* Unregister device */
+               video_unregister_device(vdev);
        }
 }
 
diff --git a/drivers/media/video/ivtv/ivtv-streams.h 
b/drivers/media/video/ivtv/ivtv-streams.h
index 8f5f5b1..3d76a41 100644
--- a/drivers/media/video/ivtv/ivtv-streams.h
+++ b/drivers/media/video/ivtv/ivtv-streams.h
@@ -22,6 +22,7 @@
 #define IVTV_STREAMS_H
 
 int ivtv_streams_setup(struct ivtv *itv);
+int ivtv_streams_register(struct ivtv *itv);
 void ivtv_streams_cleanup(struct ivtv *itv);
 
 /* Capture related */
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to