// SPDX-License-Identifier: GPL-2.0-or-later
/*
file operation functions
Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com>
Copyright (C) 2004 Chris Kennedy <c@groovy.org>
Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl>
*/
#include "ivtv-driver.h"
#include "ivtv-fileops.h"
#include "ivtv-i2c.h"
#include "ivtv-queue.h"
#include "ivtv-udma.h"
#include "ivtv-irq.h"
#include "ivtv-vbi.h"
#include "ivtv-mailbox.h"
#include "ivtv-routing.h"
#include "ivtv-streams.h"
#include "ivtv-yuv.h"
#include "ivtv-ioctl.h"
#include "ivtv-cards.h"
#include "ivtv-firmware.h"
#include <media/v4l2-event.h>
#include <media/i2c/saa7115.h>
/* This function tries to claim the stream for a specific file descriptor.
If no one else is using this stream then the stream is claimed and
associated VBI streams are also automatically claimed.
Possible error returns: -EBUSY if someone else has claimed
the stream or 0 on success. */
int ivtv_claim_stream(struct ivtv_open_id *id, int type)
{
struct ivtv *itv = id->itv;
struct ivtv_stream *s = &itv->streams[type];
struct ivtv_stream *s_vbi;
int vbi_type;
if (test_and_set_bit(IVTV_F_S_CLAIMED, &s->s_flags)) {
/* someone already claimed this stream */
if (s->fh == &id->fh) {
/* yes, this file descriptor did. So that's OK. */
return 0;
}
if (s->fh == NULL && (type == IVTV_DEC_STREAM_TYPE_VBI ||
type == IVTV_ENC_STREAM_TYPE_VBI)) {
/* VBI is handled already internally, now also assign
the file descriptor to this stream for external
reading of the stream. */
s->fh = &id->fh;
IVTV_DEBUG_INFO("Start Read VBI\n");
return 0;
}
/* someone else is using this stream already */
IVTV_DEBUG_INFO("Stream %d is busy\n", type);
return -EBUSY;
}
s->fh = &id->fh;
if (type == IVTV_DEC_STREAM_TYPE_VBI) {
/* Enable reinsertion interrupt */
ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT);
}
/* IVTV_DEC_STREAM_TYPE_MPG needs to claim IVTV_DEC_STREAM_TYPE_VBI,
IVTV_ENC_STREAM_TYPE_MPG needs to claim IVTV_ENC_STREAM_TYPE_VBI
(provided VBI insertion is on and sliced VBI is selected), for all
other streams we're done */
if (type == IVTV_DEC_STREAM_TYPE_MPG) {
vbi_type = IVTV_DEC_STREAM_TYPE_VBI;
} else if (type == IVTV_ENC_STREAM_TYPE_MPG &&
itv->vbi.insert_mpeg && !ivtv_raw_vbi(itv)) {
vbi_type = IVTV_ENC_STREAM_TYPE_VBI;
} else {
return 0;
}
s_vbi = &itv->streams[vbi_type];
if (!test_and_set_bit(IVTV_F_S_CLAIMED, &s_vbi->s_flags)) {
/* Enable reinsertion interrupt */
if (vbi_type == IVTV_DEC_STREAM_TYPE_VBI)
ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT);
}
/* mark that it is used internally */
set_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags);
return 0;
}
EXPORT_SYMBOL(ivtv_claim_stream);
/* This function releases a previously claimed stream. It will take into
account associated VBI streams. */
void ivtv_release_stream(struct ivtv_stream *s)
{
struct ivtv *itv = s->itv;
struct ivtv_stream *s_vbi;
s->fh = NULL;
if ((s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type == IVTV_ENC_STREAM_TYPE_VBI) &&
test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) {
/* this stream is still in use internally */
return;
}
if (!test_and_clear_bit(IVTV_F_S_CLAIMED, &s->s_flags)) {
IVTV_DEBUG_WARN("Release stream %s not in use!\n", s->name);
return;
}
ivtv_flush_queues(s);
/* disable reinsertion interrupt */
if (s->type == IVTV_DEC_STREAM_TYPE_VBI)
ivtv_set_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT);
/* IVTV_DEC_STREAM_TYPE_MPG needs to release IVTV_DEC_STREAM_TYPE_VBI,
IVTV_ENC_STREAM_TYPE_MPG needs to release IVTV_ENC_STREAM_TYPE_VBI,
for all other streams we're done */
if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
s_vbi = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI];
else if (s->type == IVTV_ENC_STREAM_TYPE_MPG)
s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
else
return;
/* clear internal use flag */
if (!test_and_clear_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags)) {
/* was already cleared */
return;
}
if (s_vbi->fh) {
/* VBI stream still claimed by a file descriptor */
return;
}
/* disable reinsertion interrupt */
if<