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: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
This commit is contained in:
parent
1aa32c2ffd
commit
baa4072d84
3 changed files with 76 additions and 56 deletions
|
@ -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);
|
IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name);
|
||||||
|
|
||||||
|
mutex_lock(&itv->serialize_lock);
|
||||||
rc = ivtv_start_capture(id);
|
rc = ivtv_start_capture(id);
|
||||||
|
mutex_unlock(&itv->serialize_lock);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
return ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
|
return ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
|
||||||
|
@ -613,7 +615,9 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Start decoder (returns 0 if already started) */
|
/* Start decoder (returns 0 if already started) */
|
||||||
|
mutex_lock(&itv->serialize_lock);
|
||||||
rc = ivtv_start_decoding(id, itv->speed);
|
rc = ivtv_start_decoding(id, itv->speed);
|
||||||
|
mutex_unlock(&itv->serialize_lock);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name);
|
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 */
|
/* Start a capture if there is none */
|
||||||
if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
|
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) {
|
if (rc) {
|
||||||
IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n",
|
IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n",
|
||||||
s->name, rc);
|
s->name, rc);
|
||||||
|
@ -788,6 +795,7 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp)
|
||||||
/* 'Unclaim' this stream */
|
/* 'Unclaim' this stream */
|
||||||
|
|
||||||
/* Stop radio */
|
/* Stop radio */
|
||||||
|
mutex_lock(&itv->serialize_lock);
|
||||||
if (id->type == IVTV_ENC_STREAM_TYPE_RAD) {
|
if (id->type == IVTV_ENC_STREAM_TYPE_RAD) {
|
||||||
/* Closing radio device, return to TV mode */
|
/* Closing radio device, return to TV mode */
|
||||||
ivtv_mute(itv);
|
ivtv_mute(itv);
|
||||||
|
@ -822,53 +830,26 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp)
|
||||||
ivtv_stop_capture(id, 0);
|
ivtv_stop_capture(id, 0);
|
||||||
}
|
}
|
||||||
kfree(id);
|
kfree(id);
|
||||||
|
mutex_unlock(&itv->serialize_lock);
|
||||||
return 0;
|
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_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);
|
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))
|
test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags))
|
||||||
return -EBUSY;
|
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))
|
test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_MPG].s_flags))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
if (y == IVTV_DEC_STREAM_TYPE_YUV) {
|
if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
|
||||||
if (read_reg(0x82c) == 0) {
|
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");
|
IVTV_ERR("Tried to open YUV output device but need to send data to mpeg decoder before it can be used\n");
|
||||||
/* return -ENODEV; */
|
/* return -ENODEV; */
|
||||||
|
@ -883,7 +864,7 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
item->itv = itv;
|
item->itv = itv;
|
||||||
item->type = y;
|
item->type = s->type;
|
||||||
v4l2_prio_open(&itv->prio, &item->prio);
|
v4l2_prio_open(&itv->prio, &item->prio);
|
||||||
|
|
||||||
item->open_id = itv->open_id++;
|
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? */
|
/* 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);
|
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);
|
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);
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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)
|
void ivtv_mute(struct ivtv *itv)
|
||||||
|
|
|
@ -1446,11 +1446,15 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
|
||||||
return 0;
|
return 0;
|
||||||
if (nonblocking)
|
if (nonblocking)
|
||||||
return -EAGAIN;
|
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);
|
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)
|
if ((itv->i_flags & (IVTV_F_I_EV_DEC_STOPPED|IVTV_F_I_EV_VSYNC)) == 0)
|
||||||
schedule();
|
schedule();
|
||||||
finish_wait(&itv->event_waitq, &wait);
|
finish_wait(&itv->event_waitq, &wait);
|
||||||
|
mutex_lock(&itv->serialize_lock);
|
||||||
if (signal_pending(current)) {
|
if (signal_pending(current)) {
|
||||||
/* return if a signal was received */
|
/* return if a signal was received */
|
||||||
IVTV_DEBUG_INFO("User stopped wait for event\n");
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
|
static int ivtv_serialized_ioctl(struct ivtv *itv, struct inode *inode, struct file *filp,
|
||||||
unsigned long arg)
|
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 */
|
/* Filter dvb ioctls that cannot be handled by video_usercopy */
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case VIDEO_SELECT_SOURCE:
|
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);
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -437,9 +437,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
|
||||||
if (s->v4l2dev == NULL)
|
if (s->v4l2dev == NULL)
|
||||||
return -EINVAL;
|
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);
|
IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name);
|
||||||
|
|
||||||
switch (s->type) {
|
switch (s->type) {
|
||||||
|
@ -481,7 +478,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
|
||||||
0, sizeof(itv->vbi.sliced_mpeg_size));
|
0, sizeof(itv->vbi.sliced_mpeg_size));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
mutex_unlock(&itv->serialize_lock);
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
s->subtype = subtype;
|
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))
|
if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype))
|
||||||
{
|
{
|
||||||
IVTV_DEBUG_WARN( "Error starting capture!\n");
|
IVTV_DEBUG_WARN( "Error starting capture!\n");
|
||||||
mutex_unlock(&itv->serialize_lock);
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -580,7 +575,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
|
||||||
|
|
||||||
/* you're live! sit back and await interrupts :) */
|
/* you're live! sit back and await interrupts :) */
|
||||||
atomic_inc(&itv->capturing);
|
atomic_inc(&itv->capturing);
|
||||||
mutex_unlock(&itv->serialize_lock);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -751,9 +745,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
|
||||||
stopmode = 1;
|
stopmode = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ensure these actions are done only once */
|
|
||||||
mutex_lock(&itv->serialize_lock);
|
|
||||||
|
|
||||||
/* end_capture */
|
/* end_capture */
|
||||||
/* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */
|
/* 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);
|
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);
|
ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP);
|
||||||
|
|
||||||
if (atomic_read(&itv->capturing) > 0) {
|
if (atomic_read(&itv->capturing) > 0) {
|
||||||
mutex_unlock(&itv->serialize_lock);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -827,7 +817,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
|
||||||
}
|
}
|
||||||
|
|
||||||
wake_up(&s->waitq);
|
wake_up(&s->waitq);
|
||||||
mutex_unlock(&itv->serialize_lock);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue