11c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil/* 21c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil * cx18 file operation functions 31c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil * 41c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil * Derived from ivtv-fileops.c 51c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil * 61c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> 76afdeaf865b729287e02aafc61d8d013b89996efAndy Walls * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> 81c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil * 91c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil * This program is free software; you can redistribute it and/or modify 101c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil * it under the terms of the GNU General Public License as published by 111c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil * the Free Software Foundation; either version 2 of the License, or 121c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil * (at your option) any later version. 131c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil * 141c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil * This program is distributed in the hope that it will be useful, 151c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil * but WITHOUT ANY WARRANTY; without even the implied warranty of 161c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 171c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil * GNU General Public License for more details. 181c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil * 191c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil * You should have received a copy of the GNU General Public License 201c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil * along with this program; if not, write to the Free Software 211c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 221c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil * 02111-1307 USA 231c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil */ 241c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 251c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil#include "cx18-driver.h" 261c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil#include "cx18-fileops.h" 271c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil#include "cx18-i2c.h" 281c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil#include "cx18-queue.h" 291c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil#include "cx18-vbi.h" 301c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil#include "cx18-audio.h" 311c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil#include "cx18-mailbox.h" 321c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil#include "cx18-scb.h" 331c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil#include "cx18-streams.h" 341c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil#include "cx18-controls.h" 351c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil#include "cx18-ioctl.h" 361c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil#include "cx18-cards.h" 371c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 381c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil/* This function tries to claim the stream for a specific file descriptor. 391c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil If no one else is using this stream then the stream is claimed and 4079f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls associated VBI and IDX streams are also automatically claimed. 411c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil Possible error returns: -EBUSY if someone else has claimed 421c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil the stream or 0 on success. */ 438ef22f794ea5577505bc71e468183585f429afdeDevin Heitmuellerint cx18_claim_stream(struct cx18_open_id *id, int type) 441c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil{ 451c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil struct cx18 *cx = id->cx; 461c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil struct cx18_stream *s = &cx->streams[type]; 4779f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls struct cx18_stream *s_assoc; 4879f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls 4979f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls /* Nothing should ever try to directly claim the IDX stream */ 5079f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls if (type == CX18_ENC_STREAM_TYPE_IDX) { 5179f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls CX18_WARN("MPEG Index stream cannot be claimed " 5279f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls "directly, but something tried.\n"); 5379f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls return -EINVAL; 5479f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls } 551c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 561c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (test_and_set_bit(CX18_F_S_CLAIMED, &s->s_flags)) { 571c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* someone already claimed this stream */ 581c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (s->id == id->open_id) { 591c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* yes, this file descriptor did. So that's OK. */ 601c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return 0; 611c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 621c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (s->id == -1 && type == CX18_ENC_STREAM_TYPE_VBI) { 631c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* VBI is handled already internally, now also assign 641c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil the file descriptor to this stream for external 651c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil reading of the stream. */ 661c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil s->id = id->open_id; 671c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil CX18_DEBUG_INFO("Start Read VBI\n"); 681c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return 0; 691c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 701c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* someone else is using this stream already */ 711c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil CX18_DEBUG_INFO("Stream %d is busy\n", type); 721c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return -EBUSY; 731c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 741c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil s->id = id->open_id; 751c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 7679f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls /* 7779f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls * CX18_ENC_STREAM_TYPE_MPG needs to claim: 7879f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls * CX18_ENC_STREAM_TYPE_VBI, if VBI insertion is on for sliced VBI, or 7979f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls * CX18_ENC_STREAM_TYPE_IDX, if VBI insertion is off for sliced VBI 8079f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls * (We don't yet fix up MPEG Index entries for our inserted packets). 8179f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls * 8279f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls * For all other streams we're done. 8379f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls */ 8479f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls if (type != CX18_ENC_STREAM_TYPE_MPG) 8579f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls return 0; 8679f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls 8779f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; 8879f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls if (cx->vbi.insert_mpeg && !cx18_raw_vbi(cx)) 8979f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; 9079f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls else if (!cx18_stream_enabled(s_assoc)) 911c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return 0; 921c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 9379f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls set_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags); 941c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 951c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* mark that it is used internally */ 9679f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls set_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags); 971c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return 0; 981c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil} 998ef22f794ea5577505bc71e468183585f429afdeDevin HeitmuellerEXPORT_SYMBOL(cx18_claim_stream); 1001c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 1011c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil/* This function releases a previously claimed stream. It will take into 1021c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil account associated VBI streams. */ 1038ef22f794ea5577505bc71e468183585f429afdeDevin Heitmuellervoid cx18_release_stream(struct cx18_stream *s) 1041c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil{ 1051c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil struct cx18 *cx = s->cx; 10679f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls struct cx18_stream *s_assoc; 1071c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 1081c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil s->id = -1; 10979f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls if (s->type == CX18_ENC_STREAM_TYPE_IDX) { 11079f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls /* 11179f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls * The IDX stream is only used internally, and can 11279f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls * only be indirectly unclaimed by unclaiming the MPG stream. 11379f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls */ 11479f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls return; 11579f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls } 11679f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls 1171c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (s->type == CX18_ENC_STREAM_TYPE_VBI && 1181c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) { 1191c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* this stream is still in use internally */ 1201c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return; 1211c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 1221c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (!test_and_clear_bit(CX18_F_S_CLAIMED, &s->s_flags)) { 1231c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil CX18_DEBUG_WARN("Release stream %s not in use!\n", s->name); 1241c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return; 1251c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 1261c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 1271c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil cx18_flush_queues(s); 1281c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 12979f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls /* 13079f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls * CX18_ENC_STREAM_TYPE_MPG needs to release the 13179f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls * CX18_ENC_STREAM_TYPE_VBI and/or CX18_ENC_STREAM_TYPE_IDX streams. 13279f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls * 13379f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls * For all other streams we're done. 13479f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls */ 13579f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls if (s->type != CX18_ENC_STREAM_TYPE_MPG) 1361c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return; 1371c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 13879f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls /* Unclaim the associated MPEG Index stream */ 13979f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; 14079f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls if (test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags)) { 14179f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls clear_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags); 14279f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls cx18_flush_queues(s_assoc); 1431c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 14479f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls 14579f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls /* Unclaim the associated VBI stream */ 14679f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; 14779f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls if (test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags)) { 14879f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls if (s_assoc->id == -1) { 14979f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls /* 15079f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls * The VBI stream is not still claimed by a file 15179f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls * descriptor, so completely unclaim it. 15279f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls */ 15379f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls clear_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags); 15479f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls cx18_flush_queues(s_assoc); 15579f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls } 1561c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 1571c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil} 1588ef22f794ea5577505bc71e468183585f429afdeDevin HeitmuellerEXPORT_SYMBOL(cx18_release_stream); 1591c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 1601c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuilstatic void cx18_dualwatch(struct cx18 *cx) 1611c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil{ 1621c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil struct v4l2_tuner vt; 1630d82fe801d7c6d8cb8987e66b570f6decde9e235Andy Walls u32 new_stereo_mode; 1640d82fe801d7c6d8cb8987e66b570f6decde9e235Andy Walls const u32 dual = 0x0200; 1651c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 166a75b9be1c2fb52dee765d35f29031dd788d522ebHans Verkuil new_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode); 1671c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil memset(&vt, 0, sizeof(vt)); 168ff2a20018094c593a35f4887bbdabf8926ddb6e6Andy Walls cx18_call_all(cx, tuner, g_tuner, &vt); 1691c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && 1701c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil (vt.rxsubchans & V4L2_TUNER_SUB_LANG2)) 1711c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil new_stereo_mode = dual; 1721c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 1731c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (new_stereo_mode == cx->dualwatch_stereo_mode) 1741c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return; 1751c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 176a75b9be1c2fb52dee765d35f29031dd788d522ebHans Verkuil CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x.\n", 177a75b9be1c2fb52dee765d35f29031dd788d522ebHans Verkuil cx->dualwatch_stereo_mode, new_stereo_mode); 178a75b9be1c2fb52dee765d35f29031dd788d522ebHans Verkuil if (v4l2_ctrl_s_ctrl(cx->cxhdl.audio_mode, new_stereo_mode)) 179a75b9be1c2fb52dee765d35f29031dd788d522ebHans Verkuil CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n"); 1801c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil} 1811c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 1821c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 18352fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Wallsstatic struct cx18_mdl *cx18_get_mdl(struct cx18_stream *s, int non_block, 18452fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls int *err) 1851c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil{ 1861c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil struct cx18 *cx = s->cx; 1871c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; 18852fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls struct cx18_mdl *mdl; 1891c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil DEFINE_WAIT(wait); 1901c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 1911c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil *err = 0; 1921c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil while (1) { 1931c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (s->type == CX18_ENC_STREAM_TYPE_MPG) { 1949bff2d61716bffe5e1d58de9eb940c62bb020fcfAndy Walls /* Process pending program updates and VBI data */ 1951c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (time_after(jiffies, cx->dualwatch_jiffies + msecs_to_jiffies(1000))) { 1961c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil cx->dualwatch_jiffies = jiffies; 1971c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil cx18_dualwatch(cx); 1981c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 1991c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) && 2001c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { 20152fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls while ((mdl = cx18_dequeue(s_vbi, 20252fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls &s_vbi->q_full))) { 2031c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* byteswap and process VBI data */ 20452fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls cx18_process_vbi_data(cx, mdl, 205af009cf635141858642864a26602e379e97bf7d6Andy Walls s_vbi->type); 20652fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls cx18_stream_put_mdl_fw(s_vbi, mdl); 2071c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 2081c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 20952fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls mdl = &cx->vbi.sliced_mpeg_mdl; 21052fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls if (mdl->readpos != mdl->bytesused) 21152fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls return mdl; 2121c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 2131c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 2141c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* do we have new data? */ 21552fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls mdl = cx18_dequeue(s, &s->q_full); 21652fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls if (mdl) { 21752fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls if (!test_and_clear_bit(CX18_F_M_NEED_SWAP, 21852fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls &mdl->m_flags)) 21952fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls return mdl; 2201c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (s->type == CX18_ENC_STREAM_TYPE_MPG) 2211c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* byteswap MPG data */ 22252fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls cx18_mdl_swap(mdl); 2231c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil else { 2241c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* byteswap and process VBI data */ 22552fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls cx18_process_vbi_data(cx, mdl, s->type); 2261c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 22752fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls return mdl; 2281c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 2291c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 2301c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* return if end of stream */ 2311c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (!test_bit(CX18_F_S_STREAMING, &s->s_flags)) { 2321c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil CX18_DEBUG_INFO("EOS %s\n", s->name); 2331c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return NULL; 2341c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 2351c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 2361c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* return if file was opened with O_NONBLOCK */ 2371c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (non_block) { 2381c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil *err = -EAGAIN; 2391c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return NULL; 2401c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 2411c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 2421c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* wait for more data to arrive */ 2431c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); 2441c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* New buffers might have become available before we were added 2451c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil to the waitqueue */ 246c37b11bf17b66b960b217c35283aa9c55eacb292Andy Walls if (!atomic_read(&s->q_full.depth)) 2471c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil schedule(); 2481c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil finish_wait(&s->waitq, &wait); 2491c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (signal_pending(current)) { 2501c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* return if a signal was received */ 2511c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil CX18_DEBUG_INFO("User stopped %s\n", s->name); 2521c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil *err = -EINTR; 2531c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return NULL; 2541c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 2551c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 2561c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil} 2571c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 25852fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Wallsstatic void cx18_setup_sliced_vbi_mdl(struct cx18 *cx) 2591c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil{ 26052fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls struct cx18_mdl *mdl = &cx->vbi.sliced_mpeg_mdl; 26152fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls struct cx18_buffer *buf = &cx->vbi.sliced_mpeg_buf; 2621c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; 2631c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 26452fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls buf->buf = cx->vbi.sliced_mpeg_data[idx]; 26552fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls buf->bytesused = cx->vbi.sliced_mpeg_size[idx]; 26652fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls buf->readpos = 0; 26752fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls 26852fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls mdl->curr_buf = NULL; 26952fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls mdl->bytesused = cx->vbi.sliced_mpeg_size[idx]; 27052fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls mdl->readpos = 0; 2711c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil} 2721c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 2731c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuilstatic size_t cx18_copy_buf_to_user(struct cx18_stream *s, 27452fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls struct cx18_buffer *buf, char __user *ubuf, size_t ucount, bool *stop) 2751c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil{ 2761c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil struct cx18 *cx = s->cx; 2771c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil size_t len = buf->bytesused - buf->readpos; 2781c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 27952fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls *stop = false; 2801c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (len > ucount) 2811c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil len = ucount; 2821c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG && 283dd073434b5285121007860914a004320d644ee7eAndy Walls !cx18_raw_vbi(cx) && buf != &cx->vbi.sliced_mpeg_buf) { 284302df9702192a68578916ef922c33370cbba350dAndy Walls /* 285302df9702192a68578916ef922c33370cbba350dAndy Walls * Try to find a good splice point in the PS, just before 286302df9702192a68578916ef922c33370cbba350dAndy Walls * an MPEG-2 Program Pack start code, and provide only 287302df9702192a68578916ef922c33370cbba350dAndy Walls * up to that point to the user, so it's easy to insert VBI data 288302df9702192a68578916ef922c33370cbba350dAndy Walls * the next time around. 2890c6292522968427d4f8e01f7c2e4216f04470072Andy Walls * 2900c6292522968427d4f8e01f7c2e4216f04470072Andy Walls * This will not work for an MPEG-2 TS and has only been 2910c6292522968427d4f8e01f7c2e4216f04470072Andy Walls * verified by analysis to work for an MPEG-2 PS. Helen Buus 2920c6292522968427d4f8e01f7c2e4216f04470072Andy Walls * pointed out this works for the CX23416 MPEG-2 DVD compatible 2930c6292522968427d4f8e01f7c2e4216f04470072Andy Walls * stream, and research indicates both the MPEG 2 SVCD and DVD 2940c6292522968427d4f8e01f7c2e4216f04470072Andy Walls * stream types use an MPEG-2 PS container. 295302df9702192a68578916ef922c33370cbba350dAndy Walls */ 296302df9702192a68578916ef922c33370cbba350dAndy Walls /* 297302df9702192a68578916ef922c33370cbba350dAndy Walls * An MPEG-2 Program Stream (PS) is a series of 298302df9702192a68578916ef922c33370cbba350dAndy Walls * MPEG-2 Program Packs terminated by an 299302df9702192a68578916ef922c33370cbba350dAndy Walls * MPEG Program End Code after the last Program Pack. 300302df9702192a68578916ef922c33370cbba350dAndy Walls * A Program Pack may hold a PS System Header packet and any 301302df9702192a68578916ef922c33370cbba350dAndy Walls * number of Program Elementary Stream (PES) Packets 302302df9702192a68578916ef922c33370cbba350dAndy Walls */ 3031c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil const char *start = buf->buf + buf->readpos; 3041c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil const char *p = start + 1; 3051c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil const u8 *q; 3061c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil u8 ch = cx->search_pack_header ? 0xba : 0xe0; 3071c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil int stuffing, i; 3081c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 3091c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil while (start + len > p) { 310302df9702192a68578916ef922c33370cbba350dAndy Walls /* Scan for a 0 to find a potential MPEG-2 start code */ 3111c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil q = memchr(p, 0, start + len - p); 3121c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (q == NULL) 3131c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil break; 3141c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil p = q + 1; 315302df9702192a68578916ef922c33370cbba350dAndy Walls /* 316302df9702192a68578916ef922c33370cbba350dAndy Walls * Keep looking if not a 317302df9702192a68578916ef922c33370cbba350dAndy Walls * MPEG-2 Pack header start code: 0x00 0x00 0x01 0xba 318302df9702192a68578916ef922c33370cbba350dAndy Walls * or MPEG-2 video PES start code: 0x00 0x00 0x01 0xe0 319302df9702192a68578916ef922c33370cbba350dAndy Walls */ 3201c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if ((char *)q + 15 >= buf->buf + buf->bytesused || 3211c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil q[1] != 0 || q[2] != 1 || q[3] != ch) 3221c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil continue; 323302df9702192a68578916ef922c33370cbba350dAndy Walls 324302df9702192a68578916ef922c33370cbba350dAndy Walls /* If expecting the primary video PES */ 3251c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (!cx->search_pack_header) { 326302df9702192a68578916ef922c33370cbba350dAndy Walls /* Continue if it couldn't be a PES packet */ 3271c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if ((q[6] & 0xc0) != 0x80) 3281c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil continue; 329302df9702192a68578916ef922c33370cbba350dAndy Walls /* Check if a PTS or PTS & DTS follow */ 330302df9702192a68578916ef922c33370cbba350dAndy Walls if (((q[7] & 0xc0) == 0x80 && /* PTS only */ 331302df9702192a68578916ef922c33370cbba350dAndy Walls (q[9] & 0xf0) == 0x20) || /* PTS only */ 332302df9702192a68578916ef922c33370cbba350dAndy Walls ((q[7] & 0xc0) == 0xc0 && /* PTS & DTS */ 333302df9702192a68578916ef922c33370cbba350dAndy Walls (q[9] & 0xf0) == 0x30)) { /* DTS follows */ 334302df9702192a68578916ef922c33370cbba350dAndy Walls /* Assume we found the video PES hdr */ 335302df9702192a68578916ef922c33370cbba350dAndy Walls ch = 0xba; /* next want a Program Pack*/ 3361c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil cx->search_pack_header = 1; 337302df9702192a68578916ef922c33370cbba350dAndy Walls p = q + 9; /* Skip this video PES hdr */ 3381c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 3391c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil continue; 3401c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 341302df9702192a68578916ef922c33370cbba350dAndy Walls 342302df9702192a68578916ef922c33370cbba350dAndy Walls /* We may have found a Program Pack start code */ 343302df9702192a68578916ef922c33370cbba350dAndy Walls 344302df9702192a68578916ef922c33370cbba350dAndy Walls /* Get the count of stuffing bytes & verify them */ 3451c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil stuffing = q[13] & 7; 3461c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* all stuffing bytes must be 0xff */ 3471c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil for (i = 0; i < stuffing; i++) 3481c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (q[14 + i] != 0xff) 3491c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil break; 350302df9702192a68578916ef922c33370cbba350dAndy Walls if (i == stuffing && /* right number of stuffing bytes*/ 351302df9702192a68578916ef922c33370cbba350dAndy Walls (q[4] & 0xc4) == 0x44 && /* marker check */ 352302df9702192a68578916ef922c33370cbba350dAndy Walls (q[12] & 3) == 3 && /* marker check */ 353302df9702192a68578916ef922c33370cbba350dAndy Walls q[14 + stuffing] == 0 && /* PES Pack or Sys Hdr */ 3541c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil q[15 + stuffing] == 0 && 3551c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil q[16 + stuffing] == 1) { 356302df9702192a68578916ef922c33370cbba350dAndy Walls /* We declare we actually found a Program Pack*/ 357302df9702192a68578916ef922c33370cbba350dAndy Walls cx->search_pack_header = 0; /* expect vid PES */ 3581c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil len = (char *)q - start; 35952fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls cx18_setup_sliced_vbi_mdl(cx); 36052fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls *stop = true; 3611c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil break; 3621c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 3631c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 3641c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 3651c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) { 3661c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil CX18_DEBUG_WARN("copy %zd bytes to user failed for %s\n", 3671c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil len, s->name); 3681c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return -EFAULT; 3691c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 3701c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil buf->readpos += len; 3711c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (s->type == CX18_ENC_STREAM_TYPE_MPG && 3721c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil buf != &cx->vbi.sliced_mpeg_buf) 3731c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil cx->mpg_data_received += len; 3741c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return len; 3751c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil} 3761c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 37752fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Wallsstatic size_t cx18_copy_mdl_to_user(struct cx18_stream *s, 37852fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls struct cx18_mdl *mdl, char __user *ubuf, size_t ucount) 37952fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls{ 38052fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls size_t tot_written = 0; 38152fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls int rc; 38252fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls bool stop = false; 38352fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls 38452fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls if (mdl->curr_buf == NULL) 38552fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls mdl->curr_buf = list_first_entry(&mdl->buf_list, 38652fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls struct cx18_buffer, list); 38752fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls 38852fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls if (list_entry_is_past_end(mdl->curr_buf, &mdl->buf_list, list)) { 38952fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls /* 39052fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls * For some reason we've exhausted the buffers, but the MDL 39152fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls * object still said some data was unread. 39252fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls * Fix that and bail out. 39352fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls */ 39452fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls mdl->readpos = mdl->bytesused; 39552fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls return 0; 39652fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls } 39752fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls 39852fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls list_for_each_entry_from(mdl->curr_buf, &mdl->buf_list, list) { 39952fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls 40052fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls if (mdl->curr_buf->readpos >= mdl->curr_buf->bytesused) 40152fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls continue; 40252fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls 40352fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls rc = cx18_copy_buf_to_user(s, mdl->curr_buf, ubuf + tot_written, 40452fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls ucount - tot_written, &stop); 40552fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls if (rc < 0) 40652fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls return rc; 40752fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls mdl->readpos += rc; 40852fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls tot_written += rc; 40952fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls 41052fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls if (stop || /* Forced stopping point for VBI insertion */ 41152fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls tot_written >= ucount || /* Reader request statisfied */ 41252fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls mdl->curr_buf->readpos < mdl->curr_buf->bytesused || 41352fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls mdl->readpos >= mdl->bytesused) /* MDL buffers drained */ 41452fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls break; 41552fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls } 41652fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls return tot_written; 41752fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls} 41852fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls 4191c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuilstatic ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf, 4201c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil size_t tot_count, int non_block) 4211c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil{ 4221c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil struct cx18 *cx = s->cx; 4231c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil size_t tot_written = 0; 4241c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil int single_frame = 0; 4251c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 42631554ae599a8ff6854bf8ecbedc1946c64854388Hans Verkuil if (atomic_read(&cx->ana_capturing) == 0 && s->id == -1) { 4271c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* shouldn't happen */ 4281c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil CX18_DEBUG_WARN("Stream %s not initialized before read\n", 4291c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil s->name); 4301c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return -EIO; 4311c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 4321c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 4331c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* Each VBI buffer is one frame, the v4l2 API says that for VBI the 4341c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil frames should arrive one-by-one, so make sure we never output more 4351c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil than one VBI frame at a time */ 436dd073434b5285121007860914a004320d644ee7eAndy Walls if (s->type == CX18_ENC_STREAM_TYPE_VBI && !cx18_raw_vbi(cx)) 4371c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil single_frame = 1; 4381c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 4391c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil for (;;) { 44052fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls struct cx18_mdl *mdl; 4411c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil int rc; 4421c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 44352fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls mdl = cx18_get_mdl(s, non_block, &rc); 4441c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* if there is no data available... */ 44552fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls if (mdl == NULL) { 4461c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* if we got data, then return that regardless */ 4471c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (tot_written) 4481c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil break; 4491c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* EOS condition */ 4501c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (rc == 0) { 4511c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); 4521c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil clear_bit(CX18_F_S_APPL_IO, &s->s_flags); 4531c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil cx18_release_stream(s); 4541c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 4551c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* set errno */ 4561c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return rc; 4571c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 4581c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 45952fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls rc = cx18_copy_mdl_to_user(s, mdl, ubuf + tot_written, 4601c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil tot_count - tot_written); 4611c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 46252fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls if (mdl != &cx->vbi.sliced_mpeg_mdl) { 46352fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls if (mdl->readpos == mdl->bytesused) 46452fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls cx18_stream_put_mdl_fw(s, mdl); 46566c2a6b0bc0b394d215768610d96f44cf97052acAndy Walls else 46652fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls cx18_push(s, mdl, &s->q_full); 46752fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls } else if (mdl->readpos == mdl->bytesused) { 4681c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; 4691c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 4701c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil cx->vbi.sliced_mpeg_size[idx] = 0; 4711c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil cx->vbi.inserted_frame++; 47252fcb3ecc6707f52dfe4297f96b7609d4ba517fbAndy Walls cx->vbi_data_inserted += mdl->bytesused; 4731c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 4741c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (rc < 0) 4751c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return rc; 4761c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil tot_written += rc; 4771c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 4781c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (tot_written == tot_count || single_frame) 4791c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil break; 4801c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 4811c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return tot_written; 4821c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil} 4831c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 4841c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuilstatic ssize_t cx18_read_pos(struct cx18_stream *s, char __user *ubuf, 4851c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil size_t count, loff_t *pos, int non_block) 4861c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil{ 4871c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil ssize_t rc = count ? cx18_read(s, ubuf, count, non_block) : 0; 4881c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil struct cx18 *cx = s->cx; 4891c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 4901c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil CX18_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc); 4911c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (rc > 0) 4921c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil pos += rc; 4931c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return rc; 4941c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil} 4951c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 4961c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuilint cx18_start_capture(struct cx18_open_id *id) 4971c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil{ 4981c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil struct cx18 *cx = id->cx; 4991c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil struct cx18_stream *s = &cx->streams[id->type]; 5001c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil struct cx18_stream *s_vbi; 50179f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls struct cx18_stream *s_idx; 5021c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 5031c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (s->type == CX18_ENC_STREAM_TYPE_RAD) { 5041c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* you cannot read from these stream types. */ 5051c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return -EPERM; 5061c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 5071c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 5081c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* Try to claim this stream. */ 5091c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (cx18_claim_stream(id, s->type)) 5101c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return -EBUSY; 5111c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 5121c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* If capture is already in progress, then we also have to 5131c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil do nothing extra. */ 5141c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (test_bit(CX18_F_S_STREAMOFF, &s->s_flags) || 5151c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil test_and_set_bit(CX18_F_S_STREAMING, &s->s_flags)) { 5161c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil set_bit(CX18_F_S_APPL_IO, &s->s_flags); 5171c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return 0; 5181c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 5191c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 52079f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls /* Start associated VBI or IDX stream capture if required */ 5211c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; 52279f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; 52379f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls if (s->type == CX18_ENC_STREAM_TYPE_MPG) { 52479f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls /* 52579f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls * The VBI and IDX streams should have been claimed 52679f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls * automatically, if for internal use, when the MPG stream was 52779f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls * claimed. We only need to start these streams capturing. 52879f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls */ 52979f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls if (test_bit(CX18_F_S_INTERNAL_USE, &s_idx->s_flags) && 53079f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls !test_and_set_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) { 53179f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls if (cx18_start_v4l2_encode_stream(s_idx)) { 53279f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls CX18_DEBUG_WARN("IDX capture start failed\n"); 53379f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls clear_bit(CX18_F_S_STREAMING, &s_idx->s_flags); 53479f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls goto start_failed; 53579f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls } 53679f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls CX18_DEBUG_INFO("IDX capture started\n"); 53779f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls } 53879f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) && 53979f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls !test_and_set_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) { 54079f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls if (cx18_start_v4l2_encode_stream(s_vbi)) { 54179f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls CX18_DEBUG_WARN("VBI capture start failed\n"); 54279f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags); 54379f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls goto start_failed; 54479f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls } 54579f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls CX18_DEBUG_INFO("VBI insertion started\n"); 5461c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 5471c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 5481c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 5491c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* Tell the card to start capturing */ 5501c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (!cx18_start_v4l2_encode_stream(s)) { 5511c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* We're done */ 5521c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil set_bit(CX18_F_S_APPL_IO, &s->s_flags); 5531c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* Resume a possibly paused encoder */ 5541c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) 5551c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, s->handle); 5561c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return 0; 5571c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 5581c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 55979f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Wallsstart_failed: 5601c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil CX18_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name); 5611c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 56279f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls /* 56379f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls * The associated VBI and IDX streams for internal use are released 56479f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls * automatically when the MPG stream is released. We only need to stop 56579f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls * the associated stream. 56679f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls */ 56779f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls if (s->type == CX18_ENC_STREAM_TYPE_MPG) { 56879f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls /* Stop the IDX stream which is always for internal use */ 56979f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls if (test_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) { 57079f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls cx18_stop_v4l2_encode_stream(s_idx, 0); 57179f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls clear_bit(CX18_F_S_STREAMING, &s_idx->s_flags); 57279f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls } 57379f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls /* Stop the VBI stream, if only running for internal use */ 57479f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls if (test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) && 57579f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { 57679f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls cx18_stop_v4l2_encode_stream(s_vbi, 0); 57779f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags); 57879f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls } 5791c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 5801c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil clear_bit(CX18_F_S_STREAMING, &s->s_flags); 58179f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls cx18_release_stream(s); /* Also releases associated streams */ 5821c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return -EIO; 5831c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil} 5841c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 5851c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuilssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count, 5861c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil loff_t *pos) 5871c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil{ 5880b5f265a88d89cbbf8abc42ca3311cb3219162abHans Verkuil struct cx18_open_id *id = file2id(filp); 5891c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil struct cx18 *cx = id->cx; 5901c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil struct cx18_stream *s = &cx->streams[id->type]; 5911c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil int rc; 5921c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 5931c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil CX18_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name); 5941c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 5951c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil mutex_lock(&cx->serialize_lock); 5961c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil rc = cx18_start_capture(id); 5971c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil mutex_unlock(&cx->serialize_lock); 5981c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (rc) 5991c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return rc; 600b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth 6011bf5842fe3b61d2dbbced96dbd27ad26fe93444aSimon Farnsworth if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && 602b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth (id->type == CX18_ENC_STREAM_TYPE_YUV)) { 6031bf5842fe3b61d2dbbced96dbd27ad26fe93444aSimon Farnsworth return videobuf_read_stream(&s->vbuf_q, buf, count, pos, 0, 604b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth filp->f_flags & O_NONBLOCK); 605b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth } 606b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth 6071c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); 6081c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil} 6091c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 6101c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuilunsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait) 6111c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil{ 6120b5f265a88d89cbbf8abc42ca3311cb3219162abHans Verkuil struct cx18_open_id *id = file2id(filp); 6131c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil struct cx18 *cx = id->cx; 6141c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil struct cx18_stream *s = &cx->streams[id->type]; 6151c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags); 6161c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 6171c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* Start a capture if there is none */ 6181c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) { 6191c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil int rc; 6201c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 6211c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil mutex_lock(&cx->serialize_lock); 6221c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil rc = cx18_start_capture(id); 6231c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil mutex_unlock(&cx->serialize_lock); 6241c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (rc) { 6251c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil CX18_DEBUG_INFO("Could not start capture for %s (%d)\n", 6261c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil s->name, rc); 6271c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return POLLERR; 6281c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 6291c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil CX18_DEBUG_FILE("Encoder poll started capture\n"); 6301c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 6311c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 6321bf5842fe3b61d2dbbced96dbd27ad26fe93444aSimon Farnsworth if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && 633b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth (id->type == CX18_ENC_STREAM_TYPE_YUV)) { 6341bf5842fe3b61d2dbbced96dbd27ad26fe93444aSimon Farnsworth int videobuf_poll = videobuf_poll_stream(filp, &s->vbuf_q, wait); 6351bf5842fe3b61d2dbbced96dbd27ad26fe93444aSimon Farnsworth if (eof && videobuf_poll == POLLERR) 6361bf5842fe3b61d2dbbced96dbd27ad26fe93444aSimon Farnsworth return POLLHUP; 6371bf5842fe3b61d2dbbced96dbd27ad26fe93444aSimon Farnsworth else 6381bf5842fe3b61d2dbbced96dbd27ad26fe93444aSimon Farnsworth return videobuf_poll; 639b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth } 640b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth 6411c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* add stream's waitq to the poll list */ 6421c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil CX18_DEBUG_HI_FILE("Encoder poll\n"); 6431c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil poll_wait(filp, &s->waitq, wait); 6441c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 645c37b11bf17b66b960b217c35283aa9c55eacb292Andy Walls if (atomic_read(&s->q_full.depth)) 6461c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return POLLIN | POLLRDNORM; 6471c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (eof) 6481c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return POLLHUP; 6491c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return 0; 6501c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil} 6511c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 652b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Tothint cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma) 653b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth{ 654b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth struct cx18_open_id *id = file->private_data; 655b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth struct cx18 *cx = id->cx; 656b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth struct cx18_stream *s = &cx->streams[id->type]; 657b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags); 658b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth 6591bf5842fe3b61d2dbbced96dbd27ad26fe93444aSimon Farnsworth if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && 660b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth (id->type == CX18_ENC_STREAM_TYPE_YUV)) { 661b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth 662b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth /* Start a capture if there is none */ 663b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) { 664b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth int rc; 665b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth 666b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth mutex_lock(&cx->serialize_lock); 667b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth rc = cx18_start_capture(id); 668b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth mutex_unlock(&cx->serialize_lock); 669b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth if (rc) { 670b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth CX18_DEBUG_INFO( 671b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth "Could not start capture for %s (%d)\n", 672b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth s->name, rc); 673b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth return -EINVAL; 674b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth } 6751bf5842fe3b61d2dbbced96dbd27ad26fe93444aSimon Farnsworth CX18_DEBUG_FILE("Encoder mmap started capture\n"); 676b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth } 677b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth 6781bf5842fe3b61d2dbbced96dbd27ad26fe93444aSimon Farnsworth return videobuf_mmap_mapper(&s->vbuf_q, vma); 679b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth } 680b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth 681b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth return -EINVAL; 682b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth} 683b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth 684b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Tothvoid cx18_vb_timeout(unsigned long data) 685b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth{ 686b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth struct cx18_stream *s = (struct cx18_stream *)data; 687b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth struct cx18_videobuf_buffer *buf; 688b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth unsigned long flags; 689b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth 690b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth /* Return all of the buffers in error state, so the vbi/vid inode 691b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth * can return from blocking. 692b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth */ 693b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth spin_lock_irqsave(&s->vb_lock, flags); 694b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth while (!list_empty(&s->vb_capture)) { 695b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth buf = list_entry(s->vb_capture.next, 696b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth struct cx18_videobuf_buffer, vb.queue); 697b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth list_del(&buf->vb.queue); 698b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth buf->vb.state = VIDEOBUF_ERROR; 699b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth wake_up(&buf->vb.done); 700b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth } 701b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth spin_unlock_irqrestore(&s->vb_lock, flags); 702b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth} 703b7101de3fff596b35e45cd9fb7007caa07e97c9aSteven Toth 7041c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuilvoid cx18_stop_capture(struct cx18_open_id *id, int gop_end) 7051c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil{ 7061c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil struct cx18 *cx = id->cx; 7071c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil struct cx18_stream *s = &cx->streams[id->type]; 70879f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; 70979f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls struct cx18_stream *s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; 7101c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 7111c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil CX18_DEBUG_IOCTL("close() of %s\n", s->name); 7121c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 7131c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* 'Unclaim' this stream */ 7141c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 7151c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* Stop capturing */ 7161c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) { 7171c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil CX18_DEBUG_INFO("close stopping capture\n"); 71879f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls if (id->type == CX18_ENC_STREAM_TYPE_MPG) { 71979f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls /* Stop internal use associated VBI and IDX streams */ 72079f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls if (test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) && 72179f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { 72279f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls CX18_DEBUG_INFO("close stopping embedded VBI " 72379f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls "capture\n"); 72479f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls cx18_stop_v4l2_encode_stream(s_vbi, 0); 72579f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls } 72679f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls if (test_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) { 72779f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls CX18_DEBUG_INFO("close stopping IDX capture\n"); 72879f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls cx18_stop_v4l2_encode_stream(s_idx, 0); 72979f3e96018dc55ff7819a6a1ac3740a1d7103589Andy Walls } 7301c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 7311c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (id->type == CX18_ENC_STREAM_TYPE_VBI && 7321c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) 7331c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* Also used internally, don't stop capturing */ 7341c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil s->id = -1; 7351c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil else 7361c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil cx18_stop_v4l2_encode_stream(s, gop_end); 7371c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 7381c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (!gop_end) { 7391c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil clear_bit(CX18_F_S_APPL_IO, &s->s_flags); 7401c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); 7411c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil cx18_release_stream(s); 7421c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 7431c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil} 7441c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 745bec43661b1dc0075b7445223ba775674133b164dHans Verkuilint cx18_v4l2_close(struct file *filp) 7461c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil{ 7470b5f265a88d89cbbf8abc42ca3311cb3219162abHans Verkuil struct v4l2_fh *fh = filp->private_data; 7480b5f265a88d89cbbf8abc42ca3311cb3219162abHans Verkuil struct cx18_open_id *id = fh2id(fh); 7491c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil struct cx18 *cx = id->cx; 7501c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil struct cx18_stream *s = &cx->streams[id->type]; 7511c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 7521c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil CX18_DEBUG_IOCTL("close() of %s\n", s->name); 7531c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 7541c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil mutex_lock(&cx->serialize_lock); 7554d68e700d6a192a5a8b394b26ac056a1c0fa6ebcHans Verkuil /* Stop radio */ 7564d68e700d6a192a5a8b394b26ac056a1c0fa6ebcHans Verkuil if (id->type == CX18_ENC_STREAM_TYPE_RAD && 7574d68e700d6a192a5a8b394b26ac056a1c0fa6ebcHans Verkuil v4l2_fh_is_singular_file(filp)) { 7581c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* Closing radio device, return to TV mode */ 7591c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil cx18_mute(cx); 7601c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* Mark that the radio is no longer in use */ 7611c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil clear_bit(CX18_F_I_RADIO_USER, &cx->i_flags); 7621c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* Switch tuner to TV */ 763f41737ece472cd803ffb24ac9f5d6fdd1d871341Hans Verkuil cx18_call_all(cx, core, s_std, cx->std); 7641c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* Select correct audio input (i.e. TV tuner or Line in) */ 7651c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil cx18_audio_set_io(cx); 76631554ae599a8ff6854bf8ecbedc1946c64854388Hans Verkuil if (atomic_read(&cx->ana_capturing) > 0) { 7671c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* Undo video mute */ 7681c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, 769a75b9be1c2fb52dee765d35f29031dd788d522ebHans Verkuil (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute) | 770a75b9be1c2fb52dee765d35f29031dd788d522ebHans Verkuil (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8))); 7711c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 7721c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* Done! Unmute and continue. */ 7731c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil cx18_unmute(cx); 7741c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 7754d68e700d6a192a5a8b394b26ac056a1c0fa6ebcHans Verkuil 7764d68e700d6a192a5a8b394b26ac056a1c0fa6ebcHans Verkuil v4l2_fh_del(fh); 7774d68e700d6a192a5a8b394b26ac056a1c0fa6ebcHans Verkuil v4l2_fh_exit(fh); 7784d68e700d6a192a5a8b394b26ac056a1c0fa6ebcHans Verkuil 7794d68e700d6a192a5a8b394b26ac056a1c0fa6ebcHans Verkuil /* 'Unclaim' this stream */ 7804d68e700d6a192a5a8b394b26ac056a1c0fa6ebcHans Verkuil if (s->id == id->open_id) 7814d68e700d6a192a5a8b394b26ac056a1c0fa6ebcHans Verkuil cx18_stop_capture(id, 0); 7821c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil kfree(id); 7831c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil mutex_unlock(&cx->serialize_lock); 7841c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return 0; 7851c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil} 7861c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 7871c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuilstatic int cx18_serialized_open(struct cx18_stream *s, struct file *filp) 7881c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil{ 7891c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil struct cx18 *cx = s->cx; 7901c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil struct cx18_open_id *item; 7911c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 7921c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil CX18_DEBUG_FILE("open %s\n", s->name); 7931c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 7941c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* Allocate memory */ 7950b5f265a88d89cbbf8abc42ca3311cb3219162abHans Verkuil item = kzalloc(sizeof(struct cx18_open_id), GFP_KERNEL); 7961c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (NULL == item) { 7971c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil CX18_DEBUG_WARN("nomem on v4l2 open\n"); 7981c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return -ENOMEM; 7991c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 8000b5f265a88d89cbbf8abc42ca3311cb3219162abHans Verkuil v4l2_fh_init(&item->fh, s->video_dev); 8010b5f265a88d89cbbf8abc42ca3311cb3219162abHans Verkuil 8021c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil item->cx = cx; 8031c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil item->type = s->type; 8041c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 8051c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil item->open_id = cx->open_id++; 8060b5f265a88d89cbbf8abc42ca3311cb3219162abHans Verkuil filp->private_data = &item->fh; 8074d68e700d6a192a5a8b394b26ac056a1c0fa6ebcHans Verkuil v4l2_fh_add(&item->fh); 8081c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 8094d68e700d6a192a5a8b394b26ac056a1c0fa6ebcHans Verkuil if (item->type == CX18_ENC_STREAM_TYPE_RAD && 8104d68e700d6a192a5a8b394b26ac056a1c0fa6ebcHans Verkuil v4l2_fh_is_singular_file(filp)) { 8111c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { 81231554ae599a8ff6854bf8ecbedc1946c64854388Hans Verkuil if (atomic_read(&cx->ana_capturing) > 0) { 8131c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* switching to radio while capture is 8141c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil in progress is not polite */ 8154d68e700d6a192a5a8b394b26ac056a1c0fa6ebcHans Verkuil v4l2_fh_del(&item->fh); 8160b5f265a88d89cbbf8abc42ca3311cb3219162abHans Verkuil v4l2_fh_exit(&item->fh); 8171c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil kfree(item); 8181c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return -EBUSY; 8191c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 8201c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 8211c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 8221c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* Mark that the radio is being used. */ 8231c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil set_bit(CX18_F_I_RADIO_USER, &cx->i_flags); 8241c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* We have the radio */ 8251c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil cx18_mute(cx); 8261c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* Switch tuner to radio */ 827ff2a20018094c593a35f4887bbdabf8926ddb6e6Andy Walls cx18_call_all(cx, tuner, s_radio); 8281c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* Select the correct audio input (i.e. radio tuner) */ 8291c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil cx18_audio_set_io(cx); 8301c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil /* Done! Unmute and continue. */ 8311c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil cx18_unmute(cx); 8321c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 8331c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return 0; 8341c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil} 8351c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 836bec43661b1dc0075b7445223ba775674133b164dHans Verkuilint cx18_v4l2_open(struct file *filp) 8371c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil{ 8385811cf99df2e3c102055be3ea77508e56c9f77c6Andy Walls int res; 8395811cf99df2e3c102055be3ea77508e56c9f77c6Andy Walls struct video_device *video_dev = video_devdata(filp); 8405811cf99df2e3c102055be3ea77508e56c9f77c6Andy Walls struct cx18_stream *s = video_get_drvdata(video_dev); 84132a60955fb6312f19ea4856e66b894bfb6c4e949Joe Perches struct cx18 *cx = s->cx; 8421c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 8431c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil mutex_lock(&cx->serialize_lock); 8441c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil if (cx18_init_on_first_open(cx)) { 84550462eb065e12f45851a9959a90d46b758944552Laurent Pinchart CX18_ERR("Failed to initialize on %s\n", 84650462eb065e12f45851a9959a90d46b758944552Laurent Pinchart video_device_node_name(video_dev)); 8471c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil mutex_unlock(&cx->serialize_lock); 8481c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return -ENXIO; 8491c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 8501c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil res = cx18_serialized_open(s, filp); 8511c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil mutex_unlock(&cx->serialize_lock); 8521c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil return res; 8531c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil} 8541c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 8551c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuilvoid cx18_mute(struct cx18 *cx) 8561c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil{ 857d3c5e7075508a6874d1a53d0a409b0bbbe3a9fbeAndy Walls u32 h; 858d3c5e7075508a6874d1a53d0a409b0bbbe3a9fbeAndy Walls if (atomic_read(&cx->ana_capturing)) { 859d3c5e7075508a6874d1a53d0a409b0bbbe3a9fbeAndy Walls h = cx18_find_handle(cx); 860d3c5e7075508a6874d1a53d0a409b0bbbe3a9fbeAndy Walls if (h != CX18_INVALID_TASK_HANDLE) 861d3c5e7075508a6874d1a53d0a409b0bbbe3a9fbeAndy Walls cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, h, 1); 862d3c5e7075508a6874d1a53d0a409b0bbbe3a9fbeAndy Walls else 863d3c5e7075508a6874d1a53d0a409b0bbbe3a9fbeAndy Walls CX18_ERR("Can't find valid task handle for mute\n"); 864d3c5e7075508a6874d1a53d0a409b0bbbe3a9fbeAndy Walls } 8651c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil CX18_DEBUG_INFO("Mute\n"); 8661c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil} 8671c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil 8681c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuilvoid cx18_unmute(struct cx18 *cx) 8691c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil{ 870d3c5e7075508a6874d1a53d0a409b0bbbe3a9fbeAndy Walls u32 h; 87131554ae599a8ff6854bf8ecbedc1946c64854388Hans Verkuil if (atomic_read(&cx->ana_capturing)) { 872d3c5e7075508a6874d1a53d0a409b0bbbe3a9fbeAndy Walls h = cx18_find_handle(cx); 873d3c5e7075508a6874d1a53d0a409b0bbbe3a9fbeAndy Walls if (h != CX18_INVALID_TASK_HANDLE) { 874d3c5e7075508a6874d1a53d0a409b0bbbe3a9fbeAndy Walls cx18_msleep_timeout(100, 0); 875d3c5e7075508a6874d1a53d0a409b0bbbe3a9fbeAndy Walls cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, h, 12); 876d3c5e7075508a6874d1a53d0a409b0bbbe3a9fbeAndy Walls cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, h, 0); 877d3c5e7075508a6874d1a53d0a409b0bbbe3a9fbeAndy Walls } else 878d3c5e7075508a6874d1a53d0a409b0bbbe3a9fbeAndy Walls CX18_ERR("Can't find valid task handle for unmute\n"); 8791c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil } 8801c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil CX18_DEBUG_INFO("Unmute\n"); 8811c1e45d17b663d4749af456ab7c2fc1f36405ef8Hans Verkuil} 882