Path: blob/master/drivers/media/video/cx18/cx18-fileops.c
17686 views
/*1* cx18 file operation functions2*3* Derived from ivtv-fileops.c4*5* Copyright (C) 2007 Hans Verkuil <[email protected]>6* Copyright (C) 2008 Andy Walls <[email protected]>7*8* This program is free software; you can redistribute it and/or modify9* it under the terms of the GNU General Public License as published by10* the Free Software Foundation; either version 2 of the License, or11* (at your option) any later version.12*13* This program is distributed in the hope that it will be useful,14* but WITHOUT ANY WARRANTY; without even the implied warranty of15* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the16* GNU General Public License for more details.17*18* You should have received a copy of the GNU General Public License19* along with this program; if not, write to the Free Software20* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA21* 02111-1307 USA22*/2324#include "cx18-driver.h"25#include "cx18-fileops.h"26#include "cx18-i2c.h"27#include "cx18-queue.h"28#include "cx18-vbi.h"29#include "cx18-audio.h"30#include "cx18-mailbox.h"31#include "cx18-scb.h"32#include "cx18-streams.h"33#include "cx18-controls.h"34#include "cx18-ioctl.h"35#include "cx18-cards.h"3637/* This function tries to claim the stream for a specific file descriptor.38If no one else is using this stream then the stream is claimed and39associated VBI and IDX streams are also automatically claimed.40Possible error returns: -EBUSY if someone else has claimed41the stream or 0 on success. */42int cx18_claim_stream(struct cx18_open_id *id, int type)43{44struct cx18 *cx = id->cx;45struct cx18_stream *s = &cx->streams[type];46struct cx18_stream *s_assoc;4748/* Nothing should ever try to directly claim the IDX stream */49if (type == CX18_ENC_STREAM_TYPE_IDX) {50CX18_WARN("MPEG Index stream cannot be claimed "51"directly, but something tried.\n");52return -EINVAL;53}5455if (test_and_set_bit(CX18_F_S_CLAIMED, &s->s_flags)) {56/* someone already claimed this stream */57if (s->id == id->open_id) {58/* yes, this file descriptor did. So that's OK. */59return 0;60}61if (s->id == -1 && type == CX18_ENC_STREAM_TYPE_VBI) {62/* VBI is handled already internally, now also assign63the file descriptor to this stream for external64reading of the stream. */65s->id = id->open_id;66CX18_DEBUG_INFO("Start Read VBI\n");67return 0;68}69/* someone else is using this stream already */70CX18_DEBUG_INFO("Stream %d is busy\n", type);71return -EBUSY;72}73s->id = id->open_id;7475/*76* CX18_ENC_STREAM_TYPE_MPG needs to claim:77* CX18_ENC_STREAM_TYPE_VBI, if VBI insertion is on for sliced VBI, or78* CX18_ENC_STREAM_TYPE_IDX, if VBI insertion is off for sliced VBI79* (We don't yet fix up MPEG Index entries for our inserted packets).80*81* For all other streams we're done.82*/83if (type != CX18_ENC_STREAM_TYPE_MPG)84return 0;8586s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];87if (cx->vbi.insert_mpeg && !cx18_raw_vbi(cx))88s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];89else if (!cx18_stream_enabled(s_assoc))90return 0;9192set_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags);9394/* mark that it is used internally */95set_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags);96return 0;97}98EXPORT_SYMBOL(cx18_claim_stream);99100/* This function releases a previously claimed stream. It will take into101account associated VBI streams. */102void cx18_release_stream(struct cx18_stream *s)103{104struct cx18 *cx = s->cx;105struct cx18_stream *s_assoc;106107s->id = -1;108if (s->type == CX18_ENC_STREAM_TYPE_IDX) {109/*110* The IDX stream is only used internally, and can111* only be indirectly unclaimed by unclaiming the MPG stream.112*/113return;114}115116if (s->type == CX18_ENC_STREAM_TYPE_VBI &&117test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) {118/* this stream is still in use internally */119return;120}121if (!test_and_clear_bit(CX18_F_S_CLAIMED, &s->s_flags)) {122CX18_DEBUG_WARN("Release stream %s not in use!\n", s->name);123return;124}125126cx18_flush_queues(s);127128/*129* CX18_ENC_STREAM_TYPE_MPG needs to release the130* CX18_ENC_STREAM_TYPE_VBI and/or CX18_ENC_STREAM_TYPE_IDX streams.131*132* For all other streams we're done.133*/134if (s->type != CX18_ENC_STREAM_TYPE_MPG)135return;136137/* Unclaim the associated MPEG Index stream */138s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];139if (test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags)) {140clear_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags);141cx18_flush_queues(s_assoc);142}143144/* Unclaim the associated VBI stream */145s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];146if (test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags)) {147if (s_assoc->id == -1) {148/*149* The VBI stream is not still claimed by a file150* descriptor, so completely unclaim it.151*/152clear_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags);153cx18_flush_queues(s_assoc);154}155}156}157EXPORT_SYMBOL(cx18_release_stream);158159static void cx18_dualwatch(struct cx18 *cx)160{161struct v4l2_tuner vt;162u32 new_stereo_mode;163const u32 dual = 0x0200;164165new_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode);166memset(&vt, 0, sizeof(vt));167cx18_call_all(cx, tuner, g_tuner, &vt);168if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 &&169(vt.rxsubchans & V4L2_TUNER_SUB_LANG2))170new_stereo_mode = dual;171172if (new_stereo_mode == cx->dualwatch_stereo_mode)173return;174175CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x.\n",176cx->dualwatch_stereo_mode, new_stereo_mode);177if (v4l2_ctrl_s_ctrl(cx->cxhdl.audio_mode, new_stereo_mode))178CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n");179}180181182static struct cx18_mdl *cx18_get_mdl(struct cx18_stream *s, int non_block,183int *err)184{185struct cx18 *cx = s->cx;186struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];187struct cx18_mdl *mdl;188DEFINE_WAIT(wait);189190*err = 0;191while (1) {192if (s->type == CX18_ENC_STREAM_TYPE_MPG) {193/* Process pending program updates and VBI data */194if (time_after(jiffies, cx->dualwatch_jiffies + msecs_to_jiffies(1000))) {195cx->dualwatch_jiffies = jiffies;196cx18_dualwatch(cx);197}198if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) &&199!test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {200while ((mdl = cx18_dequeue(s_vbi,201&s_vbi->q_full))) {202/* byteswap and process VBI data */203cx18_process_vbi_data(cx, mdl,204s_vbi->type);205cx18_stream_put_mdl_fw(s_vbi, mdl);206}207}208mdl = &cx->vbi.sliced_mpeg_mdl;209if (mdl->readpos != mdl->bytesused)210return mdl;211}212213/* do we have new data? */214mdl = cx18_dequeue(s, &s->q_full);215if (mdl) {216if (!test_and_clear_bit(CX18_F_M_NEED_SWAP,217&mdl->m_flags))218return mdl;219if (s->type == CX18_ENC_STREAM_TYPE_MPG)220/* byteswap MPG data */221cx18_mdl_swap(mdl);222else {223/* byteswap and process VBI data */224cx18_process_vbi_data(cx, mdl, s->type);225}226return mdl;227}228229/* return if end of stream */230if (!test_bit(CX18_F_S_STREAMING, &s->s_flags)) {231CX18_DEBUG_INFO("EOS %s\n", s->name);232return NULL;233}234235/* return if file was opened with O_NONBLOCK */236if (non_block) {237*err = -EAGAIN;238return NULL;239}240241/* wait for more data to arrive */242prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);243/* New buffers might have become available before we were added244to the waitqueue */245if (!atomic_read(&s->q_full.depth))246schedule();247finish_wait(&s->waitq, &wait);248if (signal_pending(current)) {249/* return if a signal was received */250CX18_DEBUG_INFO("User stopped %s\n", s->name);251*err = -EINTR;252return NULL;253}254}255}256257static void cx18_setup_sliced_vbi_mdl(struct cx18 *cx)258{259struct cx18_mdl *mdl = &cx->vbi.sliced_mpeg_mdl;260struct cx18_buffer *buf = &cx->vbi.sliced_mpeg_buf;261int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES;262263buf->buf = cx->vbi.sliced_mpeg_data[idx];264buf->bytesused = cx->vbi.sliced_mpeg_size[idx];265buf->readpos = 0;266267mdl->curr_buf = NULL;268mdl->bytesused = cx->vbi.sliced_mpeg_size[idx];269mdl->readpos = 0;270}271272static size_t cx18_copy_buf_to_user(struct cx18_stream *s,273struct cx18_buffer *buf, char __user *ubuf, size_t ucount, bool *stop)274{275struct cx18 *cx = s->cx;276size_t len = buf->bytesused - buf->readpos;277278*stop = false;279if (len > ucount)280len = ucount;281if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG &&282!cx18_raw_vbi(cx) && buf != &cx->vbi.sliced_mpeg_buf) {283/*284* Try to find a good splice point in the PS, just before285* an MPEG-2 Program Pack start code, and provide only286* up to that point to the user, so it's easy to insert VBI data287* the next time around.288*289* This will not work for an MPEG-2 TS and has only been290* verified by analysis to work for an MPEG-2 PS. Helen Buus291* pointed out this works for the CX23416 MPEG-2 DVD compatible292* stream, and research indicates both the MPEG 2 SVCD and DVD293* stream types use an MPEG-2 PS container.294*/295/*296* An MPEG-2 Program Stream (PS) is a series of297* MPEG-2 Program Packs terminated by an298* MPEG Program End Code after the last Program Pack.299* A Program Pack may hold a PS System Header packet and any300* number of Program Elementary Stream (PES) Packets301*/302const char *start = buf->buf + buf->readpos;303const char *p = start + 1;304const u8 *q;305u8 ch = cx->search_pack_header ? 0xba : 0xe0;306int stuffing, i;307308while (start + len > p) {309/* Scan for a 0 to find a potential MPEG-2 start code */310q = memchr(p, 0, start + len - p);311if (q == NULL)312break;313p = q + 1;314/*315* Keep looking if not a316* MPEG-2 Pack header start code: 0x00 0x00 0x01 0xba317* or MPEG-2 video PES start code: 0x00 0x00 0x01 0xe0318*/319if ((char *)q + 15 >= buf->buf + buf->bytesused ||320q[1] != 0 || q[2] != 1 || q[3] != ch)321continue;322323/* If expecting the primary video PES */324if (!cx->search_pack_header) {325/* Continue if it couldn't be a PES packet */326if ((q[6] & 0xc0) != 0x80)327continue;328/* Check if a PTS or PTS & DTS follow */329if (((q[7] & 0xc0) == 0x80 && /* PTS only */330(q[9] & 0xf0) == 0x20) || /* PTS only */331((q[7] & 0xc0) == 0xc0 && /* PTS & DTS */332(q[9] & 0xf0) == 0x30)) { /* DTS follows */333/* Assume we found the video PES hdr */334ch = 0xba; /* next want a Program Pack*/335cx->search_pack_header = 1;336p = q + 9; /* Skip this video PES hdr */337}338continue;339}340341/* We may have found a Program Pack start code */342343/* Get the count of stuffing bytes & verify them */344stuffing = q[13] & 7;345/* all stuffing bytes must be 0xff */346for (i = 0; i < stuffing; i++)347if (q[14 + i] != 0xff)348break;349if (i == stuffing && /* right number of stuffing bytes*/350(q[4] & 0xc4) == 0x44 && /* marker check */351(q[12] & 3) == 3 && /* marker check */352q[14 + stuffing] == 0 && /* PES Pack or Sys Hdr */353q[15 + stuffing] == 0 &&354q[16 + stuffing] == 1) {355/* We declare we actually found a Program Pack*/356cx->search_pack_header = 0; /* expect vid PES */357len = (char *)q - start;358cx18_setup_sliced_vbi_mdl(cx);359*stop = true;360break;361}362}363}364if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) {365CX18_DEBUG_WARN("copy %zd bytes to user failed for %s\n",366len, s->name);367return -EFAULT;368}369buf->readpos += len;370if (s->type == CX18_ENC_STREAM_TYPE_MPG &&371buf != &cx->vbi.sliced_mpeg_buf)372cx->mpg_data_received += len;373return len;374}375376static size_t cx18_copy_mdl_to_user(struct cx18_stream *s,377struct cx18_mdl *mdl, char __user *ubuf, size_t ucount)378{379size_t tot_written = 0;380int rc;381bool stop = false;382383if (mdl->curr_buf == NULL)384mdl->curr_buf = list_first_entry(&mdl->buf_list,385struct cx18_buffer, list);386387if (list_entry_is_past_end(mdl->curr_buf, &mdl->buf_list, list)) {388/*389* For some reason we've exhausted the buffers, but the MDL390* object still said some data was unread.391* Fix that and bail out.392*/393mdl->readpos = mdl->bytesused;394return 0;395}396397list_for_each_entry_from(mdl->curr_buf, &mdl->buf_list, list) {398399if (mdl->curr_buf->readpos >= mdl->curr_buf->bytesused)400continue;401402rc = cx18_copy_buf_to_user(s, mdl->curr_buf, ubuf + tot_written,403ucount - tot_written, &stop);404if (rc < 0)405return rc;406mdl->readpos += rc;407tot_written += rc;408409if (stop || /* Forced stopping point for VBI insertion */410tot_written >= ucount || /* Reader request statisfied */411mdl->curr_buf->readpos < mdl->curr_buf->bytesused ||412mdl->readpos >= mdl->bytesused) /* MDL buffers drained */413break;414}415return tot_written;416}417418static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf,419size_t tot_count, int non_block)420{421struct cx18 *cx = s->cx;422size_t tot_written = 0;423int single_frame = 0;424425if (atomic_read(&cx->ana_capturing) == 0 && s->id == -1) {426/* shouldn't happen */427CX18_DEBUG_WARN("Stream %s not initialized before read\n",428s->name);429return -EIO;430}431432/* Each VBI buffer is one frame, the v4l2 API says that for VBI the433frames should arrive one-by-one, so make sure we never output more434than one VBI frame at a time */435if (s->type == CX18_ENC_STREAM_TYPE_VBI && !cx18_raw_vbi(cx))436single_frame = 1;437438for (;;) {439struct cx18_mdl *mdl;440int rc;441442mdl = cx18_get_mdl(s, non_block, &rc);443/* if there is no data available... */444if (mdl == NULL) {445/* if we got data, then return that regardless */446if (tot_written)447break;448/* EOS condition */449if (rc == 0) {450clear_bit(CX18_F_S_STREAMOFF, &s->s_flags);451clear_bit(CX18_F_S_APPL_IO, &s->s_flags);452cx18_release_stream(s);453}454/* set errno */455return rc;456}457458rc = cx18_copy_mdl_to_user(s, mdl, ubuf + tot_written,459tot_count - tot_written);460461if (mdl != &cx->vbi.sliced_mpeg_mdl) {462if (mdl->readpos == mdl->bytesused)463cx18_stream_put_mdl_fw(s, mdl);464else465cx18_push(s, mdl, &s->q_full);466} else if (mdl->readpos == mdl->bytesused) {467int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES;468469cx->vbi.sliced_mpeg_size[idx] = 0;470cx->vbi.inserted_frame++;471cx->vbi_data_inserted += mdl->bytesused;472}473if (rc < 0)474return rc;475tot_written += rc;476477if (tot_written == tot_count || single_frame)478break;479}480return tot_written;481}482483static ssize_t cx18_read_pos(struct cx18_stream *s, char __user *ubuf,484size_t count, loff_t *pos, int non_block)485{486ssize_t rc = count ? cx18_read(s, ubuf, count, non_block) : 0;487struct cx18 *cx = s->cx;488489CX18_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc);490if (rc > 0)491pos += rc;492return rc;493}494495int cx18_start_capture(struct cx18_open_id *id)496{497struct cx18 *cx = id->cx;498struct cx18_stream *s = &cx->streams[id->type];499struct cx18_stream *s_vbi;500struct cx18_stream *s_idx;501502if (s->type == CX18_ENC_STREAM_TYPE_RAD) {503/* you cannot read from these stream types. */504return -EPERM;505}506507/* Try to claim this stream. */508if (cx18_claim_stream(id, s->type))509return -EBUSY;510511/* If capture is already in progress, then we also have to512do nothing extra. */513if (test_bit(CX18_F_S_STREAMOFF, &s->s_flags) ||514test_and_set_bit(CX18_F_S_STREAMING, &s->s_flags)) {515set_bit(CX18_F_S_APPL_IO, &s->s_flags);516return 0;517}518519/* Start associated VBI or IDX stream capture if required */520s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];521s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];522if (s->type == CX18_ENC_STREAM_TYPE_MPG) {523/*524* The VBI and IDX streams should have been claimed525* automatically, if for internal use, when the MPG stream was526* claimed. We only need to start these streams capturing.527*/528if (test_bit(CX18_F_S_INTERNAL_USE, &s_idx->s_flags) &&529!test_and_set_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) {530if (cx18_start_v4l2_encode_stream(s_idx)) {531CX18_DEBUG_WARN("IDX capture start failed\n");532clear_bit(CX18_F_S_STREAMING, &s_idx->s_flags);533goto start_failed;534}535CX18_DEBUG_INFO("IDX capture started\n");536}537if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) &&538!test_and_set_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) {539if (cx18_start_v4l2_encode_stream(s_vbi)) {540CX18_DEBUG_WARN("VBI capture start failed\n");541clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags);542goto start_failed;543}544CX18_DEBUG_INFO("VBI insertion started\n");545}546}547548/* Tell the card to start capturing */549if (!cx18_start_v4l2_encode_stream(s)) {550/* We're done */551set_bit(CX18_F_S_APPL_IO, &s->s_flags);552/* Resume a possibly paused encoder */553if (test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))554cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, s->handle);555return 0;556}557558start_failed:559CX18_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name);560561/*562* The associated VBI and IDX streams for internal use are released563* automatically when the MPG stream is released. We only need to stop564* the associated stream.565*/566if (s->type == CX18_ENC_STREAM_TYPE_MPG) {567/* Stop the IDX stream which is always for internal use */568if (test_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) {569cx18_stop_v4l2_encode_stream(s_idx, 0);570clear_bit(CX18_F_S_STREAMING, &s_idx->s_flags);571}572/* Stop the VBI stream, if only running for internal use */573if (test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) &&574!test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {575cx18_stop_v4l2_encode_stream(s_vbi, 0);576clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags);577}578}579clear_bit(CX18_F_S_STREAMING, &s->s_flags);580cx18_release_stream(s); /* Also releases associated streams */581return -EIO;582}583584ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count,585loff_t *pos)586{587struct cx18_open_id *id = file2id(filp);588struct cx18 *cx = id->cx;589struct cx18_stream *s = &cx->streams[id->type];590int rc;591592CX18_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name);593594mutex_lock(&cx->serialize_lock);595rc = cx18_start_capture(id);596mutex_unlock(&cx->serialize_lock);597if (rc)598return rc;599600if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&601(id->type == CX18_ENC_STREAM_TYPE_YUV)) {602return videobuf_read_stream(&s->vbuf_q, buf, count, pos, 0,603filp->f_flags & O_NONBLOCK);604}605606return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);607}608609unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)610{611struct cx18_open_id *id = file2id(filp);612struct cx18 *cx = id->cx;613struct cx18_stream *s = &cx->streams[id->type];614int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags);615616/* Start a capture if there is none */617if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) {618int rc;619620mutex_lock(&cx->serialize_lock);621rc = cx18_start_capture(id);622mutex_unlock(&cx->serialize_lock);623if (rc) {624CX18_DEBUG_INFO("Could not start capture for %s (%d)\n",625s->name, rc);626return POLLERR;627}628CX18_DEBUG_FILE("Encoder poll started capture\n");629}630631if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&632(id->type == CX18_ENC_STREAM_TYPE_YUV)) {633int videobuf_poll = videobuf_poll_stream(filp, &s->vbuf_q, wait);634if (eof && videobuf_poll == POLLERR)635return POLLHUP;636else637return videobuf_poll;638}639640/* add stream's waitq to the poll list */641CX18_DEBUG_HI_FILE("Encoder poll\n");642poll_wait(filp, &s->waitq, wait);643644if (atomic_read(&s->q_full.depth))645return POLLIN | POLLRDNORM;646if (eof)647return POLLHUP;648return 0;649}650651int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma)652{653struct cx18_open_id *id = file->private_data;654struct cx18 *cx = id->cx;655struct cx18_stream *s = &cx->streams[id->type];656int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags);657658if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&659(id->type == CX18_ENC_STREAM_TYPE_YUV)) {660661/* Start a capture if there is none */662if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) {663int rc;664665mutex_lock(&cx->serialize_lock);666rc = cx18_start_capture(id);667mutex_unlock(&cx->serialize_lock);668if (rc) {669CX18_DEBUG_INFO(670"Could not start capture for %s (%d)\n",671s->name, rc);672return -EINVAL;673}674CX18_DEBUG_FILE("Encoder mmap started capture\n");675}676677return videobuf_mmap_mapper(&s->vbuf_q, vma);678}679680return -EINVAL;681}682683void cx18_vb_timeout(unsigned long data)684{685struct cx18_stream *s = (struct cx18_stream *)data;686struct cx18_videobuf_buffer *buf;687unsigned long flags;688689/* Return all of the buffers in error state, so the vbi/vid inode690* can return from blocking.691*/692spin_lock_irqsave(&s->vb_lock, flags);693while (!list_empty(&s->vb_capture)) {694buf = list_entry(s->vb_capture.next,695struct cx18_videobuf_buffer, vb.queue);696list_del(&buf->vb.queue);697buf->vb.state = VIDEOBUF_ERROR;698wake_up(&buf->vb.done);699}700spin_unlock_irqrestore(&s->vb_lock, flags);701}702703void cx18_stop_capture(struct cx18_open_id *id, int gop_end)704{705struct cx18 *cx = id->cx;706struct cx18_stream *s = &cx->streams[id->type];707struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];708struct cx18_stream *s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX];709710CX18_DEBUG_IOCTL("close() of %s\n", s->name);711712/* 'Unclaim' this stream */713714/* Stop capturing */715if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) {716CX18_DEBUG_INFO("close stopping capture\n");717if (id->type == CX18_ENC_STREAM_TYPE_MPG) {718/* Stop internal use associated VBI and IDX streams */719if (test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) &&720!test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {721CX18_DEBUG_INFO("close stopping embedded VBI "722"capture\n");723cx18_stop_v4l2_encode_stream(s_vbi, 0);724}725if (test_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) {726CX18_DEBUG_INFO("close stopping IDX capture\n");727cx18_stop_v4l2_encode_stream(s_idx, 0);728}729}730if (id->type == CX18_ENC_STREAM_TYPE_VBI &&731test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags))732/* Also used internally, don't stop capturing */733s->id = -1;734else735cx18_stop_v4l2_encode_stream(s, gop_end);736}737if (!gop_end) {738clear_bit(CX18_F_S_APPL_IO, &s->s_flags);739clear_bit(CX18_F_S_STREAMOFF, &s->s_flags);740cx18_release_stream(s);741}742}743744int cx18_v4l2_close(struct file *filp)745{746struct v4l2_fh *fh = filp->private_data;747struct cx18_open_id *id = fh2id(fh);748struct cx18 *cx = id->cx;749struct cx18_stream *s = &cx->streams[id->type];750751CX18_DEBUG_IOCTL("close() of %s\n", s->name);752753v4l2_fh_del(fh);754v4l2_fh_exit(fh);755756/* Easy case first: this stream was never claimed by us */757if (s->id != id->open_id) {758kfree(id);759return 0;760}761762/* 'Unclaim' this stream */763764/* Stop radio */765mutex_lock(&cx->serialize_lock);766if (id->type == CX18_ENC_STREAM_TYPE_RAD) {767/* Closing radio device, return to TV mode */768cx18_mute(cx);769/* Mark that the radio is no longer in use */770clear_bit(CX18_F_I_RADIO_USER, &cx->i_flags);771/* Switch tuner to TV */772cx18_call_all(cx, core, s_std, cx->std);773/* Select correct audio input (i.e. TV tuner or Line in) */774cx18_audio_set_io(cx);775if (atomic_read(&cx->ana_capturing) > 0) {776/* Undo video mute */777cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,778(v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute) |779(v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8)));780}781/* Done! Unmute and continue. */782cx18_unmute(cx);783cx18_release_stream(s);784} else {785cx18_stop_capture(id, 0);786if (id->type == CX18_ENC_STREAM_TYPE_YUV)787videobuf_mmap_free(&id->vbuf_q);788}789kfree(id);790mutex_unlock(&cx->serialize_lock);791return 0;792}793794static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)795{796struct cx18 *cx = s->cx;797struct cx18_open_id *item;798799CX18_DEBUG_FILE("open %s\n", s->name);800801/* Allocate memory */802item = kzalloc(sizeof(struct cx18_open_id), GFP_KERNEL);803if (NULL == item) {804CX18_DEBUG_WARN("nomem on v4l2 open\n");805return -ENOMEM;806}807v4l2_fh_init(&item->fh, s->video_dev);808809item->cx = cx;810item->type = s->type;811812item->open_id = cx->open_id++;813filp->private_data = &item->fh;814815if (item->type == CX18_ENC_STREAM_TYPE_RAD) {816/* Try to claim this stream */817if (cx18_claim_stream(item, item->type)) {818/* No, it's already in use */819v4l2_fh_exit(&item->fh);820kfree(item);821return -EBUSY;822}823824if (!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {825if (atomic_read(&cx->ana_capturing) > 0) {826/* switching to radio while capture is827in progress is not polite */828cx18_release_stream(s);829v4l2_fh_exit(&item->fh);830kfree(item);831return -EBUSY;832}833}834835/* Mark that the radio is being used. */836set_bit(CX18_F_I_RADIO_USER, &cx->i_flags);837/* We have the radio */838cx18_mute(cx);839/* Switch tuner to radio */840cx18_call_all(cx, tuner, s_radio);841/* Select the correct audio input (i.e. radio tuner) */842cx18_audio_set_io(cx);843/* Done! Unmute and continue. */844cx18_unmute(cx);845}846v4l2_fh_add(&item->fh);847return 0;848}849850int cx18_v4l2_open(struct file *filp)851{852int res;853struct video_device *video_dev = video_devdata(filp);854struct cx18_stream *s = video_get_drvdata(video_dev);855struct cx18 *cx = s->cx;856857mutex_lock(&cx->serialize_lock);858if (cx18_init_on_first_open(cx)) {859CX18_ERR("Failed to initialize on %s\n",860video_device_node_name(video_dev));861mutex_unlock(&cx->serialize_lock);862return -ENXIO;863}864res = cx18_serialized_open(s, filp);865mutex_unlock(&cx->serialize_lock);866return res;867}868869void cx18_mute(struct cx18 *cx)870{871u32 h;872if (atomic_read(&cx->ana_capturing)) {873h = cx18_find_handle(cx);874if (h != CX18_INVALID_TASK_HANDLE)875cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, h, 1);876else877CX18_ERR("Can't find valid task handle for mute\n");878}879CX18_DEBUG_INFO("Mute\n");880}881882void cx18_unmute(struct cx18 *cx)883{884u32 h;885if (atomic_read(&cx->ana_capturing)) {886h = cx18_find_handle(cx);887if (h != CX18_INVALID_TASK_HANDLE) {888cx18_msleep_timeout(100, 0);889cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, h, 12);890cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, h, 0);891} else892CX18_ERR("Can't find valid task handle for unmute\n");893}894CX18_DEBUG_INFO("Unmute\n");895}896897898