Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit baa4072d authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB (6056): ivtv: move serialization to the fileops level



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: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 1aa32c2f
Loading
Loading
Loading
Loading
+56 −39
Original line number Diff line number Diff line
@@ -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;
}

	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);

	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)
+20 −6
Original line number Diff line number Diff line
@@ -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;
}
+0 −11
Original line number Diff line number Diff line
@@ -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;
}