V4L/DVB (6056): ivtv: move serialization to the fileops level
authorHans Verkuil <hverkuil@xs4all.nl>
Sun, 19 Aug 2007 10:10:55 +0000 (07:10 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Wed, 10 Oct 2007 01:05:43 +0000 (22:05 -0300)
Serialization is now done on the open/close/ioctl level and also when the
read/write/poll start an encoder/decoder stream.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
drivers/media/video/ivtv/ivtv-fileops.c
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/ivtv/ivtv-streams.c

index 846e9bf..1f3c8d0 100644 (file)
@@ -502,7 +502,9 @@ ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_
 
        IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name);
 
+       mutex_lock(&itv->serialize_lock);
        rc = ivtv_start_capture(id);
+       mutex_unlock(&itv->serialize_lock);
        if (rc)
                return rc;
        return ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
@@ -613,7 +615,9 @@ retry:
        }
 
        /* Start decoder (returns 0 if already started) */
+       mutex_lock(&itv->serialize_lock);
        rc = ivtv_start_decoding(id, itv->speed);
+       mutex_unlock(&itv->serialize_lock);
        if (rc) {
                IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name);
 
@@ -681,8 +685,11 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait)
 
        /* Start a capture if there is none */
        if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
-               int rc = ivtv_start_capture(id);
+               int rc;
 
+               mutex_lock(&itv->serialize_lock);
+               rc = ivtv_start_capture(id);
+               mutex_unlock(&itv->serialize_lock);
                if (rc) {
                        IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n",
                                        s->name, rc);
@@ -788,6 +795,7 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp)
        /* 'Unclaim' this stream */
 
        /* Stop radio */
+       mutex_lock(&itv->serialize_lock);
        if (id->type == IVTV_ENC_STREAM_TYPE_RAD) {
                /* Closing radio device, return to TV mode */
                ivtv_mute(itv);
@@ -822,53 +830,26 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp)
                ivtv_stop_capture(id, 0);
        }
        kfree(id);
+       mutex_unlock(&itv->serialize_lock);
        return 0;
 }
 
-int ivtv_v4l2_open(struct inode *inode, struct file *filp)
+static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
 {
-       int x, y = 0;
+       struct ivtv *itv = s->itv;
        struct ivtv_open_id *item;
-       struct ivtv *itv = NULL;
-       struct ivtv_stream *s = NULL;
-       int minor = iminor(inode);
 
-       /* Find which card this open was on */
-       spin_lock(&ivtv_cards_lock);
-       for (x = 0; itv == NULL && x < ivtv_cards_active; x++) {
-               /* find out which stream this open was on */
-               for (y = 0; y < IVTV_MAX_STREAMS; y++) {
-                       s = &ivtv_cards[x]->streams[y];
-                       if (s->v4l2dev && s->v4l2dev->minor == minor) {
-                               itv = ivtv_cards[x];
-                               break;
-                       }
-               }
-       }
-       spin_unlock(&ivtv_cards_lock);
-
-       if (itv == NULL) {
-               /* Couldn't find a device registered
-                  on that minor, shouldn't happen! */
-               IVTV_WARN("No ivtv device found on minor %d\n", minor);
-               return -ENXIO;
-       }
-
-       if (ivtv_init_on_first_open(itv)) {
-               IVTV_ERR("Failed to initialize on minor %d\n", minor);
-               return -ENXIO;
-       }
        IVTV_DEBUG_FILE("open %s\n", s->name);
 
-       if (y == IVTV_DEC_STREAM_TYPE_MPG &&
+       if (s->type == IVTV_DEC_STREAM_TYPE_MPG &&
                test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags))
                return -EBUSY;
 
-       if (y == IVTV_DEC_STREAM_TYPE_YUV &&
+       if (s->type == IVTV_DEC_STREAM_TYPE_YUV &&
                test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_MPG].s_flags))
                return -EBUSY;
 
-       if (y == IVTV_DEC_STREAM_TYPE_YUV) {
+       if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
                if (read_reg(0x82c) == 0) {
                        IVTV_ERR("Tried to open YUV output device but need to send data to mpeg decoder before it can be used\n");
                        /* return -ENODEV; */
@@ -883,7 +864,7 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp)
                return -ENOMEM;
        }
        item->itv = itv;
-       item->type = y;
+       item->type = s->type;
        v4l2_prio_open(&itv->prio, &item->prio);
 
        item->open_id = itv->open_id++;
@@ -925,14 +906,50 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp)
        }
 
        /* YUV or MPG Decoding Mode? */
-       if (y == IVTV_DEC_STREAM_TYPE_MPG)
+       if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
                clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
