18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci file operation functions 48c2ecf20Sopenharmony_ci Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> 58c2ecf20Sopenharmony_ci Copyright (C) 2004 Chris Kennedy <c@groovy.org> 68c2ecf20Sopenharmony_ci Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "ivtv-driver.h" 118c2ecf20Sopenharmony_ci#include "ivtv-fileops.h" 128c2ecf20Sopenharmony_ci#include "ivtv-i2c.h" 138c2ecf20Sopenharmony_ci#include "ivtv-queue.h" 148c2ecf20Sopenharmony_ci#include "ivtv-udma.h" 158c2ecf20Sopenharmony_ci#include "ivtv-irq.h" 168c2ecf20Sopenharmony_ci#include "ivtv-vbi.h" 178c2ecf20Sopenharmony_ci#include "ivtv-mailbox.h" 188c2ecf20Sopenharmony_ci#include "ivtv-routing.h" 198c2ecf20Sopenharmony_ci#include "ivtv-streams.h" 208c2ecf20Sopenharmony_ci#include "ivtv-yuv.h" 218c2ecf20Sopenharmony_ci#include "ivtv-ioctl.h" 228c2ecf20Sopenharmony_ci#include "ivtv-cards.h" 238c2ecf20Sopenharmony_ci#include "ivtv-firmware.h" 248c2ecf20Sopenharmony_ci#include <media/v4l2-event.h> 258c2ecf20Sopenharmony_ci#include <media/i2c/saa7115.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* This function tries to claim the stream for a specific file descriptor. 288c2ecf20Sopenharmony_ci If no one else is using this stream then the stream is claimed and 298c2ecf20Sopenharmony_ci associated VBI streams are also automatically claimed. 308c2ecf20Sopenharmony_ci Possible error returns: -EBUSY if someone else has claimed 318c2ecf20Sopenharmony_ci the stream or 0 on success. */ 328c2ecf20Sopenharmony_ciint ivtv_claim_stream(struct ivtv_open_id *id, int type) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 358c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[type]; 368c2ecf20Sopenharmony_ci struct ivtv_stream *s_vbi; 378c2ecf20Sopenharmony_ci int vbi_type; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci if (test_and_set_bit(IVTV_F_S_CLAIMED, &s->s_flags)) { 408c2ecf20Sopenharmony_ci /* someone already claimed this stream */ 418c2ecf20Sopenharmony_ci if (s->fh == &id->fh) { 428c2ecf20Sopenharmony_ci /* yes, this file descriptor did. So that's OK. */ 438c2ecf20Sopenharmony_ci return 0; 448c2ecf20Sopenharmony_ci } 458c2ecf20Sopenharmony_ci if (s->fh == NULL && (type == IVTV_DEC_STREAM_TYPE_VBI || 468c2ecf20Sopenharmony_ci type == IVTV_ENC_STREAM_TYPE_VBI)) { 478c2ecf20Sopenharmony_ci /* VBI is handled already internally, now also assign 488c2ecf20Sopenharmony_ci the file descriptor to this stream for external 498c2ecf20Sopenharmony_ci reading of the stream. */ 508c2ecf20Sopenharmony_ci s->fh = &id->fh; 518c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("Start Read VBI\n"); 528c2ecf20Sopenharmony_ci return 0; 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci /* someone else is using this stream already */ 558c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("Stream %d is busy\n", type); 568c2ecf20Sopenharmony_ci return -EBUSY; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci s->fh = &id->fh; 598c2ecf20Sopenharmony_ci if (type == IVTV_DEC_STREAM_TYPE_VBI) { 608c2ecf20Sopenharmony_ci /* Enable reinsertion interrupt */ 618c2ecf20Sopenharmony_ci ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci /* IVTV_DEC_STREAM_TYPE_MPG needs to claim IVTV_DEC_STREAM_TYPE_VBI, 658c2ecf20Sopenharmony_ci IVTV_ENC_STREAM_TYPE_MPG needs to claim IVTV_ENC_STREAM_TYPE_VBI 668c2ecf20Sopenharmony_ci (provided VBI insertion is on and sliced VBI is selected), for all 678c2ecf20Sopenharmony_ci other streams we're done */ 688c2ecf20Sopenharmony_ci if (type == IVTV_DEC_STREAM_TYPE_MPG) { 698c2ecf20Sopenharmony_ci vbi_type = IVTV_DEC_STREAM_TYPE_VBI; 708c2ecf20Sopenharmony_ci } else if (type == IVTV_ENC_STREAM_TYPE_MPG && 718c2ecf20Sopenharmony_ci itv->vbi.insert_mpeg && !ivtv_raw_vbi(itv)) { 728c2ecf20Sopenharmony_ci vbi_type = IVTV_ENC_STREAM_TYPE_VBI; 738c2ecf20Sopenharmony_ci } else { 748c2ecf20Sopenharmony_ci return 0; 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci s_vbi = &itv->streams[vbi_type]; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (!test_and_set_bit(IVTV_F_S_CLAIMED, &s_vbi->s_flags)) { 798c2ecf20Sopenharmony_ci /* Enable reinsertion interrupt */ 808c2ecf20Sopenharmony_ci if (vbi_type == IVTV_DEC_STREAM_TYPE_VBI) 818c2ecf20Sopenharmony_ci ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci /* mark that it is used internally */ 848c2ecf20Sopenharmony_ci set_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags); 858c2ecf20Sopenharmony_ci return 0; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ivtv_claim_stream); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* This function releases a previously claimed stream. It will take into 908c2ecf20Sopenharmony_ci account associated VBI streams. */ 918c2ecf20Sopenharmony_civoid ivtv_release_stream(struct ivtv_stream *s) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci struct ivtv *itv = s->itv; 948c2ecf20Sopenharmony_ci struct ivtv_stream *s_vbi; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci s->fh = NULL; 978c2ecf20Sopenharmony_ci if ((s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type == IVTV_ENC_STREAM_TYPE_VBI) && 988c2ecf20Sopenharmony_ci test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) { 998c2ecf20Sopenharmony_ci /* this stream is still in use internally */ 1008c2ecf20Sopenharmony_ci return; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci if (!test_and_clear_bit(IVTV_F_S_CLAIMED, &s->s_flags)) { 1038c2ecf20Sopenharmony_ci IVTV_DEBUG_WARN("Release stream %s not in use!\n", s->name); 1048c2ecf20Sopenharmony_ci return; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci ivtv_flush_queues(s); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* disable reinsertion interrupt */ 1108c2ecf20Sopenharmony_ci if (s->type == IVTV_DEC_STREAM_TYPE_VBI) 1118c2ecf20Sopenharmony_ci ivtv_set_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci /* IVTV_DEC_STREAM_TYPE_MPG needs to release IVTV_DEC_STREAM_TYPE_VBI, 1148c2ecf20Sopenharmony_ci IVTV_ENC_STREAM_TYPE_MPG needs to release IVTV_ENC_STREAM_TYPE_VBI, 1158c2ecf20Sopenharmony_ci for all other streams we're done */ 1168c2ecf20Sopenharmony_ci if (s->type == IVTV_DEC_STREAM_TYPE_MPG) 1178c2ecf20Sopenharmony_ci s_vbi = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI]; 1188c2ecf20Sopenharmony_ci else if (s->type == IVTV_ENC_STREAM_TYPE_MPG) 1198c2ecf20Sopenharmony_ci s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; 1208c2ecf20Sopenharmony_ci else 1218c2ecf20Sopenharmony_ci return; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* clear internal use flag */ 1248c2ecf20Sopenharmony_ci if (!test_and_clear_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags)) { 1258c2ecf20Sopenharmony_ci /* was already cleared */ 1268c2ecf20Sopenharmony_ci return; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci if (s_vbi->fh) { 1298c2ecf20Sopenharmony_ci /* VBI stream still claimed by a file descriptor */ 1308c2ecf20Sopenharmony_ci return; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci /* disable reinsertion interrupt */ 1338c2ecf20Sopenharmony_ci if (s_vbi->type == IVTV_DEC_STREAM_TYPE_VBI) 1348c2ecf20Sopenharmony_ci ivtv_set_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); 1358c2ecf20Sopenharmony_ci clear_bit(IVTV_F_S_CLAIMED, &s_vbi->s_flags); 1368c2ecf20Sopenharmony_ci ivtv_flush_queues(s_vbi); 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ivtv_release_stream); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic void ivtv_dualwatch(struct ivtv *itv) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci struct v4l2_tuner vt; 1438c2ecf20Sopenharmony_ci u32 new_stereo_mode; 1448c2ecf20Sopenharmony_ci const u32 dual = 0x02; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci new_stereo_mode = v4l2_ctrl_g_ctrl(itv->cxhdl.audio_mode); 1478c2ecf20Sopenharmony_ci memset(&vt, 0, sizeof(vt)); 1488c2ecf20Sopenharmony_ci ivtv_call_all(itv, tuner, g_tuner, &vt); 1498c2ecf20Sopenharmony_ci if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && (vt.rxsubchans & V4L2_TUNER_SUB_LANG2)) 1508c2ecf20Sopenharmony_ci new_stereo_mode = dual; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (new_stereo_mode == itv->dualwatch_stereo_mode) 1538c2ecf20Sopenharmony_ci return; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x.\n", 1568c2ecf20Sopenharmony_ci itv->dualwatch_stereo_mode, new_stereo_mode); 1578c2ecf20Sopenharmony_ci if (v4l2_ctrl_s_ctrl(itv->cxhdl.audio_mode, new_stereo_mode)) 1588c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("dualwatch: changing stereo flag failed\n"); 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic void ivtv_update_pgm_info(struct ivtv *itv) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci u32 wr_idx = (read_enc(itv->pgm_info_offset) - itv->pgm_info_offset - 4) / 24; 1648c2ecf20Sopenharmony_ci int cnt; 1658c2ecf20Sopenharmony_ci int i = 0; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (wr_idx >= itv->pgm_info_num) { 1688c2ecf20Sopenharmony_ci IVTV_DEBUG_WARN("Invalid PGM index %d (>= %d)\n", wr_idx, itv->pgm_info_num); 1698c2ecf20Sopenharmony_ci return; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci cnt = (wr_idx + itv->pgm_info_num - itv->pgm_info_write_idx) % itv->pgm_info_num; 1728c2ecf20Sopenharmony_ci while (i < cnt) { 1738c2ecf20Sopenharmony_ci int idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num; 1748c2ecf20Sopenharmony_ci struct v4l2_enc_idx_entry *e = itv->pgm_info + idx; 1758c2ecf20Sopenharmony_ci u32 addr = itv->pgm_info_offset + 4 + idx * 24; 1768c2ecf20Sopenharmony_ci const int mapping[8] = { -1, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_P, -1, 1778c2ecf20Sopenharmony_ci V4L2_ENC_IDX_FRAME_B, -1, -1, -1 }; 1788c2ecf20Sopenharmony_ci // 1=I, 2=P, 4=B 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci e->offset = read_enc(addr + 4) + ((u64)read_enc(addr + 8) << 32); 1818c2ecf20Sopenharmony_ci if (e->offset > itv->mpg_data_received) { 1828c2ecf20Sopenharmony_ci break; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci e->offset += itv->vbi_data_inserted; 1858c2ecf20Sopenharmony_ci e->length = read_enc(addr); 1868c2ecf20Sopenharmony_ci e->pts = read_enc(addr + 16) + ((u64)(read_enc(addr + 20) & 1) << 32); 1878c2ecf20Sopenharmony_ci e->flags = mapping[read_enc(addr + 12) & 7]; 1888c2ecf20Sopenharmony_ci i++; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci itv->pgm_info_write_idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, int *err) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci struct ivtv *itv = s->itv; 1968c2ecf20Sopenharmony_ci struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; 1978c2ecf20Sopenharmony_ci struct ivtv_buffer *buf; 1988c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci *err = 0; 2018c2ecf20Sopenharmony_ci while (1) { 2028c2ecf20Sopenharmony_ci if (s->type == IVTV_ENC_STREAM_TYPE_MPG) { 2038c2ecf20Sopenharmony_ci /* Process pending program info updates and pending VBI data */ 2048c2ecf20Sopenharmony_ci ivtv_update_pgm_info(itv); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (time_after(jiffies, 2078c2ecf20Sopenharmony_ci itv->dualwatch_jiffies + 2088c2ecf20Sopenharmony_ci msecs_to_jiffies(1000))) { 2098c2ecf20Sopenharmony_ci itv->dualwatch_jiffies = jiffies; 2108c2ecf20Sopenharmony_ci ivtv_dualwatch(itv); 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (test_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags) && 2148c2ecf20Sopenharmony_ci !test_bit(IVTV_F_S_APPL_IO, &s_vbi->s_flags)) { 2158c2ecf20Sopenharmony_ci while ((buf = ivtv_dequeue(s_vbi, &s_vbi->q_full))) { 2168c2ecf20Sopenharmony_ci /* byteswap and process VBI data */ 2178c2ecf20Sopenharmony_ci ivtv_process_vbi_data(itv, buf, s_vbi->dma_pts, s_vbi->type); 2188c2ecf20Sopenharmony_ci ivtv_enqueue(s_vbi, buf, &s_vbi->q_free); 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci buf = &itv->vbi.sliced_mpeg_buf; 2228c2ecf20Sopenharmony_ci if (buf->readpos != buf->bytesused) { 2238c2ecf20Sopenharmony_ci return buf; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* do we have leftover data? */ 2288c2ecf20Sopenharmony_ci buf = ivtv_dequeue(s, &s->q_io); 2298c2ecf20Sopenharmony_ci if (buf) 2308c2ecf20Sopenharmony_ci return buf; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci /* do we have new data? */ 2338c2ecf20Sopenharmony_ci buf = ivtv_dequeue(s, &s->q_full); 2348c2ecf20Sopenharmony_ci if (buf) { 2358c2ecf20Sopenharmony_ci if ((buf->b_flags & IVTV_F_B_NEED_BUF_SWAP) == 0) 2368c2ecf20Sopenharmony_ci return buf; 2378c2ecf20Sopenharmony_ci buf->b_flags &= ~IVTV_F_B_NEED_BUF_SWAP; 2388c2ecf20Sopenharmony_ci if (s->type == IVTV_ENC_STREAM_TYPE_MPG) 2398c2ecf20Sopenharmony_ci /* byteswap MPG data */ 2408c2ecf20Sopenharmony_ci ivtv_buf_swap(buf); 2418c2ecf20Sopenharmony_ci else if (s->type != IVTV_DEC_STREAM_TYPE_VBI) { 2428c2ecf20Sopenharmony_ci /* byteswap and process VBI data */ 2438c2ecf20Sopenharmony_ci ivtv_process_vbi_data(itv, buf, s->dma_pts, s->type); 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci return buf; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* return if end of stream */ 2498c2ecf20Sopenharmony_ci if (s->type != IVTV_DEC_STREAM_TYPE_VBI && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { 2508c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("EOS %s\n", s->name); 2518c2ecf20Sopenharmony_ci return NULL; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci /* return if file was opened with O_NONBLOCK */ 2558c2ecf20Sopenharmony_ci if (non_block) { 2568c2ecf20Sopenharmony_ci *err = -EAGAIN; 2578c2ecf20Sopenharmony_ci return NULL; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci /* wait for more data to arrive */ 2618c2ecf20Sopenharmony_ci mutex_unlock(&itv->serialize_lock); 2628c2ecf20Sopenharmony_ci prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); 2638c2ecf20Sopenharmony_ci /* New buffers might have become available before we were added to the waitqueue */ 2648c2ecf20Sopenharmony_ci if (!s->q_full.buffers) 2658c2ecf20Sopenharmony_ci schedule(); 2668c2ecf20Sopenharmony_ci finish_wait(&s->waitq, &wait); 2678c2ecf20Sopenharmony_ci mutex_lock(&itv->serialize_lock); 2688c2ecf20Sopenharmony_ci if (signal_pending(current)) { 2698c2ecf20Sopenharmony_ci /* return if a signal was received */ 2708c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("User stopped %s\n", s->name); 2718c2ecf20Sopenharmony_ci *err = -EINTR; 2728c2ecf20Sopenharmony_ci return NULL; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic void ivtv_setup_sliced_vbi_buf(struct ivtv *itv) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci int idx = itv->vbi.inserted_frame % IVTV_VBI_FRAMES; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci itv->vbi.sliced_mpeg_buf.buf = itv->vbi.sliced_mpeg_data[idx]; 2828c2ecf20Sopenharmony_ci itv->vbi.sliced_mpeg_buf.bytesused = itv->vbi.sliced_mpeg_size[idx]; 2838c2ecf20Sopenharmony_ci itv->vbi.sliced_mpeg_buf.readpos = 0; 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic size_t ivtv_copy_buf_to_user(struct ivtv_stream *s, struct ivtv_buffer *buf, 2878c2ecf20Sopenharmony_ci char __user *ubuf, size_t ucount) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci struct ivtv *itv = s->itv; 2908c2ecf20Sopenharmony_ci size_t len = buf->bytesused - buf->readpos; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (len > ucount) len = ucount; 2938c2ecf20Sopenharmony_ci if (itv->vbi.insert_mpeg && s->type == IVTV_ENC_STREAM_TYPE_MPG && 2948c2ecf20Sopenharmony_ci !ivtv_raw_vbi(itv) && buf != &itv->vbi.sliced_mpeg_buf) { 2958c2ecf20Sopenharmony_ci const char *start = buf->buf + buf->readpos; 2968c2ecf20Sopenharmony_ci const char *p = start + 1; 2978c2ecf20Sopenharmony_ci const u8 *q; 2988c2ecf20Sopenharmony_ci u8 ch = itv->search_pack_header ? 0xba : 0xe0; 2998c2ecf20Sopenharmony_ci int stuffing, i; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci while (start + len > p && (q = memchr(p, 0, start + len - p))) { 3028c2ecf20Sopenharmony_ci p = q + 1; 3038c2ecf20Sopenharmony_ci if ((char *)q + 15 >= buf->buf + buf->bytesused || 3048c2ecf20Sopenharmony_ci q[1] != 0 || q[2] != 1 || q[3] != ch) { 3058c2ecf20Sopenharmony_ci continue; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci if (!itv->search_pack_header) { 3088c2ecf20Sopenharmony_ci if ((q[6] & 0xc0) != 0x80) 3098c2ecf20Sopenharmony_ci continue; 3108c2ecf20Sopenharmony_ci if (((q[7] & 0xc0) == 0x80 && (q[9] & 0xf0) == 0x20) || 3118c2ecf20Sopenharmony_ci ((q[7] & 0xc0) == 0xc0 && (q[9] & 0xf0) == 0x30)) { 3128c2ecf20Sopenharmony_ci ch = 0xba; 3138c2ecf20Sopenharmony_ci itv->search_pack_header = 1; 3148c2ecf20Sopenharmony_ci p = q + 9; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci continue; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci stuffing = q[13] & 7; 3198c2ecf20Sopenharmony_ci /* all stuffing bytes must be 0xff */ 3208c2ecf20Sopenharmony_ci for (i = 0; i < stuffing; i++) 3218c2ecf20Sopenharmony_ci if (q[14 + i] != 0xff) 3228c2ecf20Sopenharmony_ci break; 3238c2ecf20Sopenharmony_ci if (i == stuffing && (q[4] & 0xc4) == 0x44 && (q[12] & 3) == 3 && 3248c2ecf20Sopenharmony_ci q[14 + stuffing] == 0 && q[15 + stuffing] == 0 && 3258c2ecf20Sopenharmony_ci q[16 + stuffing] == 1) { 3268c2ecf20Sopenharmony_ci itv->search_pack_header = 0; 3278c2ecf20Sopenharmony_ci len = (char *)q - start; 3288c2ecf20Sopenharmony_ci ivtv_setup_sliced_vbi_buf(itv); 3298c2ecf20Sopenharmony_ci break; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) { 3348c2ecf20Sopenharmony_ci IVTV_DEBUG_WARN("copy %zd bytes to user failed for %s\n", len, s->name); 3358c2ecf20Sopenharmony_ci return -EFAULT; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci /*IVTV_INFO("copied %lld %d %d %d %d %d vbi %d\n", itv->mpg_data_received, len, ucount, 3388c2ecf20Sopenharmony_ci buf->readpos, buf->bytesused, buf->bytesused - buf->readpos - len, 3398c2ecf20Sopenharmony_ci buf == &itv->vbi.sliced_mpeg_buf); */ 3408c2ecf20Sopenharmony_ci buf->readpos += len; 3418c2ecf20Sopenharmony_ci if (s->type == IVTV_ENC_STREAM_TYPE_MPG && buf != &itv->vbi.sliced_mpeg_buf) 3428c2ecf20Sopenharmony_ci itv->mpg_data_received += len; 3438c2ecf20Sopenharmony_ci return len; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic ssize_t ivtv_read(struct ivtv_stream *s, char __user *ubuf, size_t tot_count, int non_block) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci struct ivtv *itv = s->itv; 3498c2ecf20Sopenharmony_ci size_t tot_written = 0; 3508c2ecf20Sopenharmony_ci int single_frame = 0; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci if (atomic_read(&itv->capturing) == 0 && s->fh == NULL) { 3538c2ecf20Sopenharmony_ci /* shouldn't happen */ 3548c2ecf20Sopenharmony_ci IVTV_DEBUG_WARN("Stream %s not initialized before read\n", s->name); 3558c2ecf20Sopenharmony_ci return -EIO; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci /* Each VBI buffer is one frame, the v4l2 API says that for VBI the frames should 3598c2ecf20Sopenharmony_ci arrive one-by-one, so make sure we never output more than one VBI frame at a time */ 3608c2ecf20Sopenharmony_ci if (s->type == IVTV_DEC_STREAM_TYPE_VBI || 3618c2ecf20Sopenharmony_ci (s->type == IVTV_ENC_STREAM_TYPE_VBI && !ivtv_raw_vbi(itv))) 3628c2ecf20Sopenharmony_ci single_frame = 1; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci for (;;) { 3658c2ecf20Sopenharmony_ci struct ivtv_buffer *buf; 3668c2ecf20Sopenharmony_ci int rc; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci buf = ivtv_get_buffer(s, non_block, &rc); 3698c2ecf20Sopenharmony_ci /* if there is no data available... */ 3708c2ecf20Sopenharmony_ci if (buf == NULL) { 3718c2ecf20Sopenharmony_ci /* if we got data, then return that regardless */ 3728c2ecf20Sopenharmony_ci if (tot_written) 3738c2ecf20Sopenharmony_ci break; 3748c2ecf20Sopenharmony_ci /* EOS condition */ 3758c2ecf20Sopenharmony_ci if (rc == 0) { 3768c2ecf20Sopenharmony_ci clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); 3778c2ecf20Sopenharmony_ci clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); 3788c2ecf20Sopenharmony_ci ivtv_release_stream(s); 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci /* set errno */ 3818c2ecf20Sopenharmony_ci return rc; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci rc = ivtv_copy_buf_to_user(s, buf, ubuf + tot_written, tot_count - tot_written); 3848c2ecf20Sopenharmony_ci if (buf != &itv->vbi.sliced_mpeg_buf) { 3858c2ecf20Sopenharmony_ci ivtv_enqueue(s, buf, (buf->readpos == buf->bytesused) ? &s->q_free : &s->q_io); 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci else if (buf->readpos == buf->bytesused) { 3888c2ecf20Sopenharmony_ci int idx = itv->vbi.inserted_frame % IVTV_VBI_FRAMES; 3898c2ecf20Sopenharmony_ci itv->vbi.sliced_mpeg_size[idx] = 0; 3908c2ecf20Sopenharmony_ci itv->vbi.inserted_frame++; 3918c2ecf20Sopenharmony_ci itv->vbi_data_inserted += buf->bytesused; 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci if (rc < 0) 3948c2ecf20Sopenharmony_ci return rc; 3958c2ecf20Sopenharmony_ci tot_written += rc; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (tot_written == tot_count || single_frame) 3988c2ecf20Sopenharmony_ci break; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci return tot_written; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic ssize_t ivtv_read_pos(struct ivtv_stream *s, char __user *ubuf, size_t count, 4048c2ecf20Sopenharmony_ci loff_t *pos, int non_block) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci ssize_t rc = count ? ivtv_read(s, ubuf, count, non_block) : 0; 4078c2ecf20Sopenharmony_ci struct ivtv *itv = s->itv; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc); 4108c2ecf20Sopenharmony_ci if (rc > 0) 4118c2ecf20Sopenharmony_ci *pos += rc; 4128c2ecf20Sopenharmony_ci return rc; 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ciint ivtv_start_capture(struct ivtv_open_id *id) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 4188c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[id->type]; 4198c2ecf20Sopenharmony_ci struct ivtv_stream *s_vbi; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (s->type == IVTV_ENC_STREAM_TYPE_RAD || 4228c2ecf20Sopenharmony_ci s->type == IVTV_DEC_STREAM_TYPE_MPG || 4238c2ecf20Sopenharmony_ci s->type == IVTV_DEC_STREAM_TYPE_YUV || 4248c2ecf20Sopenharmony_ci s->type == IVTV_DEC_STREAM_TYPE_VOUT) { 4258c2ecf20Sopenharmony_ci /* you cannot read from these stream types. */ 4268c2ecf20Sopenharmony_ci return -EINVAL; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci /* Try to claim this stream. */ 4308c2ecf20Sopenharmony_ci if (ivtv_claim_stream(id, s->type)) 4318c2ecf20Sopenharmony_ci return -EBUSY; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci /* This stream does not need to start capturing */ 4348c2ecf20Sopenharmony_ci if (s->type == IVTV_DEC_STREAM_TYPE_VBI) { 4358c2ecf20Sopenharmony_ci set_bit(IVTV_F_S_APPL_IO, &s->s_flags); 4368c2ecf20Sopenharmony_ci return 0; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci /* If capture is already in progress, then we also have to 4408c2ecf20Sopenharmony_ci do nothing extra. */ 4418c2ecf20Sopenharmony_ci if (test_bit(IVTV_F_S_STREAMOFF, &s->s_flags) || test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags)) { 4428c2ecf20Sopenharmony_ci set_bit(IVTV_F_S_APPL_IO, &s->s_flags); 4438c2ecf20Sopenharmony_ci return 0; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci /* Start VBI capture if required */ 4478c2ecf20Sopenharmony_ci s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; 4488c2ecf20Sopenharmony_ci if (s->type == IVTV_ENC_STREAM_TYPE_MPG && 4498c2ecf20Sopenharmony_ci test_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags) && 4508c2ecf20Sopenharmony_ci !test_and_set_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags)) { 4518c2ecf20Sopenharmony_ci /* Note: the IVTV_ENC_STREAM_TYPE_VBI is claimed 4528c2ecf20Sopenharmony_ci automatically when the MPG stream is claimed. 4538c2ecf20Sopenharmony_ci We only need to start the VBI capturing. */ 4548c2ecf20Sopenharmony_ci if (ivtv_start_v4l2_encode_stream(s_vbi)) { 4558c2ecf20Sopenharmony_ci IVTV_DEBUG_WARN("VBI capture start failed\n"); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* Failure, clean up and return an error */ 4588c2ecf20Sopenharmony_ci clear_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags); 4598c2ecf20Sopenharmony_ci clear_bit(IVTV_F_S_STREAMING, &s->s_flags); 4608c2ecf20Sopenharmony_ci /* also releases the associated VBI stream */ 4618c2ecf20Sopenharmony_ci ivtv_release_stream(s); 4628c2ecf20Sopenharmony_ci return -EIO; 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("VBI insertion started\n"); 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci /* Tell the card to start capturing */ 4688c2ecf20Sopenharmony_ci if (!ivtv_start_v4l2_encode_stream(s)) { 4698c2ecf20Sopenharmony_ci /* We're done */ 4708c2ecf20Sopenharmony_ci set_bit(IVTV_F_S_APPL_IO, &s->s_flags); 4718c2ecf20Sopenharmony_ci /* Resume a possibly paused encoder */ 4728c2ecf20Sopenharmony_ci if (test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) 4738c2ecf20Sopenharmony_ci ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1); 4748c2ecf20Sopenharmony_ci return 0; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci /* failure, clean up */ 4788c2ecf20Sopenharmony_ci IVTV_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci /* Note: the IVTV_ENC_STREAM_TYPE_VBI is released 4818c2ecf20Sopenharmony_ci automatically when the MPG stream is released. 4828c2ecf20Sopenharmony_ci We only need to stop the VBI capturing. */ 4838c2ecf20Sopenharmony_ci if (s->type == IVTV_ENC_STREAM_TYPE_MPG && 4848c2ecf20Sopenharmony_ci test_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags)) { 4858c2ecf20Sopenharmony_ci ivtv_stop_v4l2_encode_stream(s_vbi, 0); 4868c2ecf20Sopenharmony_ci clear_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags); 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci clear_bit(IVTV_F_S_STREAMING, &s->s_flags); 4898c2ecf20Sopenharmony_ci ivtv_release_stream(s); 4908c2ecf20Sopenharmony_ci return -EIO; 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cissize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_t * pos) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(filp->private_data); 4968c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 4978c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[id->type]; 4988c2ecf20Sopenharmony_ci ssize_t rc; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&itv->serialize_lock)) 5038c2ecf20Sopenharmony_ci return -ERESTARTSYS; 5048c2ecf20Sopenharmony_ci rc = ivtv_start_capture(id); 5058c2ecf20Sopenharmony_ci if (!rc) 5068c2ecf20Sopenharmony_ci rc = ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); 5078c2ecf20Sopenharmony_ci mutex_unlock(&itv->serialize_lock); 5088c2ecf20Sopenharmony_ci return rc; 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ciint ivtv_start_decoding(struct ivtv_open_id *id, int speed) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 5148c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[id->type]; 5158c2ecf20Sopenharmony_ci int rc; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci if (atomic_read(&itv->decoding) == 0) { 5188c2ecf20Sopenharmony_ci if (ivtv_claim_stream(id, s->type)) { 5198c2ecf20Sopenharmony_ci /* someone else is using this stream already */ 5208c2ecf20Sopenharmony_ci IVTV_DEBUG_WARN("start decode, stream already claimed\n"); 5218c2ecf20Sopenharmony_ci return -EBUSY; 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci rc = ivtv_start_v4l2_decode_stream(s, 0); 5248c2ecf20Sopenharmony_ci if (rc < 0) { 5258c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 5268c2ecf20Sopenharmony_ci rc = ivtv_start_v4l2_decode_stream(s, 0); 5278c2ecf20Sopenharmony_ci if (rc < 0) 5288c2ecf20Sopenharmony_ci return rc; 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci if (s->type == IVTV_DEC_STREAM_TYPE_MPG) 5328c2ecf20Sopenharmony_ci return ivtv_set_speed(itv, speed); 5338c2ecf20Sopenharmony_ci return 0; 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic ssize_t ivtv_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(filp->private_data); 5398c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 5408c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[id->type]; 5418c2ecf20Sopenharmony_ci struct yuv_playback_info *yi = &itv->yuv_info; 5428c2ecf20Sopenharmony_ci struct ivtv_buffer *buf; 5438c2ecf20Sopenharmony_ci struct ivtv_queue q; 5448c2ecf20Sopenharmony_ci int bytes_written = 0; 5458c2ecf20Sopenharmony_ci int mode; 5468c2ecf20Sopenharmony_ci int rc; 5478c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_FILE("write %zd bytes to %s\n", count, s->name); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci if (s->type != IVTV_DEC_STREAM_TYPE_MPG && 5528c2ecf20Sopenharmony_ci s->type != IVTV_DEC_STREAM_TYPE_YUV && 5538c2ecf20Sopenharmony_ci s->type != IVTV_DEC_STREAM_TYPE_VOUT) 5548c2ecf20Sopenharmony_ci /* not decoder streams */ 5558c2ecf20Sopenharmony_ci return -EINVAL; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci /* Try to claim this stream */ 5588c2ecf20Sopenharmony_ci if (ivtv_claim_stream(id, s->type)) 5598c2ecf20Sopenharmony_ci return -EBUSY; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci /* This stream does not need to start any decoding */ 5628c2ecf20Sopenharmony_ci if (s->type == IVTV_DEC_STREAM_TYPE_VOUT) { 5638c2ecf20Sopenharmony_ci int elems = count / sizeof(struct v4l2_sliced_vbi_data); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci set_bit(IVTV_F_S_APPL_IO, &s->s_flags); 5668c2ecf20Sopenharmony_ci return ivtv_write_vbi_from_user(itv, 5678c2ecf20Sopenharmony_ci (const struct v4l2_sliced_vbi_data __user *)user_buf, elems); 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci mode = s->type == IVTV_DEC_STREAM_TYPE_MPG ? OUT_MPG : OUT_YUV; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci if (ivtv_set_output_mode(itv, mode) != mode) { 5738c2ecf20Sopenharmony_ci ivtv_release_stream(s); 5748c2ecf20Sopenharmony_ci return -EBUSY; 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci ivtv_queue_init(&q); 5778c2ecf20Sopenharmony_ci set_bit(IVTV_F_S_APPL_IO, &s->s_flags); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci /* Start decoder (returns 0 if already started) */ 5808c2ecf20Sopenharmony_ci rc = ivtv_start_decoding(id, itv->speed); 5818c2ecf20Sopenharmony_ci if (rc) { 5828c2ecf20Sopenharmony_ci IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci /* failure, clean up */ 5858c2ecf20Sopenharmony_ci clear_bit(IVTV_F_S_STREAMING, &s->s_flags); 5868c2ecf20Sopenharmony_ci clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); 5878c2ecf20Sopenharmony_ci return rc; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ciretry: 5918c2ecf20Sopenharmony_ci /* If possible, just DMA the entire frame - Check the data transfer size 5928c2ecf20Sopenharmony_ci since we may get here before the stream has been fully set-up */ 5938c2ecf20Sopenharmony_ci if (mode == OUT_YUV && s->q_full.length == 0 && itv->dma_data_req_size) { 5948c2ecf20Sopenharmony_ci while (count >= itv->dma_data_req_size) { 5958c2ecf20Sopenharmony_ci rc = ivtv_yuv_udma_stream_frame(itv, (void __user *)user_buf); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci if (rc < 0) 5988c2ecf20Sopenharmony_ci return rc; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci bytes_written += itv->dma_data_req_size; 6018c2ecf20Sopenharmony_ci user_buf += itv->dma_data_req_size; 6028c2ecf20Sopenharmony_ci count -= itv->dma_data_req_size; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci if (count == 0) { 6058c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused); 6068c2ecf20Sopenharmony_ci return bytes_written; 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci for (;;) { 6118c2ecf20Sopenharmony_ci /* Gather buffers */ 6128c2ecf20Sopenharmony_ci while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_io))) 6138c2ecf20Sopenharmony_ci ivtv_enqueue(s, buf, &q); 6148c2ecf20Sopenharmony_ci while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_free))) { 6158c2ecf20Sopenharmony_ci ivtv_enqueue(s, buf, &q); 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci if (q.buffers) 6188c2ecf20Sopenharmony_ci break; 6198c2ecf20Sopenharmony_ci if (filp->f_flags & O_NONBLOCK) 6208c2ecf20Sopenharmony_ci return -EAGAIN; 6218c2ecf20Sopenharmony_ci mutex_unlock(&itv->serialize_lock); 6228c2ecf20Sopenharmony_ci prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); 6238c2ecf20Sopenharmony_ci /* New buffers might have become free before we were added to the waitqueue */ 6248c2ecf20Sopenharmony_ci if (!s->q_free.buffers) 6258c2ecf20Sopenharmony_ci schedule(); 6268c2ecf20Sopenharmony_ci finish_wait(&s->waitq, &wait); 6278c2ecf20Sopenharmony_ci mutex_lock(&itv->serialize_lock); 6288c2ecf20Sopenharmony_ci if (signal_pending(current)) { 6298c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("User stopped %s\n", s->name); 6308c2ecf20Sopenharmony_ci return -EINTR; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci /* copy user data into buffers */ 6358c2ecf20Sopenharmony_ci while ((buf = ivtv_dequeue(s, &q))) { 6368c2ecf20Sopenharmony_ci /* yuv is a pain. Don't copy more data than needed for a single 6378c2ecf20Sopenharmony_ci frame, otherwise we lose sync with the incoming stream */ 6388c2ecf20Sopenharmony_ci if (s->type == IVTV_DEC_STREAM_TYPE_YUV && 6398c2ecf20Sopenharmony_ci yi->stream_size + count > itv->dma_data_req_size) 6408c2ecf20Sopenharmony_ci rc = ivtv_buf_copy_from_user(s, buf, user_buf, 6418c2ecf20Sopenharmony_ci itv->dma_data_req_size - yi->stream_size); 6428c2ecf20Sopenharmony_ci else 6438c2ecf20Sopenharmony_ci rc = ivtv_buf_copy_from_user(s, buf, user_buf, count); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci /* Make sure we really got all the user data */ 6468c2ecf20Sopenharmony_ci if (rc < 0) { 6478c2ecf20Sopenharmony_ci ivtv_queue_move(s, &q, NULL, &s->q_free, 0); 6488c2ecf20Sopenharmony_ci return rc; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci user_buf += rc; 6518c2ecf20Sopenharmony_ci count -= rc; 6528c2ecf20Sopenharmony_ci bytes_written += rc; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { 6558c2ecf20Sopenharmony_ci yi->stream_size += rc; 6568c2ecf20Sopenharmony_ci /* If we have a complete yuv frame, break loop now */ 6578c2ecf20Sopenharmony_ci if (yi->stream_size == itv->dma_data_req_size) { 6588c2ecf20Sopenharmony_ci ivtv_enqueue(s, buf, &s->q_full); 6598c2ecf20Sopenharmony_ci yi->stream_size = 0; 6608c2ecf20Sopenharmony_ci break; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci if (buf->bytesused != s->buf_size) { 6658c2ecf20Sopenharmony_ci /* incomplete, leave in q_io for next time */ 6668c2ecf20Sopenharmony_ci ivtv_enqueue(s, buf, &s->q_io); 6678c2ecf20Sopenharmony_ci break; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci /* Byteswap MPEG buffer */ 6708c2ecf20Sopenharmony_ci if (s->type == IVTV_DEC_STREAM_TYPE_MPG) 6718c2ecf20Sopenharmony_ci ivtv_buf_swap(buf); 6728c2ecf20Sopenharmony_ci ivtv_enqueue(s, buf, &s->q_full); 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci if (test_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags)) { 6768c2ecf20Sopenharmony_ci if (s->q_full.length >= itv->dma_data_req_size) { 6778c2ecf20Sopenharmony_ci int got_sig; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (mode == OUT_YUV) 6808c2ecf20Sopenharmony_ci ivtv_yuv_setup_stream_frame(itv); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci mutex_unlock(&itv->serialize_lock); 6838c2ecf20Sopenharmony_ci prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); 6848c2ecf20Sopenharmony_ci while (!(got_sig = signal_pending(current)) && 6858c2ecf20Sopenharmony_ci test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) { 6868c2ecf20Sopenharmony_ci schedule(); 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci finish_wait(&itv->dma_waitq, &wait); 6898c2ecf20Sopenharmony_ci mutex_lock(&itv->serialize_lock); 6908c2ecf20Sopenharmony_ci if (got_sig) { 6918c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("User interrupted %s\n", s->name); 6928c2ecf20Sopenharmony_ci return -EINTR; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); 6968c2ecf20Sopenharmony_ci ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size); 6978c2ecf20Sopenharmony_ci ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 1); 6988c2ecf20Sopenharmony_ci } 6998c2ecf20Sopenharmony_ci } 7008c2ecf20Sopenharmony_ci /* more user data is available, wait until buffers become free 7018c2ecf20Sopenharmony_ci to transfer the rest. */ 7028c2ecf20Sopenharmony_ci if (count && !(filp->f_flags & O_NONBLOCK)) 7038c2ecf20Sopenharmony_ci goto retry; 7048c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused); 7058c2ecf20Sopenharmony_ci return bytes_written; 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cissize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(filp->private_data); 7118c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 7128c2ecf20Sopenharmony_ci ssize_t res; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&itv->serialize_lock)) 7158c2ecf20Sopenharmony_ci return -ERESTARTSYS; 7168c2ecf20Sopenharmony_ci res = ivtv_write(filp, user_buf, count, pos); 7178c2ecf20Sopenharmony_ci mutex_unlock(&itv->serialize_lock); 7188c2ecf20Sopenharmony_ci return res; 7198c2ecf20Sopenharmony_ci} 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci__poll_t ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait) 7228c2ecf20Sopenharmony_ci{ 7238c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(filp->private_data); 7248c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 7258c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[id->type]; 7268c2ecf20Sopenharmony_ci __poll_t res = 0; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci /* add stream's waitq to the poll list */ 7298c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_FILE("Decoder poll\n"); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci /* If there are subscribed events, then only use the new event 7328c2ecf20Sopenharmony_ci API instead of the old video.h based API. */ 7338c2ecf20Sopenharmony_ci if (!list_empty(&id->fh.subscribed)) { 7348c2ecf20Sopenharmony_ci poll_wait(filp, &id->fh.wait, wait); 7358c2ecf20Sopenharmony_ci /* Turn off the old-style vsync events */ 7368c2ecf20Sopenharmony_ci clear_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags); 7378c2ecf20Sopenharmony_ci if (v4l2_event_pending(&id->fh)) 7388c2ecf20Sopenharmony_ci res = EPOLLPRI; 7398c2ecf20Sopenharmony_ci } else { 7408c2ecf20Sopenharmony_ci /* This is the old-style API which is here only for backwards 7418c2ecf20Sopenharmony_ci compatibility. */ 7428c2ecf20Sopenharmony_ci poll_wait(filp, &s->waitq, wait); 7438c2ecf20Sopenharmony_ci set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags); 7448c2ecf20Sopenharmony_ci if (test_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags) || 7458c2ecf20Sopenharmony_ci test_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags)) 7468c2ecf20Sopenharmony_ci res = EPOLLPRI; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci /* Allow write if buffers are available for writing */ 7508c2ecf20Sopenharmony_ci if (s->q_free.buffers) 7518c2ecf20Sopenharmony_ci res |= EPOLLOUT | EPOLLWRNORM; 7528c2ecf20Sopenharmony_ci return res; 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci__poll_t ivtv_v4l2_enc_poll(struct file *filp, poll_table *wait) 7568c2ecf20Sopenharmony_ci{ 7578c2ecf20Sopenharmony_ci __poll_t req_events = poll_requested_events(wait); 7588c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(filp->private_data); 7598c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 7608c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[id->type]; 7618c2ecf20Sopenharmony_ci int eof = test_bit(IVTV_F_S_STREAMOFF, &s->s_flags); 7628c2ecf20Sopenharmony_ci __poll_t res = 0; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci /* Start a capture if there is none */ 7658c2ecf20Sopenharmony_ci if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags) && 7668c2ecf20Sopenharmony_ci s->type != IVTV_ENC_STREAM_TYPE_RAD && 7678c2ecf20Sopenharmony_ci (req_events & (EPOLLIN | EPOLLRDNORM))) { 7688c2ecf20Sopenharmony_ci int rc; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci mutex_lock(&itv->serialize_lock); 7718c2ecf20Sopenharmony_ci rc = ivtv_start_capture(id); 7728c2ecf20Sopenharmony_ci mutex_unlock(&itv->serialize_lock); 7738c2ecf20Sopenharmony_ci if (rc) { 7748c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n", 7758c2ecf20Sopenharmony_ci s->name, rc); 7768c2ecf20Sopenharmony_ci return EPOLLERR; 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci IVTV_DEBUG_FILE("Encoder poll started capture\n"); 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci /* add stream's waitq to the poll list */ 7828c2ecf20Sopenharmony_ci IVTV_DEBUG_HI_FILE("Encoder poll\n"); 7838c2ecf20Sopenharmony_ci poll_wait(filp, &s->waitq, wait); 7848c2ecf20Sopenharmony_ci if (v4l2_event_pending(&id->fh)) 7858c2ecf20Sopenharmony_ci res |= EPOLLPRI; 7868c2ecf20Sopenharmony_ci else 7878c2ecf20Sopenharmony_ci poll_wait(filp, &id->fh.wait, wait); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci if (s->q_full.length || s->q_io.length) 7908c2ecf20Sopenharmony_ci return res | EPOLLIN | EPOLLRDNORM; 7918c2ecf20Sopenharmony_ci if (eof) 7928c2ecf20Sopenharmony_ci return res | EPOLLHUP; 7938c2ecf20Sopenharmony_ci return res; 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_civoid ivtv_stop_capture(struct ivtv_open_id *id, int gop_end) 7978c2ecf20Sopenharmony_ci{ 7988c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 7998c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[id->type]; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci IVTV_DEBUG_FILE("close() of %s\n", s->name); 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci /* 'Unclaim' this stream */ 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci /* Stop capturing */ 8068c2ecf20Sopenharmony_ci if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { 8078c2ecf20Sopenharmony_ci struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("close stopping capture\n"); 8108c2ecf20Sopenharmony_ci /* Special case: a running VBI capture for VBI insertion 8118c2ecf20Sopenharmony_ci in the mpeg stream. Need to stop that too. */ 8128c2ecf20Sopenharmony_ci if (id->type == IVTV_ENC_STREAM_TYPE_MPG && 8138c2ecf20Sopenharmony_ci test_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags) && 8148c2ecf20Sopenharmony_ci !test_bit(IVTV_F_S_APPL_IO, &s_vbi->s_flags)) { 8158c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("close stopping embedded VBI capture\n"); 8168c2ecf20Sopenharmony_ci ivtv_stop_v4l2_encode_stream(s_vbi, 0); 8178c2ecf20Sopenharmony_ci } 8188c2ecf20Sopenharmony_ci if ((id->type == IVTV_DEC_STREAM_TYPE_VBI || 8198c2ecf20Sopenharmony_ci id->type == IVTV_ENC_STREAM_TYPE_VBI) && 8208c2ecf20Sopenharmony_ci test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) { 8218c2ecf20Sopenharmony_ci /* Also used internally, don't stop capturing */ 8228c2ecf20Sopenharmony_ci s->fh = NULL; 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci else { 8258c2ecf20Sopenharmony_ci ivtv_stop_v4l2_encode_stream(s, gop_end); 8268c2ecf20Sopenharmony_ci } 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci if (!gop_end) { 8298c2ecf20Sopenharmony_ci clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); 8308c2ecf20Sopenharmony_ci clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); 8318c2ecf20Sopenharmony_ci ivtv_release_stream(s); 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci} 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_cistatic void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) 8368c2ecf20Sopenharmony_ci{ 8378c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 8388c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[id->type]; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci IVTV_DEBUG_FILE("close() of %s\n", s->name); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci if (id->type == IVTV_DEC_STREAM_TYPE_YUV && 8438c2ecf20Sopenharmony_ci test_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags)) { 8448c2ecf20Sopenharmony_ci /* Restore registers we've changed & clean up any mess */ 8458c2ecf20Sopenharmony_ci ivtv_yuv_close(itv); 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci /* Stop decoding */ 8498c2ecf20Sopenharmony_ci if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { 8508c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("close stopping decode\n"); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci ivtv_stop_v4l2_decode_stream(s, flags, pts); 8538c2ecf20Sopenharmony_ci itv->output_mode = OUT_NONE; 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); 8568c2ecf20Sopenharmony_ci clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci if (itv->output_mode == OUT_UDMA_YUV && id->yuv_frames) 8598c2ecf20Sopenharmony_ci itv->output_mode = OUT_NONE; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci itv->speed = 0; 8628c2ecf20Sopenharmony_ci clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags); 8638c2ecf20Sopenharmony_ci ivtv_release_stream(s); 8648c2ecf20Sopenharmony_ci} 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ciint ivtv_v4l2_close(struct file *filp) 8678c2ecf20Sopenharmony_ci{ 8688c2ecf20Sopenharmony_ci struct v4l2_fh *fh = filp->private_data; 8698c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(fh); 8708c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 8718c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[id->type]; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci IVTV_DEBUG_FILE("close %s\n", s->name); 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci mutex_lock(&itv->serialize_lock); 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci /* Stop radio */ 8788c2ecf20Sopenharmony_ci if (id->type == IVTV_ENC_STREAM_TYPE_RAD && 8798c2ecf20Sopenharmony_ci v4l2_fh_is_singular_file(filp)) { 8808c2ecf20Sopenharmony_ci /* Closing radio device, return to TV mode */ 8818c2ecf20Sopenharmony_ci ivtv_mute(itv); 8828c2ecf20Sopenharmony_ci /* Mark that the radio is no longer in use */ 8838c2ecf20Sopenharmony_ci clear_bit(IVTV_F_I_RADIO_USER, &itv->i_flags); 8848c2ecf20Sopenharmony_ci /* Switch tuner to TV */ 8858c2ecf20Sopenharmony_ci ivtv_call_all(itv, video, s_std, itv->std); 8868c2ecf20Sopenharmony_ci /* Select correct audio input (i.e. TV tuner or Line in) */ 8878c2ecf20Sopenharmony_ci ivtv_audio_set_io(itv); 8888c2ecf20Sopenharmony_ci if (itv->hw_flags & IVTV_HW_SAA711X) { 8898c2ecf20Sopenharmony_ci ivtv_call_hw(itv, IVTV_HW_SAA711X, video, s_crystal_freq, 8908c2ecf20Sopenharmony_ci SAA7115_FREQ_32_11_MHZ, 0); 8918c2ecf20Sopenharmony_ci } 8928c2ecf20Sopenharmony_ci if (atomic_read(&itv->capturing) > 0) { 8938c2ecf20Sopenharmony_ci /* Undo video mute */ 8948c2ecf20Sopenharmony_ci ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1, 8958c2ecf20Sopenharmony_ci v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute) | 8968c2ecf20Sopenharmony_ci (v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute_yuv) << 8)); 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci /* Done! Unmute and continue. */ 8998c2ecf20Sopenharmony_ci ivtv_unmute(itv); 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci v4l2_fh_del(fh); 9038c2ecf20Sopenharmony_ci v4l2_fh_exit(fh); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci /* Easy case first: this stream was never claimed by us */ 9068c2ecf20Sopenharmony_ci if (s->fh != &id->fh) 9078c2ecf20Sopenharmony_ci goto close_done; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci /* 'Unclaim' this stream */ 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) { 9128c2ecf20Sopenharmony_ci struct ivtv_stream *s_vout = &itv->streams[IVTV_DEC_STREAM_TYPE_VOUT]; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci ivtv_stop_decoding(id, V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY, 0); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci /* If all output streams are closed, and if the user doesn't have 9178c2ecf20Sopenharmony_ci IVTV_DEC_STREAM_TYPE_VOUT open, then disable CC on TV-out. */ 9188c2ecf20Sopenharmony_ci if (itv->output_mode == OUT_NONE && !test_bit(IVTV_F_S_APPL_IO, &s_vout->s_flags)) { 9198c2ecf20Sopenharmony_ci /* disable CC on TV-out */ 9208c2ecf20Sopenharmony_ci ivtv_disable_cc(itv); 9218c2ecf20Sopenharmony_ci } 9228c2ecf20Sopenharmony_ci } else { 9238c2ecf20Sopenharmony_ci ivtv_stop_capture(id, 0); 9248c2ecf20Sopenharmony_ci } 9258c2ecf20Sopenharmony_ciclose_done: 9268c2ecf20Sopenharmony_ci kfree(id); 9278c2ecf20Sopenharmony_ci mutex_unlock(&itv->serialize_lock); 9288c2ecf20Sopenharmony_ci return 0; 9298c2ecf20Sopenharmony_ci} 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_cistatic int ivtv_open(struct file *filp) 9328c2ecf20Sopenharmony_ci{ 9338c2ecf20Sopenharmony_ci struct video_device *vdev = video_devdata(filp); 9348c2ecf20Sopenharmony_ci struct ivtv_stream *s = video_get_drvdata(vdev); 9358c2ecf20Sopenharmony_ci struct ivtv *itv = s->itv; 9368c2ecf20Sopenharmony_ci struct ivtv_open_id *item; 9378c2ecf20Sopenharmony_ci int res = 0; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci IVTV_DEBUG_FILE("open %s\n", s->name); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci if (ivtv_init_on_first_open(itv)) { 9428c2ecf20Sopenharmony_ci IVTV_ERR("Failed to initialize on device %s\n", 9438c2ecf20Sopenharmony_ci video_device_node_name(vdev)); 9448c2ecf20Sopenharmony_ci return -ENXIO; 9458c2ecf20Sopenharmony_ci } 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG 9488c2ecf20Sopenharmony_ci /* Unless ivtv_fw_debug is set, error out if firmware dead. */ 9498c2ecf20Sopenharmony_ci if (ivtv_fw_debug) { 9508c2ecf20Sopenharmony_ci IVTV_WARN("Opening %s with dead firmware lockout disabled\n", 9518c2ecf20Sopenharmony_ci video_device_node_name(vdev)); 9528c2ecf20Sopenharmony_ci IVTV_WARN("Selected firmware errors will be ignored\n"); 9538c2ecf20Sopenharmony_ci } else { 9548c2ecf20Sopenharmony_ci#else 9558c2ecf20Sopenharmony_ci if (1) { 9568c2ecf20Sopenharmony_ci#endif 9578c2ecf20Sopenharmony_ci res = ivtv_firmware_check(itv, "ivtv_serialized_open"); 9588c2ecf20Sopenharmony_ci if (res == -EAGAIN) 9598c2ecf20Sopenharmony_ci res = ivtv_firmware_check(itv, "ivtv_serialized_open"); 9608c2ecf20Sopenharmony_ci if (res < 0) 9618c2ecf20Sopenharmony_ci return -EIO; 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci if (s->type == IVTV_DEC_STREAM_TYPE_MPG && 9658c2ecf20Sopenharmony_ci test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags)) 9668c2ecf20Sopenharmony_ci return -EBUSY; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci if (s->type == IVTV_DEC_STREAM_TYPE_YUV && 9698c2ecf20Sopenharmony_ci test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_MPG].s_flags)) 9708c2ecf20Sopenharmony_ci return -EBUSY; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { 9738c2ecf20Sopenharmony_ci if (read_reg(0x82c) == 0) { 9748c2ecf20Sopenharmony_ci IVTV_ERR("Tried to open YUV output device but need to send data to mpeg decoder before it can be used\n"); 9758c2ecf20Sopenharmony_ci /* return -ENODEV; */ 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci ivtv_udma_alloc(itv); 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci /* Allocate memory */ 9818c2ecf20Sopenharmony_ci item = kzalloc(sizeof(struct ivtv_open_id), GFP_KERNEL); 9828c2ecf20Sopenharmony_ci if (NULL == item) { 9838c2ecf20Sopenharmony_ci IVTV_DEBUG_WARN("nomem on v4l2 open\n"); 9848c2ecf20Sopenharmony_ci return -ENOMEM; 9858c2ecf20Sopenharmony_ci } 9868c2ecf20Sopenharmony_ci v4l2_fh_init(&item->fh, &s->vdev); 9878c2ecf20Sopenharmony_ci item->itv = itv; 9888c2ecf20Sopenharmony_ci item->type = s->type; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci filp->private_data = &item->fh; 9918c2ecf20Sopenharmony_ci v4l2_fh_add(&item->fh); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci if (item->type == IVTV_ENC_STREAM_TYPE_RAD && 9948c2ecf20Sopenharmony_ci v4l2_fh_is_singular_file(filp)) { 9958c2ecf20Sopenharmony_ci if (!test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { 9968c2ecf20Sopenharmony_ci if (atomic_read(&itv->capturing) > 0) { 9978c2ecf20Sopenharmony_ci /* switching to radio while capture is 9988c2ecf20Sopenharmony_ci in progress is not polite */ 9998c2ecf20Sopenharmony_ci v4l2_fh_del(&item->fh); 10008c2ecf20Sopenharmony_ci v4l2_fh_exit(&item->fh); 10018c2ecf20Sopenharmony_ci kfree(item); 10028c2ecf20Sopenharmony_ci return -EBUSY; 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci } 10058c2ecf20Sopenharmony_ci /* Mark that the radio is being used. */ 10068c2ecf20Sopenharmony_ci set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags); 10078c2ecf20Sopenharmony_ci /* We have the radio */ 10088c2ecf20Sopenharmony_ci ivtv_mute(itv); 10098c2ecf20Sopenharmony_ci /* Switch tuner to radio */ 10108c2ecf20Sopenharmony_ci ivtv_call_all(itv, tuner, s_radio); 10118c2ecf20Sopenharmony_ci /* Select the correct audio input (i.e. radio tuner) */ 10128c2ecf20Sopenharmony_ci ivtv_audio_set_io(itv); 10138c2ecf20Sopenharmony_ci if (itv->hw_flags & IVTV_HW_SAA711X) { 10148c2ecf20Sopenharmony_ci ivtv_call_hw(itv, IVTV_HW_SAA711X, video, s_crystal_freq, 10158c2ecf20Sopenharmony_ci SAA7115_FREQ_32_11_MHZ, SAA7115_FREQ_FL_APLL); 10168c2ecf20Sopenharmony_ci } 10178c2ecf20Sopenharmony_ci /* Done! Unmute and continue. */ 10188c2ecf20Sopenharmony_ci ivtv_unmute(itv); 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci /* YUV or MPG Decoding Mode? */ 10228c2ecf20Sopenharmony_ci if (s->type == IVTV_DEC_STREAM_TYPE_MPG) { 10238c2ecf20Sopenharmony_ci clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); 10248c2ecf20Sopenharmony_ci } else if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { 10258c2ecf20Sopenharmony_ci set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); 10268c2ecf20Sopenharmony_ci /* For yuv, we need to know the dma size before we start */ 10278c2ecf20Sopenharmony_ci itv->dma_data_req_size = 10288c2ecf20Sopenharmony_ci 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31); 10298c2ecf20Sopenharmony_ci itv->yuv_info.stream_size = 0; 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci return 0; 10328c2ecf20Sopenharmony_ci} 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ciint ivtv_v4l2_open(struct file *filp) 10358c2ecf20Sopenharmony_ci{ 10368c2ecf20Sopenharmony_ci struct video_device *vdev = video_devdata(filp); 10378c2ecf20Sopenharmony_ci int res; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(vdev->lock)) 10408c2ecf20Sopenharmony_ci return -ERESTARTSYS; 10418c2ecf20Sopenharmony_ci res = ivtv_open(filp); 10428c2ecf20Sopenharmony_ci mutex_unlock(vdev->lock); 10438c2ecf20Sopenharmony_ci return res; 10448c2ecf20Sopenharmony_ci} 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_civoid ivtv_mute(struct ivtv *itv) 10478c2ecf20Sopenharmony_ci{ 10488c2ecf20Sopenharmony_ci if (atomic_read(&itv->capturing)) 10498c2ecf20Sopenharmony_ci ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 1); 10508c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("Mute\n"); 10518c2ecf20Sopenharmony_ci} 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_civoid ivtv_unmute(struct ivtv *itv) 10548c2ecf20Sopenharmony_ci{ 10558c2ecf20Sopenharmony_ci if (atomic_read(&itv->capturing)) { 10568c2ecf20Sopenharmony_ci ivtv_msleep_timeout(100, 0); 10578c2ecf20Sopenharmony_ci ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12); 10588c2ecf20Sopenharmony_ci ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0); 10598c2ecf20Sopenharmony_ci } 10608c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("Unmute\n"); 10618c2ecf20Sopenharmony_ci} 1062