18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci ioctl system call 48c2ecf20Sopenharmony_ci Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> 58c2ecf20Sopenharmony_ci Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "ivtv-driver.h" 108c2ecf20Sopenharmony_ci#include "ivtv-version.h" 118c2ecf20Sopenharmony_ci#include "ivtv-mailbox.h" 128c2ecf20Sopenharmony_ci#include "ivtv-i2c.h" 138c2ecf20Sopenharmony_ci#include "ivtv-queue.h" 148c2ecf20Sopenharmony_ci#include "ivtv-fileops.h" 158c2ecf20Sopenharmony_ci#include "ivtv-vbi.h" 168c2ecf20Sopenharmony_ci#include "ivtv-routing.h" 178c2ecf20Sopenharmony_ci#include "ivtv-streams.h" 188c2ecf20Sopenharmony_ci#include "ivtv-yuv.h" 198c2ecf20Sopenharmony_ci#include "ivtv-ioctl.h" 208c2ecf20Sopenharmony_ci#include "ivtv-gpio.h" 218c2ecf20Sopenharmony_ci#include "ivtv-controls.h" 228c2ecf20Sopenharmony_ci#include "ivtv-cards.h" 238c2ecf20Sopenharmony_ci#include <media/i2c/saa7127.h> 248c2ecf20Sopenharmony_ci#include <media/tveeprom.h> 258c2ecf20Sopenharmony_ci#include <media/v4l2-event.h> 268c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS 278c2ecf20Sopenharmony_ci#include <linux/compat.h> 288c2ecf20Sopenharmony_ci#include <linux/dvb/audio.h> 298c2ecf20Sopenharmony_ci#include <linux/dvb/video.h> 308c2ecf20Sopenharmony_ci#endif 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ciu16 ivtv_service2vbi(int type) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci switch (type) { 358c2ecf20Sopenharmony_ci case V4L2_SLICED_TELETEXT_B: 368c2ecf20Sopenharmony_ci return IVTV_SLICED_TYPE_TELETEXT_B; 378c2ecf20Sopenharmony_ci case V4L2_SLICED_CAPTION_525: 388c2ecf20Sopenharmony_ci return IVTV_SLICED_TYPE_CAPTION_525; 398c2ecf20Sopenharmony_ci case V4L2_SLICED_WSS_625: 408c2ecf20Sopenharmony_ci return IVTV_SLICED_TYPE_WSS_625; 418c2ecf20Sopenharmony_ci case V4L2_SLICED_VPS: 428c2ecf20Sopenharmony_ci return IVTV_SLICED_TYPE_VPS; 438c2ecf20Sopenharmony_ci default: 448c2ecf20Sopenharmony_ci return 0; 458c2ecf20Sopenharmony_ci } 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic int valid_service_line(int field, int line, int is_pal) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci return (is_pal && line >= 6 && (line != 23 || field == 0)) || 518c2ecf20Sopenharmony_ci (!is_pal && line >= 10 && line < 22); 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic u16 select_service_from_set(int field, int line, u16 set, int is_pal) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525); 578c2ecf20Sopenharmony_ci int i; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci set = set & valid_set; 608c2ecf20Sopenharmony_ci if (set == 0 || !valid_service_line(field, line, is_pal)) { 618c2ecf20Sopenharmony_ci return 0; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci if (!is_pal) { 648c2ecf20Sopenharmony_ci if (line == 21 && (set & V4L2_SLICED_CAPTION_525)) 658c2ecf20Sopenharmony_ci return V4L2_SLICED_CAPTION_525; 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci else { 688c2ecf20Sopenharmony_ci if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS)) 698c2ecf20Sopenharmony_ci return V4L2_SLICED_VPS; 708c2ecf20Sopenharmony_ci if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625)) 718c2ecf20Sopenharmony_ci return V4L2_SLICED_WSS_625; 728c2ecf20Sopenharmony_ci if (line == 23) 738c2ecf20Sopenharmony_ci return 0; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci for (i = 0; i < 32; i++) { 768c2ecf20Sopenharmony_ci if (BIT(i) & set) 778c2ecf20Sopenharmony_ci return BIT(i); 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci return 0; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_civoid ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci u16 set = fmt->service_set; 858c2ecf20Sopenharmony_ci int f, l; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci fmt->service_set = 0; 888c2ecf20Sopenharmony_ci for (f = 0; f < 2; f++) { 898c2ecf20Sopenharmony_ci for (l = 0; l < 24; l++) { 908c2ecf20Sopenharmony_ci fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal); 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic void check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci int f, l; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci for (f = 0; f < 2; f++) { 1008c2ecf20Sopenharmony_ci for (l = 0; l < 24; l++) { 1018c2ecf20Sopenharmony_ci fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal); 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ciu16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci int f, l; 1098c2ecf20Sopenharmony_ci u16 set = 0; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci for (f = 0; f < 2; f++) { 1128c2ecf20Sopenharmony_ci for (l = 0; l < 24; l++) { 1138c2ecf20Sopenharmony_ci set |= fmt->service_lines[f][l]; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci return set; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_civoid ivtv_set_osd_alpha(struct ivtv *itv) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci ivtv_vapi(itv, CX2341X_OSD_SET_GLOBAL_ALPHA, 3, 1228c2ecf20Sopenharmony_ci itv->osd_global_alpha_state, itv->osd_global_alpha, !itv->osd_local_alpha_state); 1238c2ecf20Sopenharmony_ci ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_chroma_key_state, itv->osd_chroma_key); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ciint ivtv_set_speed(struct ivtv *itv, int speed) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci u32 data[CX2341X_MBOX_MAX_DATA]; 1298c2ecf20Sopenharmony_ci int single_step = (speed == 1 || speed == -1); 1308c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (speed == 0) speed = 1000; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* No change? */ 1358c2ecf20Sopenharmony_ci if (speed == itv->speed && !single_step) 1368c2ecf20Sopenharmony_ci return 0; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (single_step && (speed < 0) == (itv->speed < 0)) { 1398c2ecf20Sopenharmony_ci /* Single step video and no need to change direction */ 1408c2ecf20Sopenharmony_ci ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0); 1418c2ecf20Sopenharmony_ci itv->speed = speed; 1428c2ecf20Sopenharmony_ci return 0; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci if (single_step) 1458c2ecf20Sopenharmony_ci /* Need to change direction */ 1468c2ecf20Sopenharmony_ci speed = speed < 0 ? -1000 : 1000; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci data[0] = (speed > 1000 || speed < -1000) ? 0x80000000 : 0; 1498c2ecf20Sopenharmony_ci data[0] |= (speed > 1000 || speed < -1500) ? 0x40000000 : 0; 1508c2ecf20Sopenharmony_ci data[1] = (speed < 0); 1518c2ecf20Sopenharmony_ci data[2] = speed < 0 ? 3 : 7; 1528c2ecf20Sopenharmony_ci data[3] = v4l2_ctrl_g_ctrl(itv->cxhdl.video_b_frames); 1538c2ecf20Sopenharmony_ci data[4] = (speed == 1500 || speed == 500) ? itv->speed_mute_audio : 0; 1548c2ecf20Sopenharmony_ci data[5] = 0; 1558c2ecf20Sopenharmony_ci data[6] = 0; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (speed == 1500 || speed == -1500) data[0] |= 1; 1588c2ecf20Sopenharmony_ci else if (speed == 2000 || speed == -2000) data[0] |= 2; 1598c2ecf20Sopenharmony_ci else if (speed > -1000 && speed < 0) data[0] |= (-1000 / speed); 1608c2ecf20Sopenharmony_ci else if (speed < 1000 && speed > 0) data[0] |= (1000 / speed); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* If not decoding, just change speed setting */ 1638c2ecf20Sopenharmony_ci if (atomic_read(&itv->decoding) > 0) { 1648c2ecf20Sopenharmony_ci int got_sig = 0; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* Stop all DMA and decoding activity */ 1678c2ecf20Sopenharmony_ci ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, 0); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci /* Wait for any DMA to finish */ 1708c2ecf20Sopenharmony_ci mutex_unlock(&itv->serialize_lock); 1718c2ecf20Sopenharmony_ci prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); 1728c2ecf20Sopenharmony_ci while (test_bit(IVTV_F_I_DMA, &itv->i_flags)) { 1738c2ecf20Sopenharmony_ci got_sig = signal_pending(current); 1748c2ecf20Sopenharmony_ci if (got_sig) 1758c2ecf20Sopenharmony_ci break; 1768c2ecf20Sopenharmony_ci got_sig = 0; 1778c2ecf20Sopenharmony_ci schedule(); 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci finish_wait(&itv->dma_waitq, &wait); 1808c2ecf20Sopenharmony_ci mutex_lock(&itv->serialize_lock); 1818c2ecf20Sopenharmony_ci if (got_sig) 1828c2ecf20Sopenharmony_ci return -EINTR; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci /* Change Speed safely */ 1858c2ecf20Sopenharmony_ci ivtv_api(itv, CX2341X_DEC_SET_PLAYBACK_SPEED, 7, data); 1868c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("Setting Speed to 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", 1878c2ecf20Sopenharmony_ci data[0], data[1], data[2], data[3], data[4], data[5], data[6]); 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci if (single_step) { 1908c2ecf20Sopenharmony_ci speed = (speed < 0) ? -1 : 1; 1918c2ecf20Sopenharmony_ci ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0); 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci itv->speed = speed; 1948c2ecf20Sopenharmony_ci return 0; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic int ivtv_validate_speed(int cur_speed, int new_speed) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci int fact = new_speed < 0 ? -1 : 1; 2008c2ecf20Sopenharmony_ci int s; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci if (cur_speed == 0) 2038c2ecf20Sopenharmony_ci cur_speed = 1000; 2048c2ecf20Sopenharmony_ci if (new_speed < 0) 2058c2ecf20Sopenharmony_ci new_speed = -new_speed; 2068c2ecf20Sopenharmony_ci if (cur_speed < 0) 2078c2ecf20Sopenharmony_ci cur_speed = -cur_speed; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (cur_speed <= new_speed) { 2108c2ecf20Sopenharmony_ci if (new_speed > 1500) 2118c2ecf20Sopenharmony_ci return fact * 2000; 2128c2ecf20Sopenharmony_ci if (new_speed > 1000) 2138c2ecf20Sopenharmony_ci return fact * 1500; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci else { 2168c2ecf20Sopenharmony_ci if (new_speed >= 2000) 2178c2ecf20Sopenharmony_ci return fact * 2000; 2188c2ecf20Sopenharmony_ci if (new_speed >= 1500) 2198c2ecf20Sopenharmony_ci return fact * 1500; 2208c2ecf20Sopenharmony_ci if (new_speed >= 1000) 2218c2ecf20Sopenharmony_ci return fact * 1000; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci if (new_speed == 0) 2248c2ecf20Sopenharmony_ci return 1000; 2258c2ecf20Sopenharmony_ci if (new_speed == 1 || new_speed == 1000) 2268c2ecf20Sopenharmony_ci return fact * new_speed; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci s = new_speed; 2298c2ecf20Sopenharmony_ci new_speed = 1000 / new_speed; 2308c2ecf20Sopenharmony_ci if (1000 / cur_speed == new_speed) 2318c2ecf20Sopenharmony_ci new_speed += (cur_speed < s) ? -1 : 1; 2328c2ecf20Sopenharmony_ci if (new_speed > 60) return 1000 / (fact * 60); 2338c2ecf20Sopenharmony_ci return 1000 / (fact * new_speed); 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id, 2378c2ecf20Sopenharmony_ci struct v4l2_decoder_cmd *dc, int try) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) 2428c2ecf20Sopenharmony_ci return -EINVAL; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci switch (dc->cmd) { 2458c2ecf20Sopenharmony_ci case V4L2_DEC_CMD_START: { 2468c2ecf20Sopenharmony_ci dc->flags &= V4L2_DEC_CMD_START_MUTE_AUDIO; 2478c2ecf20Sopenharmony_ci dc->start.speed = ivtv_validate_speed(itv->speed, dc->start.speed); 2488c2ecf20Sopenharmony_ci if (dc->start.speed < 0) 2498c2ecf20Sopenharmony_ci dc->start.format = V4L2_DEC_START_FMT_GOP; 2508c2ecf20Sopenharmony_ci else 2518c2ecf20Sopenharmony_ci dc->start.format = V4L2_DEC_START_FMT_NONE; 2528c2ecf20Sopenharmony_ci if (dc->start.speed != 500 && dc->start.speed != 1500) 2538c2ecf20Sopenharmony_ci dc->flags = dc->start.speed == 1000 ? 0 : 2548c2ecf20Sopenharmony_ci V4L2_DEC_CMD_START_MUTE_AUDIO; 2558c2ecf20Sopenharmony_ci if (try) break; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci itv->speed_mute_audio = dc->flags & V4L2_DEC_CMD_START_MUTE_AUDIO; 2588c2ecf20Sopenharmony_ci if (ivtv_set_output_mode(itv, OUT_MPG) != OUT_MPG) 2598c2ecf20Sopenharmony_ci return -EBUSY; 2608c2ecf20Sopenharmony_ci if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) { 2618c2ecf20Sopenharmony_ci /* forces ivtv_set_speed to be called */ 2628c2ecf20Sopenharmony_ci itv->speed = 0; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci return ivtv_start_decoding(id, dc->start.speed); 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci case V4L2_DEC_CMD_STOP: 2688c2ecf20Sopenharmony_ci dc->flags &= V4L2_DEC_CMD_STOP_IMMEDIATELY | V4L2_DEC_CMD_STOP_TO_BLACK; 2698c2ecf20Sopenharmony_ci if (dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) 2708c2ecf20Sopenharmony_ci dc->stop.pts = 0; 2718c2ecf20Sopenharmony_ci if (try) break; 2728c2ecf20Sopenharmony_ci if (atomic_read(&itv->decoding) == 0) 2738c2ecf20Sopenharmony_ci return 0; 2748c2ecf20Sopenharmony_ci if (itv->output_mode != OUT_MPG) 2758c2ecf20Sopenharmony_ci return -EBUSY; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci itv->output_mode = OUT_NONE; 2788c2ecf20Sopenharmony_ci return ivtv_stop_v4l2_decode_stream(s, dc->flags, dc->stop.pts); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci case V4L2_DEC_CMD_PAUSE: 2818c2ecf20Sopenharmony_ci dc->flags &= V4L2_DEC_CMD_PAUSE_TO_BLACK; 2828c2ecf20Sopenharmony_ci if (try) break; 2838c2ecf20Sopenharmony_ci if (!atomic_read(&itv->decoding)) 2848c2ecf20Sopenharmony_ci return -EPERM; 2858c2ecf20Sopenharmony_ci if (itv->output_mode != OUT_MPG) 2868c2ecf20Sopenharmony_ci return -EBUSY; 2878c2ecf20Sopenharmony_ci if (atomic_read(&itv->decoding) > 0) { 2888c2ecf20Sopenharmony_ci ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, 2898c2ecf20Sopenharmony_ci (dc->flags & V4L2_DEC_CMD_PAUSE_TO_BLACK) ? 1 : 0); 2908c2ecf20Sopenharmony_ci set_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags); 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci break; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci case V4L2_DEC_CMD_RESUME: 2958c2ecf20Sopenharmony_ci dc->flags = 0; 2968c2ecf20Sopenharmony_ci if (try) break; 2978c2ecf20Sopenharmony_ci if (!atomic_read(&itv->decoding)) 2988c2ecf20Sopenharmony_ci return -EPERM; 2998c2ecf20Sopenharmony_ci if (itv->output_mode != OUT_MPG) 3008c2ecf20Sopenharmony_ci return -EBUSY; 3018c2ecf20Sopenharmony_ci if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) { 3028c2ecf20Sopenharmony_ci int speed = itv->speed; 3038c2ecf20Sopenharmony_ci itv->speed = 0; 3048c2ecf20Sopenharmony_ci return ivtv_start_decoding(id, speed); 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci break; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci default: 3098c2ecf20Sopenharmony_ci return -EINVAL; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci return 0; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic int ivtv_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 3178c2ecf20Sopenharmony_ci struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci vbifmt->reserved[0] = 0; 3208c2ecf20Sopenharmony_ci vbifmt->reserved[1] = 0; 3218c2ecf20Sopenharmony_ci if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT)) 3228c2ecf20Sopenharmony_ci return -EINVAL; 3238c2ecf20Sopenharmony_ci vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; 3248c2ecf20Sopenharmony_ci memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines)); 3258c2ecf20Sopenharmony_ci if (itv->is_60hz) { 3268c2ecf20Sopenharmony_ci vbifmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525; 3278c2ecf20Sopenharmony_ci vbifmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525; 3288c2ecf20Sopenharmony_ci } else { 3298c2ecf20Sopenharmony_ci vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625; 3308c2ecf20Sopenharmony_ci vbifmt->service_lines[0][16] = V4L2_SLICED_VPS; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci vbifmt->service_set = ivtv_get_service_set(vbifmt); 3338c2ecf20Sopenharmony_ci return 0; 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(fh); 3398c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 3408c2ecf20Sopenharmony_ci struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci pixfmt->width = itv->cxhdl.width; 3438c2ecf20Sopenharmony_ci pixfmt->height = itv->cxhdl.height; 3448c2ecf20Sopenharmony_ci pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; 3458c2ecf20Sopenharmony_ci pixfmt->field = V4L2_FIELD_INTERLACED; 3468c2ecf20Sopenharmony_ci if (id->type == IVTV_ENC_STREAM_TYPE_YUV) { 3478c2ecf20Sopenharmony_ci pixfmt->pixelformat = V4L2_PIX_FMT_HM12; 3488c2ecf20Sopenharmony_ci /* YUV size is (Y=(h*720) + UV=(h*(720/2))) */ 3498c2ecf20Sopenharmony_ci pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2; 3508c2ecf20Sopenharmony_ci pixfmt->bytesperline = 720; 3518c2ecf20Sopenharmony_ci } else { 3528c2ecf20Sopenharmony_ci pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; 3538c2ecf20Sopenharmony_ci pixfmt->sizeimage = 128 * 1024; 3548c2ecf20Sopenharmony_ci pixfmt->bytesperline = 0; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci return 0; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic int ivtv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 3628c2ecf20Sopenharmony_ci struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci vbifmt->sampling_rate = 27000000; 3658c2ecf20Sopenharmony_ci vbifmt->offset = 248; 3668c2ecf20Sopenharmony_ci vbifmt->samples_per_line = itv->vbi.raw_decoder_line_size - 4; 3678c2ecf20Sopenharmony_ci vbifmt->sample_format = V4L2_PIX_FMT_GREY; 3688c2ecf20Sopenharmony_ci vbifmt->start[0] = itv->vbi.start[0]; 3698c2ecf20Sopenharmony_ci vbifmt->start[1] = itv->vbi.start[1]; 3708c2ecf20Sopenharmony_ci vbifmt->count[0] = vbifmt->count[1] = itv->vbi.count; 3718c2ecf20Sopenharmony_ci vbifmt->flags = 0; 3728c2ecf20Sopenharmony_ci vbifmt->reserved[0] = 0; 3738c2ecf20Sopenharmony_ci vbifmt->reserved[1] = 0; 3748c2ecf20Sopenharmony_ci return 0; 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; 3808c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(fh); 3818c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci vbifmt->reserved[0] = 0; 3848c2ecf20Sopenharmony_ci vbifmt->reserved[1] = 0; 3858c2ecf20Sopenharmony_ci vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci if (id->type == IVTV_DEC_STREAM_TYPE_VBI) { 3888c2ecf20Sopenharmony_ci vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 : 3898c2ecf20Sopenharmony_ci V4L2_SLICED_VBI_525; 3908c2ecf20Sopenharmony_ci ivtv_expand_service_set(vbifmt, itv->is_50hz); 3918c2ecf20Sopenharmony_ci vbifmt->service_set = ivtv_get_service_set(vbifmt); 3928c2ecf20Sopenharmony_ci return 0; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci v4l2_subdev_call(itv->sd_video, vbi, g_sliced_fmt, vbifmt); 3968c2ecf20Sopenharmony_ci vbifmt->service_set = ivtv_get_service_set(vbifmt); 3978c2ecf20Sopenharmony_ci return 0; 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic int ivtv_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(fh); 4038c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 4048c2ecf20Sopenharmony_ci struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) 4078c2ecf20Sopenharmony_ci return -EINVAL; 4088c2ecf20Sopenharmony_ci pixfmt->width = itv->main_rect.width; 4098c2ecf20Sopenharmony_ci pixfmt->height = itv->main_rect.height; 4108c2ecf20Sopenharmony_ci pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; 4118c2ecf20Sopenharmony_ci pixfmt->field = V4L2_FIELD_INTERLACED; 4128c2ecf20Sopenharmony_ci if (id->type == IVTV_DEC_STREAM_TYPE_YUV) { 4138c2ecf20Sopenharmony_ci switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) { 4148c2ecf20Sopenharmony_ci case IVTV_YUV_MODE_INTERLACED: 4158c2ecf20Sopenharmony_ci pixfmt->field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ? 4168c2ecf20Sopenharmony_ci V4L2_FIELD_INTERLACED_BT : V4L2_FIELD_INTERLACED_TB; 4178c2ecf20Sopenharmony_ci break; 4188c2ecf20Sopenharmony_ci case IVTV_YUV_MODE_PROGRESSIVE: 4198c2ecf20Sopenharmony_ci pixfmt->field = V4L2_FIELD_NONE; 4208c2ecf20Sopenharmony_ci break; 4218c2ecf20Sopenharmony_ci default: 4228c2ecf20Sopenharmony_ci pixfmt->field = V4L2_FIELD_ANY; 4238c2ecf20Sopenharmony_ci break; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci pixfmt->pixelformat = V4L2_PIX_FMT_HM12; 4268c2ecf20Sopenharmony_ci pixfmt->bytesperline = 720; 4278c2ecf20Sopenharmony_ci pixfmt->width = itv->yuv_info.v4l2_src_w; 4288c2ecf20Sopenharmony_ci pixfmt->height = itv->yuv_info.v4l2_src_h; 4298c2ecf20Sopenharmony_ci /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ 4308c2ecf20Sopenharmony_ci pixfmt->sizeimage = 4318c2ecf20Sopenharmony_ci 1080 * ((pixfmt->height + 31) & ~31); 4328c2ecf20Sopenharmony_ci } else { 4338c2ecf20Sopenharmony_ci pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; 4348c2ecf20Sopenharmony_ci pixfmt->sizeimage = 128 * 1024; 4358c2ecf20Sopenharmony_ci pixfmt->bytesperline = 0; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci return 0; 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_cistatic int ivtv_g_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 4438c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; 4448c2ecf20Sopenharmony_ci struct v4l2_window *winfmt = &fmt->fmt.win; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) 4478c2ecf20Sopenharmony_ci return -EINVAL; 4488c2ecf20Sopenharmony_ci if (!itv->osd_video_pbase) 4498c2ecf20Sopenharmony_ci return -EINVAL; 4508c2ecf20Sopenharmony_ci winfmt->chromakey = itv->osd_chroma_key; 4518c2ecf20Sopenharmony_ci winfmt->global_alpha = itv->osd_global_alpha; 4528c2ecf20Sopenharmony_ci winfmt->field = V4L2_FIELD_INTERLACED; 4538c2ecf20Sopenharmony_ci winfmt->clips = NULL; 4548c2ecf20Sopenharmony_ci winfmt->clipcount = 0; 4558c2ecf20Sopenharmony_ci winfmt->bitmap = NULL; 4568c2ecf20Sopenharmony_ci winfmt->w.top = winfmt->w.left = 0; 4578c2ecf20Sopenharmony_ci winfmt->w.width = itv->osd_rect.width; 4588c2ecf20Sopenharmony_ci winfmt->w.height = itv->osd_rect.height; 4598c2ecf20Sopenharmony_ci return 0; 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_cistatic int ivtv_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci return ivtv_g_fmt_sliced_vbi_out(file, fh, fmt); 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic int ivtv_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(fh); 4708c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 4718c2ecf20Sopenharmony_ci int w = fmt->fmt.pix.width; 4728c2ecf20Sopenharmony_ci int h = fmt->fmt.pix.height; 4738c2ecf20Sopenharmony_ci int min_h = 2; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci w = min(w, 720); 4768c2ecf20Sopenharmony_ci w = max(w, 2); 4778c2ecf20Sopenharmony_ci if (id->type == IVTV_ENC_STREAM_TYPE_YUV) { 4788c2ecf20Sopenharmony_ci /* YUV height must be a multiple of 32 */ 4798c2ecf20Sopenharmony_ci h &= ~0x1f; 4808c2ecf20Sopenharmony_ci min_h = 32; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci h = min(h, itv->is_50hz ? 576 : 480); 4838c2ecf20Sopenharmony_ci h = max(h, min_h); 4848c2ecf20Sopenharmony_ci ivtv_g_fmt_vid_cap(file, fh, fmt); 4858c2ecf20Sopenharmony_ci fmt->fmt.pix.width = w; 4868c2ecf20Sopenharmony_ci fmt->fmt.pix.height = h; 4878c2ecf20Sopenharmony_ci return 0; 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic int ivtv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci return ivtv_g_fmt_vbi_cap(file, fh, fmt); 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_cistatic int ivtv_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) 4968c2ecf20Sopenharmony_ci{ 4978c2ecf20Sopenharmony_ci struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; 4988c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(fh); 4998c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci if (id->type == IVTV_DEC_STREAM_TYPE_VBI) 5028c2ecf20Sopenharmony_ci return ivtv_g_fmt_sliced_vbi_cap(file, fh, fmt); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci /* set sliced VBI capture format */ 5058c2ecf20Sopenharmony_ci vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; 5068c2ecf20Sopenharmony_ci vbifmt->reserved[0] = 0; 5078c2ecf20Sopenharmony_ci vbifmt->reserved[1] = 0; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci if (vbifmt->service_set) 5108c2ecf20Sopenharmony_ci ivtv_expand_service_set(vbifmt, itv->is_50hz); 5118c2ecf20Sopenharmony_ci check_service_set(vbifmt, itv->is_50hz); 5128c2ecf20Sopenharmony_ci vbifmt->service_set = ivtv_get_service_set(vbifmt); 5138c2ecf20Sopenharmony_ci return 0; 5148c2ecf20Sopenharmony_ci} 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(fh); 5198c2ecf20Sopenharmony_ci s32 w = fmt->fmt.pix.width; 5208c2ecf20Sopenharmony_ci s32 h = fmt->fmt.pix.height; 5218c2ecf20Sopenharmony_ci int field = fmt->fmt.pix.field; 5228c2ecf20Sopenharmony_ci int ret = ivtv_g_fmt_vid_out(file, fh, fmt); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci w = min(w, 720); 5258c2ecf20Sopenharmony_ci w = max(w, 2); 5268c2ecf20Sopenharmony_ci /* Why can the height be 576 even when the output is NTSC? 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci Internally the buffers of the PVR350 are always set to 720x576. The 5298c2ecf20Sopenharmony_ci decoded video frame will always be placed in the top left corner of 5308c2ecf20Sopenharmony_ci this buffer. For any video which is not 720x576, the buffer will 5318c2ecf20Sopenharmony_ci then be cropped to remove the unused right and lower areas, with 5328c2ecf20Sopenharmony_ci the remaining image being scaled by the hardware to fit the display 5338c2ecf20Sopenharmony_ci area. The video can be scaled both up and down, so a 720x480 video 5348c2ecf20Sopenharmony_ci can be displayed full-screen on PAL and a 720x576 video can be 5358c2ecf20Sopenharmony_ci displayed without cropping on NTSC. 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci Note that the scaling only occurs on the video stream, the osd 5388c2ecf20Sopenharmony_ci resolution is locked to the broadcast standard and not scaled. 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci Thanks to Ian Armstrong for this explanation. */ 5418c2ecf20Sopenharmony_ci h = min(h, 576); 5428c2ecf20Sopenharmony_ci h = max(h, 2); 5438c2ecf20Sopenharmony_ci if (id->type == IVTV_DEC_STREAM_TYPE_YUV) 5448c2ecf20Sopenharmony_ci fmt->fmt.pix.field = field; 5458c2ecf20Sopenharmony_ci fmt->fmt.pix.width = w; 5468c2ecf20Sopenharmony_ci fmt->fmt.pix.height = h; 5478c2ecf20Sopenharmony_ci return ret; 5488c2ecf20Sopenharmony_ci} 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_cistatic int ivtv_try_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 5538c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; 5548c2ecf20Sopenharmony_ci u32 chromakey = fmt->fmt.win.chromakey; 5558c2ecf20Sopenharmony_ci u8 global_alpha = fmt->fmt.win.global_alpha; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) 5588c2ecf20Sopenharmony_ci return -EINVAL; 5598c2ecf20Sopenharmony_ci if (!itv->osd_video_pbase) 5608c2ecf20Sopenharmony_ci return -EINVAL; 5618c2ecf20Sopenharmony_ci ivtv_g_fmt_vid_out_overlay(file, fh, fmt); 5628c2ecf20Sopenharmony_ci fmt->fmt.win.chromakey = chromakey; 5638c2ecf20Sopenharmony_ci fmt->fmt.win.global_alpha = global_alpha; 5648c2ecf20Sopenharmony_ci return 0; 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_cistatic int ivtv_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci return ivtv_g_fmt_sliced_vbi_out(file, fh, fmt); 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(fh); 5758c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 5768c2ecf20Sopenharmony_ci struct v4l2_subdev_format format = { 5778c2ecf20Sopenharmony_ci .which = V4L2_SUBDEV_FORMAT_ACTIVE, 5788c2ecf20Sopenharmony_ci }; 5798c2ecf20Sopenharmony_ci int ret = ivtv_try_fmt_vid_cap(file, fh, fmt); 5808c2ecf20Sopenharmony_ci int w = fmt->fmt.pix.width; 5818c2ecf20Sopenharmony_ci int h = fmt->fmt.pix.height; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (ret) 5848c2ecf20Sopenharmony_ci return ret; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (itv->cxhdl.width == w && itv->cxhdl.height == h) 5878c2ecf20Sopenharmony_ci return 0; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci if (atomic_read(&itv->capturing) > 0) 5908c2ecf20Sopenharmony_ci return -EBUSY; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci itv->cxhdl.width = w; 5938c2ecf20Sopenharmony_ci itv->cxhdl.height = h; 5948c2ecf20Sopenharmony_ci if (v4l2_ctrl_g_ctrl(itv->cxhdl.video_encoding) == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) 5958c2ecf20Sopenharmony_ci fmt->fmt.pix.width /= 2; 5968c2ecf20Sopenharmony_ci format.format.width = fmt->fmt.pix.width; 5978c2ecf20Sopenharmony_ci format.format.height = h; 5988c2ecf20Sopenharmony_ci format.format.code = MEDIA_BUS_FMT_FIXED; 5998c2ecf20Sopenharmony_ci v4l2_subdev_call(itv->sd_video, pad, set_fmt, NULL, &format); 6008c2ecf20Sopenharmony_ci return ivtv_g_fmt_vid_cap(file, fh, fmt); 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_cistatic int ivtv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if (!ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0) 6088c2ecf20Sopenharmony_ci return -EBUSY; 6098c2ecf20Sopenharmony_ci itv->vbi.sliced_in->service_set = 0; 6108c2ecf20Sopenharmony_ci itv->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE; 6118c2ecf20Sopenharmony_ci v4l2_subdev_call(itv->sd_video, vbi, s_raw_fmt, &fmt->fmt.vbi); 6128c2ecf20Sopenharmony_ci return ivtv_g_fmt_vbi_cap(file, fh, fmt); 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cistatic int ivtv_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; 6188c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(fh); 6198c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 6208c2ecf20Sopenharmony_ci int ret = ivtv_try_fmt_sliced_vbi_cap(file, fh, fmt); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci if (ret || id->type == IVTV_DEC_STREAM_TYPE_VBI) 6238c2ecf20Sopenharmony_ci return ret; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci check_service_set(vbifmt, itv->is_50hz); 6268c2ecf20Sopenharmony_ci if (ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0) 6278c2ecf20Sopenharmony_ci return -EBUSY; 6288c2ecf20Sopenharmony_ci itv->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; 6298c2ecf20Sopenharmony_ci v4l2_subdev_call(itv->sd_video, vbi, s_sliced_fmt, vbifmt); 6308c2ecf20Sopenharmony_ci memcpy(itv->vbi.sliced_in, vbifmt, sizeof(*itv->vbi.sliced_in)); 6318c2ecf20Sopenharmony_ci return 0; 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_cistatic int ivtv_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(fh); 6378c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 6388c2ecf20Sopenharmony_ci struct yuv_playback_info *yi = &itv->yuv_info; 6398c2ecf20Sopenharmony_ci int ret = ivtv_try_fmt_vid_out(file, fh, fmt); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci if (ret) 6428c2ecf20Sopenharmony_ci return ret; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci if (id->type != IVTV_DEC_STREAM_TYPE_YUV) 6458c2ecf20Sopenharmony_ci return 0; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* Return now if we already have some frame data */ 6488c2ecf20Sopenharmony_ci if (yi->stream_size) 6498c2ecf20Sopenharmony_ci return -EBUSY; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci yi->v4l2_src_w = fmt->fmt.pix.width; 6528c2ecf20Sopenharmony_ci yi->v4l2_src_h = fmt->fmt.pix.height; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci switch (fmt->fmt.pix.field) { 6558c2ecf20Sopenharmony_ci case V4L2_FIELD_NONE: 6568c2ecf20Sopenharmony_ci yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE; 6578c2ecf20Sopenharmony_ci break; 6588c2ecf20Sopenharmony_ci case V4L2_FIELD_ANY: 6598c2ecf20Sopenharmony_ci yi->lace_mode = IVTV_YUV_MODE_AUTO; 6608c2ecf20Sopenharmony_ci break; 6618c2ecf20Sopenharmony_ci case V4L2_FIELD_INTERLACED_BT: 6628c2ecf20Sopenharmony_ci yi->lace_mode = 6638c2ecf20Sopenharmony_ci IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD; 6648c2ecf20Sopenharmony_ci break; 6658c2ecf20Sopenharmony_ci case V4L2_FIELD_INTERLACED_TB: 6668c2ecf20Sopenharmony_ci default: 6678c2ecf20Sopenharmony_ci yi->lace_mode = IVTV_YUV_MODE_INTERLACED; 6688c2ecf20Sopenharmony_ci break; 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) 6738c2ecf20Sopenharmony_ci itv->dma_data_req_size = 6748c2ecf20Sopenharmony_ci 1080 * ((yi->v4l2_src_h + 31) & ~31); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci return 0; 6778c2ecf20Sopenharmony_ci} 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_cistatic int ivtv_s_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) 6808c2ecf20Sopenharmony_ci{ 6818c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 6828c2ecf20Sopenharmony_ci int ret = ivtv_try_fmt_vid_out_overlay(file, fh, fmt); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci if (ret == 0) { 6858c2ecf20Sopenharmony_ci itv->osd_chroma_key = fmt->fmt.win.chromakey; 6868c2ecf20Sopenharmony_ci itv->osd_global_alpha = fmt->fmt.win.global_alpha; 6878c2ecf20Sopenharmony_ci ivtv_set_osd_alpha(itv); 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci return ret; 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG 6938c2ecf20Sopenharmony_cistatic int ivtv_itvc(struct ivtv *itv, bool get, u64 reg, u64 *val) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci volatile u8 __iomem *reg_start; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci if (reg & 0x3) 6988c2ecf20Sopenharmony_ci return -EINVAL; 6998c2ecf20Sopenharmony_ci if (reg >= IVTV_REG_OFFSET && reg < IVTV_REG_OFFSET + IVTV_REG_SIZE) 7008c2ecf20Sopenharmony_ci reg_start = itv->reg_mem - IVTV_REG_OFFSET; 7018c2ecf20Sopenharmony_ci else if (itv->has_cx23415 && reg >= IVTV_DECODER_OFFSET && 7028c2ecf20Sopenharmony_ci reg < IVTV_DECODER_OFFSET + IVTV_DECODER_SIZE) 7038c2ecf20Sopenharmony_ci reg_start = itv->dec_mem - IVTV_DECODER_OFFSET; 7048c2ecf20Sopenharmony_ci else if (reg < IVTV_ENCODER_SIZE) 7058c2ecf20Sopenharmony_ci reg_start = itv->enc_mem; 7068c2ecf20Sopenharmony_ci else 7078c2ecf20Sopenharmony_ci return -EINVAL; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci if (get) 7108c2ecf20Sopenharmony_ci *val = readl(reg + reg_start); 7118c2ecf20Sopenharmony_ci else 7128c2ecf20Sopenharmony_ci writel(*val, reg + reg_start); 7138c2ecf20Sopenharmony_ci return 0; 7148c2ecf20Sopenharmony_ci} 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_cistatic int ivtv_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci reg->size = 4; 7218c2ecf20Sopenharmony_ci return ivtv_itvc(itv, true, reg->reg, ®->val); 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_cistatic int ivtv_s_register(struct file *file, void *fh, const struct v4l2_dbg_register *reg) 7258c2ecf20Sopenharmony_ci{ 7268c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 7278c2ecf20Sopenharmony_ci u64 val = reg->val; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci return ivtv_itvc(itv, false, reg->reg, &val); 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci#endif 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_cistatic int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vcap) 7348c2ecf20Sopenharmony_ci{ 7358c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(file->private_data); 7368c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci strscpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver)); 7398c2ecf20Sopenharmony_ci strscpy(vcap->card, itv->card_name, sizeof(vcap->card)); 7408c2ecf20Sopenharmony_ci snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev)); 7418c2ecf20Sopenharmony_ci vcap->capabilities = itv->v4l2_cap | V4L2_CAP_DEVICE_CAPS; 7428c2ecf20Sopenharmony_ci return 0; 7438c2ecf20Sopenharmony_ci} 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_cistatic int ivtv_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) 7468c2ecf20Sopenharmony_ci{ 7478c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci return ivtv_get_audio_input(itv, vin->index, vin); 7508c2ecf20Sopenharmony_ci} 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_cistatic int ivtv_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) 7538c2ecf20Sopenharmony_ci{ 7548c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci vin->index = itv->audio_input; 7578c2ecf20Sopenharmony_ci return ivtv_get_audio_input(itv, vin->index, vin); 7588c2ecf20Sopenharmony_ci} 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_cistatic int ivtv_s_audio(struct file *file, void *fh, const struct v4l2_audio *vout) 7618c2ecf20Sopenharmony_ci{ 7628c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci if (vout->index >= itv->nof_audio_inputs) 7658c2ecf20Sopenharmony_ci return -EINVAL; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci itv->audio_input = vout->index; 7688c2ecf20Sopenharmony_ci ivtv_audio_set_io(itv); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci return 0; 7718c2ecf20Sopenharmony_ci} 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_cistatic int ivtv_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vin) 7748c2ecf20Sopenharmony_ci{ 7758c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci /* set it to defaults from our table */ 7788c2ecf20Sopenharmony_ci return ivtv_get_audio_output(itv, vin->index, vin); 7798c2ecf20Sopenharmony_ci} 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_cistatic int ivtv_g_audout(struct file *file, void *fh, struct v4l2_audioout *vin) 7828c2ecf20Sopenharmony_ci{ 7838c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci vin->index = 0; 7868c2ecf20Sopenharmony_ci return ivtv_get_audio_output(itv, vin->index, vin); 7878c2ecf20Sopenharmony_ci} 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_cistatic int ivtv_s_audout(struct file *file, void *fh, const struct v4l2_audioout *vout) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci if (itv->card->video_outputs == NULL || vout->index != 0) 7948c2ecf20Sopenharmony_ci return -EINVAL; 7958c2ecf20Sopenharmony_ci return 0; 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_cistatic int ivtv_enum_input(struct file *file, void *fh, struct v4l2_input *vin) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci /* set it to defaults from our table */ 8038c2ecf20Sopenharmony_ci return ivtv_get_input(itv, vin->index, vin); 8048c2ecf20Sopenharmony_ci} 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_cistatic int ivtv_enum_output(struct file *file, void *fh, struct v4l2_output *vout) 8078c2ecf20Sopenharmony_ci{ 8088c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci return ivtv_get_output(itv, vout->index, vout); 8118c2ecf20Sopenharmony_ci} 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_cistatic int ivtv_g_pixelaspect(struct file *file, void *fh, 8148c2ecf20Sopenharmony_ci int type, struct v4l2_fract *f) 8158c2ecf20Sopenharmony_ci{ 8168c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(fh); 8178c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { 8208c2ecf20Sopenharmony_ci f->numerator = itv->is_50hz ? 54 : 11; 8218c2ecf20Sopenharmony_ci f->denominator = itv->is_50hz ? 59 : 10; 8228c2ecf20Sopenharmony_ci } else if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { 8238c2ecf20Sopenharmony_ci f->numerator = itv->is_out_50hz ? 54 : 11; 8248c2ecf20Sopenharmony_ci f->denominator = itv->is_out_50hz ? 59 : 10; 8258c2ecf20Sopenharmony_ci } else { 8268c2ecf20Sopenharmony_ci return -EINVAL; 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci return 0; 8298c2ecf20Sopenharmony_ci} 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_cistatic int ivtv_s_selection(struct file *file, void *fh, 8328c2ecf20Sopenharmony_ci struct v4l2_selection *sel) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(fh); 8358c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 8368c2ecf20Sopenharmony_ci struct yuv_playback_info *yi = &itv->yuv_info; 8378c2ecf20Sopenharmony_ci struct v4l2_rect r = { 0, 0, 720, 0 }; 8388c2ecf20Sopenharmony_ci int streamtype = id->type; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || 8418c2ecf20Sopenharmony_ci !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) 8428c2ecf20Sopenharmony_ci return -EINVAL; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci if (sel->target != V4L2_SEL_TGT_COMPOSE) 8458c2ecf20Sopenharmony_ci return -EINVAL; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || 8498c2ecf20Sopenharmony_ci !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) 8508c2ecf20Sopenharmony_ci return -EINVAL; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci r.height = itv->is_out_50hz ? 576 : 480; 8538c2ecf20Sopenharmony_ci if (streamtype == IVTV_DEC_STREAM_TYPE_YUV && yi->track_osd) { 8548c2ecf20Sopenharmony_ci r.width = yi->osd_full_w; 8558c2ecf20Sopenharmony_ci r.height = yi->osd_full_h; 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci sel->r.width = clamp(sel->r.width, 16U, r.width); 8588c2ecf20Sopenharmony_ci sel->r.height = clamp(sel->r.height, 16U, r.height); 8598c2ecf20Sopenharmony_ci sel->r.left = clamp_t(unsigned, sel->r.left, 0, r.width - sel->r.width); 8608c2ecf20Sopenharmony_ci sel->r.top = clamp_t(unsigned, sel->r.top, 0, r.height - sel->r.height); 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { 8638c2ecf20Sopenharmony_ci yi->main_rect = sel->r; 8648c2ecf20Sopenharmony_ci return 0; 8658c2ecf20Sopenharmony_ci } 8668c2ecf20Sopenharmony_ci if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, 8678c2ecf20Sopenharmony_ci sel->r.width, sel->r.height, sel->r.left, sel->r.top)) { 8688c2ecf20Sopenharmony_ci itv->main_rect = sel->r; 8698c2ecf20Sopenharmony_ci return 0; 8708c2ecf20Sopenharmony_ci } 8718c2ecf20Sopenharmony_ci return -EINVAL; 8728c2ecf20Sopenharmony_ci} 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_cistatic int ivtv_g_selection(struct file *file, void *fh, 8758c2ecf20Sopenharmony_ci struct v4l2_selection *sel) 8768c2ecf20Sopenharmony_ci{ 8778c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(fh); 8788c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 8798c2ecf20Sopenharmony_ci struct yuv_playback_info *yi = &itv->yuv_info; 8808c2ecf20Sopenharmony_ci struct v4l2_rect r = { 0, 0, 720, 0 }; 8818c2ecf20Sopenharmony_ci int streamtype = id->type; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci if (sel->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { 8848c2ecf20Sopenharmony_ci switch (sel->target) { 8858c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_CROP_DEFAULT: 8868c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_CROP_BOUNDS: 8878c2ecf20Sopenharmony_ci sel->r.top = sel->r.left = 0; 8888c2ecf20Sopenharmony_ci sel->r.width = 720; 8898c2ecf20Sopenharmony_ci sel->r.height = itv->is_50hz ? 576 : 480; 8908c2ecf20Sopenharmony_ci return 0; 8918c2ecf20Sopenharmony_ci default: 8928c2ecf20Sopenharmony_ci return -EINVAL; 8938c2ecf20Sopenharmony_ci } 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || 8978c2ecf20Sopenharmony_ci !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) 8988c2ecf20Sopenharmony_ci return -EINVAL; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci switch (sel->target) { 9018c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_COMPOSE: 9028c2ecf20Sopenharmony_ci if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) 9038c2ecf20Sopenharmony_ci sel->r = yi->main_rect; 9048c2ecf20Sopenharmony_ci else 9058c2ecf20Sopenharmony_ci sel->r = itv->main_rect; 9068c2ecf20Sopenharmony_ci return 0; 9078c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_COMPOSE_DEFAULT: 9088c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_COMPOSE_BOUNDS: 9098c2ecf20Sopenharmony_ci r.height = itv->is_out_50hz ? 576 : 480; 9108c2ecf20Sopenharmony_ci if (streamtype == IVTV_DEC_STREAM_TYPE_YUV && yi->track_osd) { 9118c2ecf20Sopenharmony_ci r.width = yi->osd_full_w; 9128c2ecf20Sopenharmony_ci r.height = yi->osd_full_h; 9138c2ecf20Sopenharmony_ci } 9148c2ecf20Sopenharmony_ci sel->r = r; 9158c2ecf20Sopenharmony_ci return 0; 9168c2ecf20Sopenharmony_ci } 9178c2ecf20Sopenharmony_ci return -EINVAL; 9188c2ecf20Sopenharmony_ci} 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_cistatic int ivtv_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) 9218c2ecf20Sopenharmony_ci{ 9228c2ecf20Sopenharmony_ci static const struct v4l2_fmtdesc hm12 = { 9238c2ecf20Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, 9248c2ecf20Sopenharmony_ci .description = "HM12 (YUV 4:2:0)", 9258c2ecf20Sopenharmony_ci .pixelformat = V4L2_PIX_FMT_HM12, 9268c2ecf20Sopenharmony_ci }; 9278c2ecf20Sopenharmony_ci static const struct v4l2_fmtdesc mpeg = { 9288c2ecf20Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, 9298c2ecf20Sopenharmony_ci .flags = V4L2_FMT_FLAG_COMPRESSED, 9308c2ecf20Sopenharmony_ci .description = "MPEG", 9318c2ecf20Sopenharmony_ci .pixelformat = V4L2_PIX_FMT_MPEG, 9328c2ecf20Sopenharmony_ci }; 9338c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 9348c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci if (fmt->index) 9378c2ecf20Sopenharmony_ci return -EINVAL; 9388c2ecf20Sopenharmony_ci if (s->type == IVTV_ENC_STREAM_TYPE_MPG) 9398c2ecf20Sopenharmony_ci *fmt = mpeg; 9408c2ecf20Sopenharmony_ci else if (s->type == IVTV_ENC_STREAM_TYPE_YUV) 9418c2ecf20Sopenharmony_ci *fmt = hm12; 9428c2ecf20Sopenharmony_ci else 9438c2ecf20Sopenharmony_ci return -EINVAL; 9448c2ecf20Sopenharmony_ci return 0; 9458c2ecf20Sopenharmony_ci} 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_cistatic int ivtv_enum_fmt_vid_out(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) 9488c2ecf20Sopenharmony_ci{ 9498c2ecf20Sopenharmony_ci static const struct v4l2_fmtdesc hm12 = { 9508c2ecf20Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_OUTPUT, 9518c2ecf20Sopenharmony_ci .description = "HM12 (YUV 4:2:0)", 9528c2ecf20Sopenharmony_ci .pixelformat = V4L2_PIX_FMT_HM12, 9538c2ecf20Sopenharmony_ci }; 9548c2ecf20Sopenharmony_ci static const struct v4l2_fmtdesc mpeg = { 9558c2ecf20Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_OUTPUT, 9568c2ecf20Sopenharmony_ci .flags = V4L2_FMT_FLAG_COMPRESSED, 9578c2ecf20Sopenharmony_ci .description = "MPEG", 9588c2ecf20Sopenharmony_ci .pixelformat = V4L2_PIX_FMT_MPEG, 9598c2ecf20Sopenharmony_ci }; 9608c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 9618c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci if (fmt->index) 9648c2ecf20Sopenharmony_ci return -EINVAL; 9658c2ecf20Sopenharmony_ci if (s->type == IVTV_DEC_STREAM_TYPE_MPG) 9668c2ecf20Sopenharmony_ci *fmt = mpeg; 9678c2ecf20Sopenharmony_ci else if (s->type == IVTV_DEC_STREAM_TYPE_YUV) 9688c2ecf20Sopenharmony_ci *fmt = hm12; 9698c2ecf20Sopenharmony_ci else 9708c2ecf20Sopenharmony_ci return -EINVAL; 9718c2ecf20Sopenharmony_ci return 0; 9728c2ecf20Sopenharmony_ci} 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_cistatic int ivtv_g_input(struct file *file, void *fh, unsigned int *i) 9758c2ecf20Sopenharmony_ci{ 9768c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci *i = itv->active_input; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci return 0; 9818c2ecf20Sopenharmony_ci} 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ciint ivtv_s_input(struct file *file, void *fh, unsigned int inp) 9848c2ecf20Sopenharmony_ci{ 9858c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 9868c2ecf20Sopenharmony_ci v4l2_std_id std; 9878c2ecf20Sopenharmony_ci int i; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci if (inp >= itv->nof_inputs) 9908c2ecf20Sopenharmony_ci return -EINVAL; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci if (inp == itv->active_input) { 9938c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("Input unchanged\n"); 9948c2ecf20Sopenharmony_ci return 0; 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci if (atomic_read(&itv->capturing) > 0) { 9988c2ecf20Sopenharmony_ci return -EBUSY; 9998c2ecf20Sopenharmony_ci } 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("Changing input from %d to %d\n", 10028c2ecf20Sopenharmony_ci itv->active_input, inp); 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci itv->active_input = inp; 10058c2ecf20Sopenharmony_ci /* Set the audio input to whatever is appropriate for the 10068c2ecf20Sopenharmony_ci input type. */ 10078c2ecf20Sopenharmony_ci itv->audio_input = itv->card->video_inputs[inp].audio_index; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci if (itv->card->video_inputs[inp].video_type == IVTV_CARD_INPUT_VID_TUNER) 10108c2ecf20Sopenharmony_ci std = itv->tuner_std; 10118c2ecf20Sopenharmony_ci else 10128c2ecf20Sopenharmony_ci std = V4L2_STD_ALL; 10138c2ecf20Sopenharmony_ci for (i = 0; i <= IVTV_ENC_STREAM_TYPE_VBI; i++) 10148c2ecf20Sopenharmony_ci itv->streams[i].vdev.tvnorms = std; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci /* prevent others from messing with the streams until 10178c2ecf20Sopenharmony_ci we're finished changing inputs. */ 10188c2ecf20Sopenharmony_ci ivtv_mute(itv); 10198c2ecf20Sopenharmony_ci ivtv_video_set_io(itv); 10208c2ecf20Sopenharmony_ci ivtv_audio_set_io(itv); 10218c2ecf20Sopenharmony_ci ivtv_unmute(itv); 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci return 0; 10248c2ecf20Sopenharmony_ci} 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_cistatic int ivtv_g_output(struct file *file, void *fh, unsigned int *i) 10278c2ecf20Sopenharmony_ci{ 10288c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) 10318c2ecf20Sopenharmony_ci return -EINVAL; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci *i = itv->active_output; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci return 0; 10368c2ecf20Sopenharmony_ci} 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_cistatic int ivtv_s_output(struct file *file, void *fh, unsigned int outp) 10398c2ecf20Sopenharmony_ci{ 10408c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci if (outp >= itv->card->nof_outputs) 10438c2ecf20Sopenharmony_ci return -EINVAL; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci if (outp == itv->active_output) { 10468c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("Output unchanged\n"); 10478c2ecf20Sopenharmony_ci return 0; 10488c2ecf20Sopenharmony_ci } 10498c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("Changing output from %d to %d\n", 10508c2ecf20Sopenharmony_ci itv->active_output, outp); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci itv->active_output = outp; 10538c2ecf20Sopenharmony_ci ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing, 10548c2ecf20Sopenharmony_ci SAA7127_INPUT_TYPE_NORMAL, 10558c2ecf20Sopenharmony_ci itv->card->video_outputs[outp].video_output, 0); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci return 0; 10588c2ecf20Sopenharmony_ci} 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_cistatic int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) 10618c2ecf20Sopenharmony_ci{ 10628c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 10638c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci if (s->vdev.vfl_dir) 10668c2ecf20Sopenharmony_ci return -ENOTTY; 10678c2ecf20Sopenharmony_ci if (vf->tuner != 0) 10688c2ecf20Sopenharmony_ci return -EINVAL; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci ivtv_call_all(itv, tuner, g_frequency, vf); 10718c2ecf20Sopenharmony_ci return 0; 10728c2ecf20Sopenharmony_ci} 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ciint ivtv_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf) 10758c2ecf20Sopenharmony_ci{ 10768c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 10778c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci if (s->vdev.vfl_dir) 10808c2ecf20Sopenharmony_ci return -ENOTTY; 10818c2ecf20Sopenharmony_ci if (vf->tuner != 0) 10828c2ecf20Sopenharmony_ci return -EINVAL; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci ivtv_mute(itv); 10858c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency); 10868c2ecf20Sopenharmony_ci ivtv_call_all(itv, tuner, s_frequency, vf); 10878c2ecf20Sopenharmony_ci ivtv_unmute(itv); 10888c2ecf20Sopenharmony_ci return 0; 10898c2ecf20Sopenharmony_ci} 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_cistatic int ivtv_g_std(struct file *file, void *fh, v4l2_std_id *std) 10928c2ecf20Sopenharmony_ci{ 10938c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci *std = itv->std; 10968c2ecf20Sopenharmony_ci return 0; 10978c2ecf20Sopenharmony_ci} 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_civoid ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id std) 11008c2ecf20Sopenharmony_ci{ 11018c2ecf20Sopenharmony_ci itv->std = std; 11028c2ecf20Sopenharmony_ci itv->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0; 11038c2ecf20Sopenharmony_ci itv->is_50hz = !itv->is_60hz; 11048c2ecf20Sopenharmony_ci cx2341x_handler_set_50hz(&itv->cxhdl, itv->is_50hz); 11058c2ecf20Sopenharmony_ci itv->cxhdl.width = 720; 11068c2ecf20Sopenharmony_ci itv->cxhdl.height = itv->is_50hz ? 576 : 480; 11078c2ecf20Sopenharmony_ci itv->vbi.count = itv->is_50hz ? 18 : 12; 11088c2ecf20Sopenharmony_ci itv->vbi.start[0] = itv->is_50hz ? 6 : 10; 11098c2ecf20Sopenharmony_ci itv->vbi.start[1] = itv->is_50hz ? 318 : 273; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci if (itv->hw_flags & IVTV_HW_CX25840) 11128c2ecf20Sopenharmony_ci itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284; 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci /* Tuner */ 11158c2ecf20Sopenharmony_ci ivtv_call_all(itv, video, s_std, itv->std); 11168c2ecf20Sopenharmony_ci} 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_civoid ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id std) 11198c2ecf20Sopenharmony_ci{ 11208c2ecf20Sopenharmony_ci struct yuv_playback_info *yi = &itv->yuv_info; 11218c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 11228c2ecf20Sopenharmony_ci int f; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci /* set display standard */ 11258c2ecf20Sopenharmony_ci itv->std_out = std; 11268c2ecf20Sopenharmony_ci itv->is_out_60hz = (std & V4L2_STD_525_60) ? 1 : 0; 11278c2ecf20Sopenharmony_ci itv->is_out_50hz = !itv->is_out_60hz; 11288c2ecf20Sopenharmony_ci ivtv_call_all(itv, video, s_std_output, itv->std_out); 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci /* 11318c2ecf20Sopenharmony_ci * The next firmware call is time sensitive. Time it to 11328c2ecf20Sopenharmony_ci * avoid risk of a hard lock, by trying to ensure the call 11338c2ecf20Sopenharmony_ci * happens within the first 100 lines of the top field. 11348c2ecf20Sopenharmony_ci * Make 4 attempts to sync to the decoder before giving up. 11358c2ecf20Sopenharmony_ci */ 11368c2ecf20Sopenharmony_ci mutex_unlock(&itv->serialize_lock); 11378c2ecf20Sopenharmony_ci for (f = 0; f < 4; f++) { 11388c2ecf20Sopenharmony_ci prepare_to_wait(&itv->vsync_waitq, &wait, 11398c2ecf20Sopenharmony_ci TASK_UNINTERRUPTIBLE); 11408c2ecf20Sopenharmony_ci if ((read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16) < 100) 11418c2ecf20Sopenharmony_ci break; 11428c2ecf20Sopenharmony_ci schedule_timeout(msecs_to_jiffies(25)); 11438c2ecf20Sopenharmony_ci } 11448c2ecf20Sopenharmony_ci finish_wait(&itv->vsync_waitq, &wait); 11458c2ecf20Sopenharmony_ci mutex_lock(&itv->serialize_lock); 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci if (f == 4) 11488c2ecf20Sopenharmony_ci IVTV_WARN("Mode change failed to sync to decoder\n"); 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz); 11518c2ecf20Sopenharmony_ci itv->main_rect.left = 0; 11528c2ecf20Sopenharmony_ci itv->main_rect.top = 0; 11538c2ecf20Sopenharmony_ci itv->main_rect.width = 720; 11548c2ecf20Sopenharmony_ci itv->main_rect.height = itv->is_out_50hz ? 576 : 480; 11558c2ecf20Sopenharmony_ci ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, 11568c2ecf20Sopenharmony_ci 720, itv->main_rect.height, 0, 0); 11578c2ecf20Sopenharmony_ci yi->main_rect = itv->main_rect; 11588c2ecf20Sopenharmony_ci if (!itv->osd_info) { 11598c2ecf20Sopenharmony_ci yi->osd_full_w = 720; 11608c2ecf20Sopenharmony_ci yi->osd_full_h = itv->is_out_50hz ? 576 : 480; 11618c2ecf20Sopenharmony_ci } 11628c2ecf20Sopenharmony_ci} 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_cistatic int ivtv_s_std(struct file *file, void *fh, v4l2_std_id std) 11658c2ecf20Sopenharmony_ci{ 11668c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci if ((std & V4L2_STD_ALL) == 0) 11698c2ecf20Sopenharmony_ci return -EINVAL; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci if (std == itv->std) 11728c2ecf20Sopenharmony_ci return 0; 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) || 11758c2ecf20Sopenharmony_ci atomic_read(&itv->capturing) > 0 || 11768c2ecf20Sopenharmony_ci atomic_read(&itv->decoding) > 0) { 11778c2ecf20Sopenharmony_ci /* Switching standard would mess with already running 11788c2ecf20Sopenharmony_ci streams, prevent that by returning EBUSY. */ 11798c2ecf20Sopenharmony_ci return -EBUSY; 11808c2ecf20Sopenharmony_ci } 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("Switching standard to %llx.\n", 11838c2ecf20Sopenharmony_ci (unsigned long long)itv->std); 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci ivtv_s_std_enc(itv, std); 11868c2ecf20Sopenharmony_ci if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) 11878c2ecf20Sopenharmony_ci ivtv_s_std_dec(itv, std); 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci return 0; 11908c2ecf20Sopenharmony_ci} 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_cistatic int ivtv_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) 11938c2ecf20Sopenharmony_ci{ 11948c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(fh); 11958c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci if (vt->index != 0) 11988c2ecf20Sopenharmony_ci return -EINVAL; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci ivtv_call_all(itv, tuner, s_tuner, vt); 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci return 0; 12038c2ecf20Sopenharmony_ci} 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_cistatic int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) 12068c2ecf20Sopenharmony_ci{ 12078c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci if (vt->index != 0) 12108c2ecf20Sopenharmony_ci return -EINVAL; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci ivtv_call_all(itv, tuner, g_tuner, vt); 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci if (vt->type == V4L2_TUNER_RADIO) 12158c2ecf20Sopenharmony_ci strscpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name)); 12168c2ecf20Sopenharmony_ci else 12178c2ecf20Sopenharmony_ci strscpy(vt->name, "ivtv TV Tuner", sizeof(vt->name)); 12188c2ecf20Sopenharmony_ci return 0; 12198c2ecf20Sopenharmony_ci} 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_cistatic int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap) 12228c2ecf20Sopenharmony_ci{ 12238c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 12248c2ecf20Sopenharmony_ci int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; 12258c2ecf20Sopenharmony_ci int f, l; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { 12288c2ecf20Sopenharmony_ci for (f = 0; f < 2; f++) { 12298c2ecf20Sopenharmony_ci for (l = 0; l < 24; l++) { 12308c2ecf20Sopenharmony_ci if (valid_service_line(f, l, itv->is_50hz)) 12318c2ecf20Sopenharmony_ci cap->service_lines[f][l] = set; 12328c2ecf20Sopenharmony_ci } 12338c2ecf20Sopenharmony_ci } 12348c2ecf20Sopenharmony_ci } else if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) { 12358c2ecf20Sopenharmony_ci if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT)) 12368c2ecf20Sopenharmony_ci return -EINVAL; 12378c2ecf20Sopenharmony_ci if (itv->is_60hz) { 12388c2ecf20Sopenharmony_ci cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525; 12398c2ecf20Sopenharmony_ci cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525; 12408c2ecf20Sopenharmony_ci } else { 12418c2ecf20Sopenharmony_ci cap->service_lines[0][23] = V4L2_SLICED_WSS_625; 12428c2ecf20Sopenharmony_ci cap->service_lines[0][16] = V4L2_SLICED_VPS; 12438c2ecf20Sopenharmony_ci } 12448c2ecf20Sopenharmony_ci } else { 12458c2ecf20Sopenharmony_ci return -EINVAL; 12468c2ecf20Sopenharmony_ci } 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci set = 0; 12498c2ecf20Sopenharmony_ci for (f = 0; f < 2; f++) 12508c2ecf20Sopenharmony_ci for (l = 0; l < 24; l++) 12518c2ecf20Sopenharmony_ci set |= cap->service_lines[f][l]; 12528c2ecf20Sopenharmony_ci cap->service_set = set; 12538c2ecf20Sopenharmony_ci return 0; 12548c2ecf20Sopenharmony_ci} 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_cistatic int ivtv_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *idx) 12578c2ecf20Sopenharmony_ci{ 12588c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 12598c2ecf20Sopenharmony_ci struct v4l2_enc_idx_entry *e = idx->entry; 12608c2ecf20Sopenharmony_ci int entries; 12618c2ecf20Sopenharmony_ci int i; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) % 12648c2ecf20Sopenharmony_ci IVTV_MAX_PGM_INDEX; 12658c2ecf20Sopenharmony_ci if (entries > V4L2_ENC_IDX_ENTRIES) 12668c2ecf20Sopenharmony_ci entries = V4L2_ENC_IDX_ENTRIES; 12678c2ecf20Sopenharmony_ci idx->entries = 0; 12688c2ecf20Sopenharmony_ci idx->entries_cap = IVTV_MAX_PGM_INDEX; 12698c2ecf20Sopenharmony_ci if (!atomic_read(&itv->capturing)) 12708c2ecf20Sopenharmony_ci return 0; 12718c2ecf20Sopenharmony_ci for (i = 0; i < entries; i++) { 12728c2ecf20Sopenharmony_ci *e = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX]; 12738c2ecf20Sopenharmony_ci if ((e->flags & V4L2_ENC_IDX_FRAME_MASK) <= V4L2_ENC_IDX_FRAME_B) { 12748c2ecf20Sopenharmony_ci idx->entries++; 12758c2ecf20Sopenharmony_ci e++; 12768c2ecf20Sopenharmony_ci } 12778c2ecf20Sopenharmony_ci } 12788c2ecf20Sopenharmony_ci itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX; 12798c2ecf20Sopenharmony_ci return 0; 12808c2ecf20Sopenharmony_ci} 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_cistatic int ivtv_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc) 12838c2ecf20Sopenharmony_ci{ 12848c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(fh); 12858c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci switch (enc->cmd) { 12898c2ecf20Sopenharmony_ci case V4L2_ENC_CMD_START: 12908c2ecf20Sopenharmony_ci IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); 12918c2ecf20Sopenharmony_ci enc->flags = 0; 12928c2ecf20Sopenharmony_ci return ivtv_start_capture(id); 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci case V4L2_ENC_CMD_STOP: 12958c2ecf20Sopenharmony_ci IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); 12968c2ecf20Sopenharmony_ci enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; 12978c2ecf20Sopenharmony_ci ivtv_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END); 12988c2ecf20Sopenharmony_ci return 0; 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci case V4L2_ENC_CMD_PAUSE: 13018c2ecf20Sopenharmony_ci IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); 13028c2ecf20Sopenharmony_ci enc->flags = 0; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci if (!atomic_read(&itv->capturing)) 13058c2ecf20Sopenharmony_ci return -EPERM; 13068c2ecf20Sopenharmony_ci if (test_and_set_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) 13078c2ecf20Sopenharmony_ci return 0; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci ivtv_mute(itv); 13108c2ecf20Sopenharmony_ci ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 0); 13118c2ecf20Sopenharmony_ci break; 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci case V4L2_ENC_CMD_RESUME: 13148c2ecf20Sopenharmony_ci IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); 13158c2ecf20Sopenharmony_ci enc->flags = 0; 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci if (!atomic_read(&itv->capturing)) 13188c2ecf20Sopenharmony_ci return -EPERM; 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci if (!test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) 13218c2ecf20Sopenharmony_ci return 0; 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1); 13248c2ecf20Sopenharmony_ci ivtv_unmute(itv); 13258c2ecf20Sopenharmony_ci break; 13268c2ecf20Sopenharmony_ci default: 13278c2ecf20Sopenharmony_ci IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); 13288c2ecf20Sopenharmony_ci return -EINVAL; 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci return 0; 13328c2ecf20Sopenharmony_ci} 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_cistatic int ivtv_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc) 13358c2ecf20Sopenharmony_ci{ 13368c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci switch (enc->cmd) { 13398c2ecf20Sopenharmony_ci case V4L2_ENC_CMD_START: 13408c2ecf20Sopenharmony_ci IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); 13418c2ecf20Sopenharmony_ci enc->flags = 0; 13428c2ecf20Sopenharmony_ci return 0; 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci case V4L2_ENC_CMD_STOP: 13458c2ecf20Sopenharmony_ci IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); 13468c2ecf20Sopenharmony_ci enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; 13478c2ecf20Sopenharmony_ci return 0; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci case V4L2_ENC_CMD_PAUSE: 13508c2ecf20Sopenharmony_ci IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); 13518c2ecf20Sopenharmony_ci enc->flags = 0; 13528c2ecf20Sopenharmony_ci return 0; 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci case V4L2_ENC_CMD_RESUME: 13558c2ecf20Sopenharmony_ci IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); 13568c2ecf20Sopenharmony_ci enc->flags = 0; 13578c2ecf20Sopenharmony_ci return 0; 13588c2ecf20Sopenharmony_ci default: 13598c2ecf20Sopenharmony_ci IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); 13608c2ecf20Sopenharmony_ci return -EINVAL; 13618c2ecf20Sopenharmony_ci } 13628c2ecf20Sopenharmony_ci} 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_cistatic int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) 13658c2ecf20Sopenharmony_ci{ 13668c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 13678c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; 13688c2ecf20Sopenharmony_ci u32 data[CX2341X_MBOX_MAX_DATA]; 13698c2ecf20Sopenharmony_ci struct yuv_playback_info *yi = &itv->yuv_info; 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci int pixfmt; 13728c2ecf20Sopenharmony_ci static u32 pixel_format[16] = { 13738c2ecf20Sopenharmony_ci V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */ 13748c2ecf20Sopenharmony_ci V4L2_PIX_FMT_RGB565, 13758c2ecf20Sopenharmony_ci V4L2_PIX_FMT_RGB555, 13768c2ecf20Sopenharmony_ci V4L2_PIX_FMT_RGB444, 13778c2ecf20Sopenharmony_ci V4L2_PIX_FMT_RGB32, 13788c2ecf20Sopenharmony_ci 0, 13798c2ecf20Sopenharmony_ci 0, 13808c2ecf20Sopenharmony_ci 0, 13818c2ecf20Sopenharmony_ci V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */ 13828c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YUV565, 13838c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YUV555, 13848c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YUV444, 13858c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YUV32, 13868c2ecf20Sopenharmony_ci 0, 13878c2ecf20Sopenharmony_ci 0, 13888c2ecf20Sopenharmony_ci 0, 13898c2ecf20Sopenharmony_ci }; 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) 13928c2ecf20Sopenharmony_ci return -ENOTTY; 13938c2ecf20Sopenharmony_ci if (!itv->osd_video_pbase) 13948c2ecf20Sopenharmony_ci return -ENOTTY; 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY | 13978c2ecf20Sopenharmony_ci V4L2_FBUF_CAP_GLOBAL_ALPHA; 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); 14008c2ecf20Sopenharmony_ci data[0] |= (read_reg(0x2a00) >> 7) & 0x40; 14018c2ecf20Sopenharmony_ci pixfmt = (data[0] >> 3) & 0xf; 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci fb->fmt.pixelformat = pixel_format[pixfmt]; 14048c2ecf20Sopenharmony_ci fb->fmt.width = itv->osd_rect.width; 14058c2ecf20Sopenharmony_ci fb->fmt.height = itv->osd_rect.height; 14068c2ecf20Sopenharmony_ci fb->fmt.field = V4L2_FIELD_INTERLACED; 14078c2ecf20Sopenharmony_ci fb->fmt.bytesperline = fb->fmt.width; 14088c2ecf20Sopenharmony_ci fb->fmt.colorspace = V4L2_COLORSPACE_SMPTE170M; 14098c2ecf20Sopenharmony_ci fb->fmt.field = V4L2_FIELD_INTERLACED; 14108c2ecf20Sopenharmony_ci if (fb->fmt.pixelformat != V4L2_PIX_FMT_PAL8) 14118c2ecf20Sopenharmony_ci fb->fmt.bytesperline *= 2; 14128c2ecf20Sopenharmony_ci if (fb->fmt.pixelformat == V4L2_PIX_FMT_RGB32 || 14138c2ecf20Sopenharmony_ci fb->fmt.pixelformat == V4L2_PIX_FMT_YUV32) 14148c2ecf20Sopenharmony_ci fb->fmt.bytesperline *= 2; 14158c2ecf20Sopenharmony_ci fb->fmt.sizeimage = fb->fmt.bytesperline * fb->fmt.height; 14168c2ecf20Sopenharmony_ci fb->base = (void *)itv->osd_video_pbase; 14178c2ecf20Sopenharmony_ci fb->flags = 0; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci if (itv->osd_chroma_key_state) 14208c2ecf20Sopenharmony_ci fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci if (itv->osd_global_alpha_state) 14238c2ecf20Sopenharmony_ci fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci if (yi->track_osd) 14268c2ecf20Sopenharmony_ci fb->flags |= V4L2_FBUF_FLAG_OVERLAY; 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci pixfmt &= 7; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci /* no local alpha for RGB565 or unknown formats */ 14318c2ecf20Sopenharmony_ci if (pixfmt == 1 || pixfmt > 4) 14328c2ecf20Sopenharmony_ci return 0; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci /* 16-bit formats have inverted local alpha */ 14358c2ecf20Sopenharmony_ci if (pixfmt == 2 || pixfmt == 3) 14368c2ecf20Sopenharmony_ci fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA; 14378c2ecf20Sopenharmony_ci else 14388c2ecf20Sopenharmony_ci fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA; 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci if (itv->osd_local_alpha_state) { 14418c2ecf20Sopenharmony_ci /* 16-bit formats have inverted local alpha */ 14428c2ecf20Sopenharmony_ci if (pixfmt == 2 || pixfmt == 3) 14438c2ecf20Sopenharmony_ci fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA; 14448c2ecf20Sopenharmony_ci else 14458c2ecf20Sopenharmony_ci fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; 14468c2ecf20Sopenharmony_ci } 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci return 0; 14498c2ecf20Sopenharmony_ci} 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_cistatic int ivtv_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *fb) 14528c2ecf20Sopenharmony_ci{ 14538c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(fh); 14548c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 14558c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; 14568c2ecf20Sopenharmony_ci struct yuv_playback_info *yi = &itv->yuv_info; 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) 14598c2ecf20Sopenharmony_ci return -ENOTTY; 14608c2ecf20Sopenharmony_ci if (!itv->osd_video_pbase) 14618c2ecf20Sopenharmony_ci return -ENOTTY; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0; 14648c2ecf20Sopenharmony_ci itv->osd_local_alpha_state = 14658c2ecf20Sopenharmony_ci (fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0; 14668c2ecf20Sopenharmony_ci itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0; 14678c2ecf20Sopenharmony_ci ivtv_set_osd_alpha(itv); 14688c2ecf20Sopenharmony_ci yi->track_osd = (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0; 14698c2ecf20Sopenharmony_ci return 0; 14708c2ecf20Sopenharmony_ci} 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_cistatic int ivtv_overlay(struct file *file, void *fh, unsigned int on) 14738c2ecf20Sopenharmony_ci{ 14748c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(fh); 14758c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 14768c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) 14798c2ecf20Sopenharmony_ci return -ENOTTY; 14808c2ecf20Sopenharmony_ci if (!itv->osd_video_pbase) 14818c2ecf20Sopenharmony_ci return -ENOTTY; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, on != 0); 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci return 0; 14868c2ecf20Sopenharmony_ci} 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_cistatic int ivtv_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) 14898c2ecf20Sopenharmony_ci{ 14908c2ecf20Sopenharmony_ci switch (sub->type) { 14918c2ecf20Sopenharmony_ci case V4L2_EVENT_VSYNC: 14928c2ecf20Sopenharmony_ci case V4L2_EVENT_EOS: 14938c2ecf20Sopenharmony_ci return v4l2_event_subscribe(fh, sub, 0, NULL); 14948c2ecf20Sopenharmony_ci default: 14958c2ecf20Sopenharmony_ci return v4l2_ctrl_subscribe_event(fh, sub); 14968c2ecf20Sopenharmony_ci } 14978c2ecf20Sopenharmony_ci} 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_cistatic int ivtv_log_status(struct file *file, void *fh) 15008c2ecf20Sopenharmony_ci{ 15018c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 15028c2ecf20Sopenharmony_ci u32 data[CX2341X_MBOX_MAX_DATA]; 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT; 15058c2ecf20Sopenharmony_ci struct v4l2_input vidin; 15068c2ecf20Sopenharmony_ci struct v4l2_audio audin; 15078c2ecf20Sopenharmony_ci int i; 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name); 15108c2ecf20Sopenharmony_ci if (itv->hw_flags & IVTV_HW_TVEEPROM) { 15118c2ecf20Sopenharmony_ci struct tveeprom tv; 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci ivtv_read_eeprom(itv, &tv); 15148c2ecf20Sopenharmony_ci } 15158c2ecf20Sopenharmony_ci ivtv_call_all(itv, core, log_status); 15168c2ecf20Sopenharmony_ci ivtv_get_input(itv, itv->active_input, &vidin); 15178c2ecf20Sopenharmony_ci ivtv_get_audio_input(itv, itv->audio_input, &audin); 15188c2ecf20Sopenharmony_ci IVTV_INFO("Video Input: %s\n", vidin.name); 15198c2ecf20Sopenharmony_ci IVTV_INFO("Audio Input: %s%s\n", audin.name, 15208c2ecf20Sopenharmony_ci itv->dualwatch_stereo_mode == V4L2_MPEG_AUDIO_MODE_DUAL ? 15218c2ecf20Sopenharmony_ci " (Bilingual)" : ""); 15228c2ecf20Sopenharmony_ci if (has_output) { 15238c2ecf20Sopenharmony_ci struct v4l2_output vidout; 15248c2ecf20Sopenharmony_ci struct v4l2_audioout audout; 15258c2ecf20Sopenharmony_ci int mode = itv->output_mode; 15268c2ecf20Sopenharmony_ci static const char * const output_modes[5] = { 15278c2ecf20Sopenharmony_ci "None", 15288c2ecf20Sopenharmony_ci "MPEG Streaming", 15298c2ecf20Sopenharmony_ci "YUV Streaming", 15308c2ecf20Sopenharmony_ci "YUV Frames", 15318c2ecf20Sopenharmony_ci "Passthrough", 15328c2ecf20Sopenharmony_ci }; 15338c2ecf20Sopenharmony_ci static const char * const alpha_mode[4] = { 15348c2ecf20Sopenharmony_ci "None", 15358c2ecf20Sopenharmony_ci "Global", 15368c2ecf20Sopenharmony_ci "Local", 15378c2ecf20Sopenharmony_ci "Global and Local" 15388c2ecf20Sopenharmony_ci }; 15398c2ecf20Sopenharmony_ci static const char * const pixel_format[16] = { 15408c2ecf20Sopenharmony_ci "ARGB Indexed", 15418c2ecf20Sopenharmony_ci "RGB 5:6:5", 15428c2ecf20Sopenharmony_ci "ARGB 1:5:5:5", 15438c2ecf20Sopenharmony_ci "ARGB 1:4:4:4", 15448c2ecf20Sopenharmony_ci "ARGB 8:8:8:8", 15458c2ecf20Sopenharmony_ci "5", 15468c2ecf20Sopenharmony_ci "6", 15478c2ecf20Sopenharmony_ci "7", 15488c2ecf20Sopenharmony_ci "AYUV Indexed", 15498c2ecf20Sopenharmony_ci "YUV 5:6:5", 15508c2ecf20Sopenharmony_ci "AYUV 1:5:5:5", 15518c2ecf20Sopenharmony_ci "AYUV 1:4:4:4", 15528c2ecf20Sopenharmony_ci "AYUV 8:8:8:8", 15538c2ecf20Sopenharmony_ci "13", 15548c2ecf20Sopenharmony_ci "14", 15558c2ecf20Sopenharmony_ci "15", 15568c2ecf20Sopenharmony_ci }; 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci ivtv_get_output(itv, itv->active_output, &vidout); 15598c2ecf20Sopenharmony_ci ivtv_get_audio_output(itv, 0, &audout); 15608c2ecf20Sopenharmony_ci IVTV_INFO("Video Output: %s\n", vidout.name); 15618c2ecf20Sopenharmony_ci if (mode < 0 || mode > OUT_PASSTHROUGH) 15628c2ecf20Sopenharmony_ci mode = OUT_NONE; 15638c2ecf20Sopenharmony_ci IVTV_INFO("Output Mode: %s\n", output_modes[mode]); 15648c2ecf20Sopenharmony_ci ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0); 15658c2ecf20Sopenharmony_ci data[0] |= (read_reg(0x2a00) >> 7) & 0x40; 15668c2ecf20Sopenharmony_ci IVTV_INFO("Overlay: %s, Alpha: %s, Pixel Format: %s\n", 15678c2ecf20Sopenharmony_ci data[0] & 1 ? "On" : "Off", 15688c2ecf20Sopenharmony_ci alpha_mode[(data[0] >> 1) & 0x3], 15698c2ecf20Sopenharmony_ci pixel_format[(data[0] >> 3) & 0xf]); 15708c2ecf20Sopenharmony_ci } 15718c2ecf20Sopenharmony_ci IVTV_INFO("Tuner: %s\n", 15728c2ecf20Sopenharmony_ci test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV"); 15738c2ecf20Sopenharmony_ci v4l2_ctrl_handler_log_status(&itv->cxhdl.hdl, itv->v4l2_dev.name); 15748c2ecf20Sopenharmony_ci IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags); 15758c2ecf20Sopenharmony_ci for (i = 0; i < IVTV_MAX_STREAMS; i++) { 15768c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[i]; 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci if (s->vdev.v4l2_dev == NULL || s->buffers == 0) 15798c2ecf20Sopenharmony_ci continue; 15808c2ecf20Sopenharmony_ci IVTV_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags, 15818c2ecf20Sopenharmony_ci (s->buffers - s->q_free.buffers) * 100 / s->buffers, 15828c2ecf20Sopenharmony_ci (s->buffers * s->buf_size) / 1024, s->buffers); 15838c2ecf20Sopenharmony_ci } 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", 15868c2ecf20Sopenharmony_ci (long long)itv->mpg_data_received, 15878c2ecf20Sopenharmony_ci (long long)itv->vbi_data_inserted); 15888c2ecf20Sopenharmony_ci return 0; 15898c2ecf20Sopenharmony_ci} 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_cistatic int ivtv_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec) 15928c2ecf20Sopenharmony_ci{ 15938c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(file->private_data); 15948c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci IVTV_DEBUG_IOCTL("VIDIOC_DECODER_CMD %d\n", dec->cmd); 15978c2ecf20Sopenharmony_ci return ivtv_video_command(itv, id, dec, false); 15988c2ecf20Sopenharmony_ci} 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_cistatic int ivtv_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec) 16018c2ecf20Sopenharmony_ci{ 16028c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(file->private_data); 16038c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci IVTV_DEBUG_IOCTL("VIDIOC_TRY_DECODER_CMD %d\n", dec->cmd); 16068c2ecf20Sopenharmony_ci return ivtv_video_command(itv, id, dec, true); 16078c2ecf20Sopenharmony_ci} 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS 16108c2ecf20Sopenharmony_cistatic __inline__ void warn_deprecated_ioctl(const char *name) 16118c2ecf20Sopenharmony_ci{ 16128c2ecf20Sopenharmony_ci pr_warn_once("warning: the %s ioctl is deprecated. Don't use it, as it will be removed soon\n", 16138c2ecf20Sopenharmony_ci name); 16148c2ecf20Sopenharmony_ci} 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 16178c2ecf20Sopenharmony_cistruct compat_video_event { 16188c2ecf20Sopenharmony_ci __s32 type; 16198c2ecf20Sopenharmony_ci /* unused, make sure to use atomic time for y2038 if it ever gets used */ 16208c2ecf20Sopenharmony_ci compat_long_t timestamp; 16218c2ecf20Sopenharmony_ci union { 16228c2ecf20Sopenharmony_ci video_size_t size; 16238c2ecf20Sopenharmony_ci unsigned int frame_rate; /* in frames per 1000sec */ 16248c2ecf20Sopenharmony_ci unsigned char vsync_field; /* unknown/odd/even/progressive */ 16258c2ecf20Sopenharmony_ci } u; 16268c2ecf20Sopenharmony_ci}; 16278c2ecf20Sopenharmony_ci#define VIDEO_GET_EVENT32 _IOR('o', 28, struct compat_video_event) 16288c2ecf20Sopenharmony_ci#endif 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci#endif 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_cistatic int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) 16338c2ecf20Sopenharmony_ci{ 16348c2ecf20Sopenharmony_ci struct ivtv_open_id *id = fh2id(filp->private_data); 16358c2ecf20Sopenharmony_ci struct ivtv *itv = id->itv; 16368c2ecf20Sopenharmony_ci struct ivtv_stream *s = &itv->streams[id->type]; 16378c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS 16388c2ecf20Sopenharmony_ci int nonblocking = filp->f_flags & O_NONBLOCK; 16398c2ecf20Sopenharmony_ci unsigned long iarg = (unsigned long)arg; 16408c2ecf20Sopenharmony_ci#endif 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci switch (cmd) { 16438c2ecf20Sopenharmony_ci case IVTV_IOC_DMA_FRAME: { 16448c2ecf20Sopenharmony_ci struct ivtv_dma_frame *args = arg; 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci IVTV_DEBUG_IOCTL("IVTV_IOC_DMA_FRAME\n"); 16478c2ecf20Sopenharmony_ci if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) 16488c2ecf20Sopenharmony_ci return -EINVAL; 16498c2ecf20Sopenharmony_ci if (args->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 16508c2ecf20Sopenharmony_ci return -EINVAL; 16518c2ecf20Sopenharmony_ci if (itv->output_mode == OUT_UDMA_YUV && args->y_source == NULL) 16528c2ecf20Sopenharmony_ci return 0; 16538c2ecf20Sopenharmony_ci if (ivtv_start_decoding(id, id->type)) { 16548c2ecf20Sopenharmony_ci return -EBUSY; 16558c2ecf20Sopenharmony_ci } 16568c2ecf20Sopenharmony_ci if (ivtv_set_output_mode(itv, OUT_UDMA_YUV) != OUT_UDMA_YUV) { 16578c2ecf20Sopenharmony_ci ivtv_release_stream(s); 16588c2ecf20Sopenharmony_ci return -EBUSY; 16598c2ecf20Sopenharmony_ci } 16608c2ecf20Sopenharmony_ci /* Mark that this file handle started the UDMA_YUV mode */ 16618c2ecf20Sopenharmony_ci id->yuv_frames = 1; 16628c2ecf20Sopenharmony_ci if (args->y_source == NULL) 16638c2ecf20Sopenharmony_ci return 0; 16648c2ecf20Sopenharmony_ci return ivtv_yuv_prep_frame(itv, args); 16658c2ecf20Sopenharmony_ci } 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci case IVTV_IOC_PASSTHROUGH_MODE: 16688c2ecf20Sopenharmony_ci IVTV_DEBUG_IOCTL("IVTV_IOC_PASSTHROUGH_MODE\n"); 16698c2ecf20Sopenharmony_ci if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) 16708c2ecf20Sopenharmony_ci return -EINVAL; 16718c2ecf20Sopenharmony_ci return ivtv_passthrough_mode(itv, *(int *)arg != 0); 16728c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS 16738c2ecf20Sopenharmony_ci case VIDEO_GET_PTS: { 16748c2ecf20Sopenharmony_ci s64 *pts = arg; 16758c2ecf20Sopenharmony_ci s64 frame; 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci warn_deprecated_ioctl("VIDEO_GET_PTS"); 16788c2ecf20Sopenharmony_ci if (s->type < IVTV_DEC_STREAM_TYPE_MPG) { 16798c2ecf20Sopenharmony_ci *pts = s->dma_pts; 16808c2ecf20Sopenharmony_ci break; 16818c2ecf20Sopenharmony_ci } 16828c2ecf20Sopenharmony_ci if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) 16838c2ecf20Sopenharmony_ci return -EINVAL; 16848c2ecf20Sopenharmony_ci return ivtv_g_pts_frame(itv, pts, &frame); 16858c2ecf20Sopenharmony_ci } 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci case VIDEO_GET_FRAME_COUNT: { 16888c2ecf20Sopenharmony_ci s64 *frame = arg; 16898c2ecf20Sopenharmony_ci s64 pts; 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci warn_deprecated_ioctl("VIDEO_GET_FRAME_COUNT"); 16928c2ecf20Sopenharmony_ci if (s->type < IVTV_DEC_STREAM_TYPE_MPG) { 16938c2ecf20Sopenharmony_ci *frame = 0; 16948c2ecf20Sopenharmony_ci break; 16958c2ecf20Sopenharmony_ci } 16968c2ecf20Sopenharmony_ci if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) 16978c2ecf20Sopenharmony_ci return -EINVAL; 16988c2ecf20Sopenharmony_ci return ivtv_g_pts_frame(itv, &pts, frame); 16998c2ecf20Sopenharmony_ci } 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci case VIDEO_PLAY: { 17028c2ecf20Sopenharmony_ci struct v4l2_decoder_cmd dc; 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci warn_deprecated_ioctl("VIDEO_PLAY"); 17058c2ecf20Sopenharmony_ci memset(&dc, 0, sizeof(dc)); 17068c2ecf20Sopenharmony_ci dc.cmd = V4L2_DEC_CMD_START; 17078c2ecf20Sopenharmony_ci return ivtv_video_command(itv, id, &dc, 0); 17088c2ecf20Sopenharmony_ci } 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci case VIDEO_STOP: { 17118c2ecf20Sopenharmony_ci struct v4l2_decoder_cmd dc; 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci warn_deprecated_ioctl("VIDEO_STOP"); 17148c2ecf20Sopenharmony_ci memset(&dc, 0, sizeof(dc)); 17158c2ecf20Sopenharmony_ci dc.cmd = V4L2_DEC_CMD_STOP; 17168c2ecf20Sopenharmony_ci dc.flags = V4L2_DEC_CMD_STOP_TO_BLACK | V4L2_DEC_CMD_STOP_IMMEDIATELY; 17178c2ecf20Sopenharmony_ci return ivtv_video_command(itv, id, &dc, 0); 17188c2ecf20Sopenharmony_ci } 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci case VIDEO_FREEZE: { 17218c2ecf20Sopenharmony_ci struct v4l2_decoder_cmd dc; 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci warn_deprecated_ioctl("VIDEO_FREEZE"); 17248c2ecf20Sopenharmony_ci memset(&dc, 0, sizeof(dc)); 17258c2ecf20Sopenharmony_ci dc.cmd = V4L2_DEC_CMD_PAUSE; 17268c2ecf20Sopenharmony_ci return ivtv_video_command(itv, id, &dc, 0); 17278c2ecf20Sopenharmony_ci } 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci case VIDEO_CONTINUE: { 17308c2ecf20Sopenharmony_ci struct v4l2_decoder_cmd dc; 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci warn_deprecated_ioctl("VIDEO_CONTINUE"); 17338c2ecf20Sopenharmony_ci memset(&dc, 0, sizeof(dc)); 17348c2ecf20Sopenharmony_ci dc.cmd = V4L2_DEC_CMD_RESUME; 17358c2ecf20Sopenharmony_ci return ivtv_video_command(itv, id, &dc, 0); 17368c2ecf20Sopenharmony_ci } 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci case VIDEO_COMMAND: 17398c2ecf20Sopenharmony_ci case VIDEO_TRY_COMMAND: { 17408c2ecf20Sopenharmony_ci /* Note: struct v4l2_decoder_cmd has the same layout as 17418c2ecf20Sopenharmony_ci struct video_command */ 17428c2ecf20Sopenharmony_ci struct v4l2_decoder_cmd *dc = arg; 17438c2ecf20Sopenharmony_ci int try = (cmd == VIDEO_TRY_COMMAND); 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci if (try) 17468c2ecf20Sopenharmony_ci warn_deprecated_ioctl("VIDEO_TRY_COMMAND"); 17478c2ecf20Sopenharmony_ci else 17488c2ecf20Sopenharmony_ci warn_deprecated_ioctl("VIDEO_COMMAND"); 17498c2ecf20Sopenharmony_ci return ivtv_video_command(itv, id, dc, try); 17508c2ecf20Sopenharmony_ci } 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 17538c2ecf20Sopenharmony_ci case VIDEO_GET_EVENT32: 17548c2ecf20Sopenharmony_ci#endif 17558c2ecf20Sopenharmony_ci case VIDEO_GET_EVENT: { 17568c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 17578c2ecf20Sopenharmony_ci struct compat_video_event *ev32 = arg; 17588c2ecf20Sopenharmony_ci#endif 17598c2ecf20Sopenharmony_ci struct video_event *ev = arg; 17608c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci warn_deprecated_ioctl("VIDEO_GET_EVENT"); 17638c2ecf20Sopenharmony_ci if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) 17648c2ecf20Sopenharmony_ci return -EINVAL; 17658c2ecf20Sopenharmony_ci memset(ev, 0, sizeof(*ev)); 17668c2ecf20Sopenharmony_ci set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags); 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci while (1) { 17698c2ecf20Sopenharmony_ci if (test_and_clear_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags)) 17708c2ecf20Sopenharmony_ci ev->type = VIDEO_EVENT_DECODER_STOPPED; 17718c2ecf20Sopenharmony_ci else if (test_and_clear_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags)) { 17728c2ecf20Sopenharmony_ci unsigned char vsync_field; 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci ev->type = VIDEO_EVENT_VSYNC; 17758c2ecf20Sopenharmony_ci vsync_field = test_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags) ? 17768c2ecf20Sopenharmony_ci VIDEO_VSYNC_FIELD_ODD : VIDEO_VSYNC_FIELD_EVEN; 17778c2ecf20Sopenharmony_ci if (itv->output_mode == OUT_UDMA_YUV && 17788c2ecf20Sopenharmony_ci (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) == 17798c2ecf20Sopenharmony_ci IVTV_YUV_MODE_PROGRESSIVE) { 17808c2ecf20Sopenharmony_ci vsync_field = VIDEO_VSYNC_FIELD_PROGRESSIVE; 17818c2ecf20Sopenharmony_ci } 17828c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 17838c2ecf20Sopenharmony_ci if (cmd == VIDEO_GET_EVENT32) 17848c2ecf20Sopenharmony_ci ev32->u.vsync_field = vsync_field; 17858c2ecf20Sopenharmony_ci else 17868c2ecf20Sopenharmony_ci#endif 17878c2ecf20Sopenharmony_ci ev->u.vsync_field = vsync_field; 17888c2ecf20Sopenharmony_ci } 17898c2ecf20Sopenharmony_ci if (ev->type) 17908c2ecf20Sopenharmony_ci return 0; 17918c2ecf20Sopenharmony_ci if (nonblocking) 17928c2ecf20Sopenharmony_ci return -EAGAIN; 17938c2ecf20Sopenharmony_ci /* Wait for event. Note that serialize_lock is locked, 17948c2ecf20Sopenharmony_ci so to allow other processes to access the driver while 17958c2ecf20Sopenharmony_ci we are waiting unlock first and later lock again. */ 17968c2ecf20Sopenharmony_ci mutex_unlock(&itv->serialize_lock); 17978c2ecf20Sopenharmony_ci prepare_to_wait(&itv->event_waitq, &wait, TASK_INTERRUPTIBLE); 17988c2ecf20Sopenharmony_ci if (!test_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags) && 17998c2ecf20Sopenharmony_ci !test_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags)) 18008c2ecf20Sopenharmony_ci schedule(); 18018c2ecf20Sopenharmony_ci finish_wait(&itv->event_waitq, &wait); 18028c2ecf20Sopenharmony_ci mutex_lock(&itv->serialize_lock); 18038c2ecf20Sopenharmony_ci if (signal_pending(current)) { 18048c2ecf20Sopenharmony_ci /* return if a signal was received */ 18058c2ecf20Sopenharmony_ci IVTV_DEBUG_INFO("User stopped wait for event\n"); 18068c2ecf20Sopenharmony_ci return -EINTR; 18078c2ecf20Sopenharmony_ci } 18088c2ecf20Sopenharmony_ci } 18098c2ecf20Sopenharmony_ci break; 18108c2ecf20Sopenharmony_ci } 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci case VIDEO_SELECT_SOURCE: 18138c2ecf20Sopenharmony_ci warn_deprecated_ioctl("VIDEO_SELECT_SOURCE"); 18148c2ecf20Sopenharmony_ci if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) 18158c2ecf20Sopenharmony_ci return -EINVAL; 18168c2ecf20Sopenharmony_ci return ivtv_passthrough_mode(itv, iarg == VIDEO_SOURCE_DEMUX); 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci case AUDIO_SET_MUTE: 18198c2ecf20Sopenharmony_ci warn_deprecated_ioctl("AUDIO_SET_MUTE"); 18208c2ecf20Sopenharmony_ci itv->speed_mute_audio = iarg; 18218c2ecf20Sopenharmony_ci return 0; 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci case AUDIO_CHANNEL_SELECT: 18248c2ecf20Sopenharmony_ci warn_deprecated_ioctl("AUDIO_CHANNEL_SELECT"); 18258c2ecf20Sopenharmony_ci if (iarg > AUDIO_STEREO_SWAPPED) 18268c2ecf20Sopenharmony_ci return -EINVAL; 18278c2ecf20Sopenharmony_ci return v4l2_ctrl_s_ctrl(itv->ctrl_audio_playback, iarg + 1); 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci case AUDIO_BILINGUAL_CHANNEL_SELECT: 18308c2ecf20Sopenharmony_ci warn_deprecated_ioctl("AUDIO_BILINGUAL_CHANNEL_SELECT"); 18318c2ecf20Sopenharmony_ci if (iarg > AUDIO_STEREO_SWAPPED) 18328c2ecf20Sopenharmony_ci return -EINVAL; 18338c2ecf20Sopenharmony_ci return v4l2_ctrl_s_ctrl(itv->ctrl_audio_multilingual_playback, iarg + 1); 18348c2ecf20Sopenharmony_ci#endif 18358c2ecf20Sopenharmony_ci default: 18368c2ecf20Sopenharmony_ci return -EINVAL; 18378c2ecf20Sopenharmony_ci } 18388c2ecf20Sopenharmony_ci return 0; 18398c2ecf20Sopenharmony_ci} 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_cistatic long ivtv_default(struct file *file, void *fh, bool valid_prio, 18428c2ecf20Sopenharmony_ci unsigned int cmd, void *arg) 18438c2ecf20Sopenharmony_ci{ 18448c2ecf20Sopenharmony_ci struct ivtv *itv = fh2id(fh)->itv; 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci if (!valid_prio) { 18478c2ecf20Sopenharmony_ci switch (cmd) { 18488c2ecf20Sopenharmony_ci case IVTV_IOC_PASSTHROUGH_MODE: 18498c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS 18508c2ecf20Sopenharmony_ci case VIDEO_PLAY: 18518c2ecf20Sopenharmony_ci case VIDEO_STOP: 18528c2ecf20Sopenharmony_ci case VIDEO_FREEZE: 18538c2ecf20Sopenharmony_ci case VIDEO_CONTINUE: 18548c2ecf20Sopenharmony_ci case VIDEO_COMMAND: 18558c2ecf20Sopenharmony_ci case VIDEO_SELECT_SOURCE: 18568c2ecf20Sopenharmony_ci case AUDIO_SET_MUTE: 18578c2ecf20Sopenharmony_ci case AUDIO_CHANNEL_SELECT: 18588c2ecf20Sopenharmony_ci case AUDIO_BILINGUAL_CHANNEL_SELECT: 18598c2ecf20Sopenharmony_ci#endif 18608c2ecf20Sopenharmony_ci return -EBUSY; 18618c2ecf20Sopenharmony_ci } 18628c2ecf20Sopenharmony_ci } 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci switch (cmd) { 18658c2ecf20Sopenharmony_ci case VIDIOC_INT_RESET: { 18668c2ecf20Sopenharmony_ci u32 val = *(u32 *)arg; 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci if ((val == 0 && itv->options.newi2c) || (val & 0x01)) 18698c2ecf20Sopenharmony_ci ivtv_reset_ir_gpio(itv); 18708c2ecf20Sopenharmony_ci if (val & 0x02) 18718c2ecf20Sopenharmony_ci v4l2_subdev_call(itv->sd_video, core, reset, 0); 18728c2ecf20Sopenharmony_ci break; 18738c2ecf20Sopenharmony_ci } 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci case IVTV_IOC_DMA_FRAME: 18768c2ecf20Sopenharmony_ci case IVTV_IOC_PASSTHROUGH_MODE: 18778c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_IVTV_DEPRECATED_IOCTLS 18788c2ecf20Sopenharmony_ci case VIDEO_GET_PTS: 18798c2ecf20Sopenharmony_ci case VIDEO_GET_FRAME_COUNT: 18808c2ecf20Sopenharmony_ci case VIDEO_GET_EVENT: 18818c2ecf20Sopenharmony_ci case VIDEO_PLAY: 18828c2ecf20Sopenharmony_ci case VIDEO_STOP: 18838c2ecf20Sopenharmony_ci case VIDEO_FREEZE: 18848c2ecf20Sopenharmony_ci case VIDEO_CONTINUE: 18858c2ecf20Sopenharmony_ci case VIDEO_COMMAND: 18868c2ecf20Sopenharmony_ci case VIDEO_TRY_COMMAND: 18878c2ecf20Sopenharmony_ci case VIDEO_SELECT_SOURCE: 18888c2ecf20Sopenharmony_ci case AUDIO_SET_MUTE: 18898c2ecf20Sopenharmony_ci case AUDIO_CHANNEL_SELECT: 18908c2ecf20Sopenharmony_ci case AUDIO_BILINGUAL_CHANNEL_SELECT: 18918c2ecf20Sopenharmony_ci#endif 18928c2ecf20Sopenharmony_ci return ivtv_decoder_ioctls(file, cmd, (void *)arg); 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci default: 18958c2ecf20Sopenharmony_ci return -ENOTTY; 18968c2ecf20Sopenharmony_ci } 18978c2ecf20Sopenharmony_ci return 0; 18988c2ecf20Sopenharmony_ci} 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_cistatic const struct v4l2_ioctl_ops ivtv_ioctl_ops = { 19018c2ecf20Sopenharmony_ci .vidioc_querycap = ivtv_querycap, 19028c2ecf20Sopenharmony_ci .vidioc_s_audio = ivtv_s_audio, 19038c2ecf20Sopenharmony_ci .vidioc_g_audio = ivtv_g_audio, 19048c2ecf20Sopenharmony_ci .vidioc_enumaudio = ivtv_enumaudio, 19058c2ecf20Sopenharmony_ci .vidioc_s_audout = ivtv_s_audout, 19068c2ecf20Sopenharmony_ci .vidioc_g_audout = ivtv_g_audout, 19078c2ecf20Sopenharmony_ci .vidioc_enum_input = ivtv_enum_input, 19088c2ecf20Sopenharmony_ci .vidioc_enum_output = ivtv_enum_output, 19098c2ecf20Sopenharmony_ci .vidioc_enumaudout = ivtv_enumaudout, 19108c2ecf20Sopenharmony_ci .vidioc_g_pixelaspect = ivtv_g_pixelaspect, 19118c2ecf20Sopenharmony_ci .vidioc_s_selection = ivtv_s_selection, 19128c2ecf20Sopenharmony_ci .vidioc_g_selection = ivtv_g_selection, 19138c2ecf20Sopenharmony_ci .vidioc_g_input = ivtv_g_input, 19148c2ecf20Sopenharmony_ci .vidioc_s_input = ivtv_s_input, 19158c2ecf20Sopenharmony_ci .vidioc_g_output = ivtv_g_output, 19168c2ecf20Sopenharmony_ci .vidioc_s_output = ivtv_s_output, 19178c2ecf20Sopenharmony_ci .vidioc_g_frequency = ivtv_g_frequency, 19188c2ecf20Sopenharmony_ci .vidioc_s_frequency = ivtv_s_frequency, 19198c2ecf20Sopenharmony_ci .vidioc_s_tuner = ivtv_s_tuner, 19208c2ecf20Sopenharmony_ci .vidioc_g_tuner = ivtv_g_tuner, 19218c2ecf20Sopenharmony_ci .vidioc_g_enc_index = ivtv_g_enc_index, 19228c2ecf20Sopenharmony_ci .vidioc_g_fbuf = ivtv_g_fbuf, 19238c2ecf20Sopenharmony_ci .vidioc_s_fbuf = ivtv_s_fbuf, 19248c2ecf20Sopenharmony_ci .vidioc_g_std = ivtv_g_std, 19258c2ecf20Sopenharmony_ci .vidioc_s_std = ivtv_s_std, 19268c2ecf20Sopenharmony_ci .vidioc_overlay = ivtv_overlay, 19278c2ecf20Sopenharmony_ci .vidioc_log_status = ivtv_log_status, 19288c2ecf20Sopenharmony_ci .vidioc_enum_fmt_vid_cap = ivtv_enum_fmt_vid_cap, 19298c2ecf20Sopenharmony_ci .vidioc_encoder_cmd = ivtv_encoder_cmd, 19308c2ecf20Sopenharmony_ci .vidioc_try_encoder_cmd = ivtv_try_encoder_cmd, 19318c2ecf20Sopenharmony_ci .vidioc_decoder_cmd = ivtv_decoder_cmd, 19328c2ecf20Sopenharmony_ci .vidioc_try_decoder_cmd = ivtv_try_decoder_cmd, 19338c2ecf20Sopenharmony_ci .vidioc_enum_fmt_vid_out = ivtv_enum_fmt_vid_out, 19348c2ecf20Sopenharmony_ci .vidioc_g_fmt_vid_cap = ivtv_g_fmt_vid_cap, 19358c2ecf20Sopenharmony_ci .vidioc_g_fmt_vbi_cap = ivtv_g_fmt_vbi_cap, 19368c2ecf20Sopenharmony_ci .vidioc_g_fmt_sliced_vbi_cap = ivtv_g_fmt_sliced_vbi_cap, 19378c2ecf20Sopenharmony_ci .vidioc_g_fmt_vid_out = ivtv_g_fmt_vid_out, 19388c2ecf20Sopenharmony_ci .vidioc_g_fmt_vid_out_overlay = ivtv_g_fmt_vid_out_overlay, 19398c2ecf20Sopenharmony_ci .vidioc_g_fmt_sliced_vbi_out = ivtv_g_fmt_sliced_vbi_out, 19408c2ecf20Sopenharmony_ci .vidioc_s_fmt_vid_cap = ivtv_s_fmt_vid_cap, 19418c2ecf20Sopenharmony_ci .vidioc_s_fmt_vbi_cap = ivtv_s_fmt_vbi_cap, 19428c2ecf20Sopenharmony_ci .vidioc_s_fmt_sliced_vbi_cap = ivtv_s_fmt_sliced_vbi_cap, 19438c2ecf20Sopenharmony_ci .vidioc_s_fmt_vid_out = ivtv_s_fmt_vid_out, 19448c2ecf20Sopenharmony_ci .vidioc_s_fmt_vid_out_overlay = ivtv_s_fmt_vid_out_overlay, 19458c2ecf20Sopenharmony_ci .vidioc_s_fmt_sliced_vbi_out = ivtv_s_fmt_sliced_vbi_out, 19468c2ecf20Sopenharmony_ci .vidioc_try_fmt_vid_cap = ivtv_try_fmt_vid_cap, 19478c2ecf20Sopenharmony_ci .vidioc_try_fmt_vbi_cap = ivtv_try_fmt_vbi_cap, 19488c2ecf20Sopenharmony_ci .vidioc_try_fmt_sliced_vbi_cap = ivtv_try_fmt_sliced_vbi_cap, 19498c2ecf20Sopenharmony_ci .vidioc_try_fmt_vid_out = ivtv_try_fmt_vid_out, 19508c2ecf20Sopenharmony_ci .vidioc_try_fmt_vid_out_overlay = ivtv_try_fmt_vid_out_overlay, 19518c2ecf20Sopenharmony_ci .vidioc_try_fmt_sliced_vbi_out = ivtv_try_fmt_sliced_vbi_out, 19528c2ecf20Sopenharmony_ci .vidioc_g_sliced_vbi_cap = ivtv_g_sliced_vbi_cap, 19538c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG 19548c2ecf20Sopenharmony_ci .vidioc_g_register = ivtv_g_register, 19558c2ecf20Sopenharmony_ci .vidioc_s_register = ivtv_s_register, 19568c2ecf20Sopenharmony_ci#endif 19578c2ecf20Sopenharmony_ci .vidioc_default = ivtv_default, 19588c2ecf20Sopenharmony_ci .vidioc_subscribe_event = ivtv_subscribe_event, 19598c2ecf20Sopenharmony_ci .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 19608c2ecf20Sopenharmony_ci}; 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_civoid ivtv_set_funcs(struct video_device *vdev) 19638c2ecf20Sopenharmony_ci{ 19648c2ecf20Sopenharmony_ci vdev->ioctl_ops = &ivtv_ioctl_ops; 19658c2ecf20Sopenharmony_ci} 1966