-       else if (y == IVTV_DEC_STREAM_TYPE_YUV)
-       {
+       else if (s->type == IVTV_DEC_STREAM_TYPE_YUV)
                set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
+       return 0;
+}
+
+int ivtv_v4l2_open(struct inode *inode, struct file *filp)
+{
+       int res, x, y = 0;
+       struct ivtv *itv = NULL;
+       struct ivtv_stream *s = NULL;
+       int minor = iminor(inode);
+
+       /* Find which card this open was on */
+       spin_lock(&ivtv_cards_lock);
+       for (x = 0; itv == NULL && x < ivtv_cards_active; x++) {
+               /* find out which stream this open was on */
+               for (y = 0; y < IVTV_MAX_STREAMS; y++) {
+                       s = &ivtv_cards[x]->streams[y];
+                       if (s->v4l2dev && s->v4l2dev->minor == minor) {
+                               itv = ivtv_cards[x];
+                               break;
+                       }
+               }
        }
+       spin_unlock(&ivtv_cards_lock);
 
-       return 0;
+       if (itv == NULL) {
+               /* Couldn't find a device registered
+                  on that minor, shouldn't happen! */
+               IVTV_WARN("No ivtv device found on minor %d\n", minor);
+               return -ENXIO;
+       }
+
+       mutex_lock(&itv->serialize_lock);
+       if (ivtv_init_on_first_open(itv)) {
+               IVTV_ERR("Failed to initialize on minor %d\n", minor);
+               mutex_unlock(&itv->serialize_lock);
+               return -ENXIO;
+       }
+       res = ivtv_serialized_open(s, filp);
+       mutex_unlock(&itv->serialize_lock);
+       return res;
 }
 
 void ivtv_mute(struct ivtv *itv)
index 2c0f272..2061d82 100644 (file)
@@ -1446,11 +1446,15 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
                                return 0;
                        if (nonblocking)
                                return -EAGAIN;
-                       /* wait for event */
+                       /* Wait for event. Note that serialize_lock is locked,
+                          so to allow other processes to access the driver while
+                          we are waiting unlock first and later lock again. */
+                       mutex_unlock(&itv->serialize_lock);
                        prepare_to_wait(&itv->event_waitq, &wait, TASK_INTERRUPTIBLE);
                        if ((itv->i_flags & (IVTV_F_I_EV_DEC_STOPPED|IVTV_F_I_EV_VSYNC)) == 0)
                                schedule();
                        finish_wait(&itv->event_waitq, &wait);
+                       mutex_lock(&itv->serialize_lock);
                        if (signal_pending(current)) {
                                /* return if a signal was received */
                                IVTV_DEBUG_INFO("User stopped wait for event\n");
@@ -1580,12 +1584,9 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp,
        return 0;
 }
 
-int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
-                   unsigned long arg)
+static int ivtv_serialized_ioctl(struct ivtv *itv, struct inode *inode, struct file *filp,
+               unsigned int cmd, unsigned long arg)
 {
-       struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
-       struct ivtv *itv = id->itv;
-
        /* Filter dvb ioctls that cannot be handled by video_usercopy */
        switch (cmd) {
        case VIDEO_SELECT_SOURCE:
@@ -1620,3 +1621,16 @@ int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
        }
        return video_usercopy(inode, filp, cmd, arg, ivtv_v4l2_do_ioctl);
 }
+
+int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+                   unsigned long arg)
+{
+       struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
+       struct ivtv *itv = id->itv;
+       int res;
+
+       mutex_lock(&itv->serialize_lock);
+       res = ivtv_serialized_ioctl(itv, inode, filp, cmd, arg);
+       mutex_unlock(&itv->serialize_lock);
+       return res;
+}
index fab5c51..65fa247 100644 (file)
@@ -437,9 +437,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
        if (s->v4l2dev == NULL)
                return -EINVAL;
 
-       /* Big serialization lock to ensure no two streams are started
-          simultaneously: that can give all sorts of weird results. */
-       mutex_lock(&itv->serialize_lock);
        IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name);
 
        switch (s->type) {
@@ -481,7 +478,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
                        0, sizeof(itv->vbi.sliced_mpeg_size));
                break;
        default:
-               mutex_unlock(&itv->serialize_lock);
                return -EINVAL;
        }
        s->subtype = subtype;
@@ -564,7 +560,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
        if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype))
        {
                IVTV_DEBUG_WARN( "Error starting capture!\n");
-               mutex_unlock(&itv->serialize_lock);
                return -EINVAL;
        }
 
@@ -580,7 +575,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
 
        /* you're live! sit back and await interrupts :) */
        atomic_inc(&itv->capturing);
-       mutex_unlock(&itv->serialize_lock);
        return 0;
 }
 
@@ -751,9 +745,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
                stopmode = 1;
        }
 
-       /* ensure these actions are done only once */
-       mutex_lock(&itv->serialize_lock);
-
        /* end_capture */
        /* when: 0 =  end of GOP  1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */
        ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype);
@@ -810,7 +801,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
                ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP);
 
        if (atomic_read(&itv->capturing) > 0) {
-               mutex_unlock(&itv->serialize_lock);
                return 0;
        }
 
@@ -827,7 +817,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
        }
 
        wake_up(&s->waitq);
-       mutex_unlock(&itv->serialize_lock);
 
        return 0;
 }