⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ivtv-ioctl.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/*    ioctl system call    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>    This program is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 2 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#include "ivtv-driver.h"#include "ivtv-version.h"#include "ivtv-mailbox.h"#include "ivtv-i2c.h"#include "ivtv-queue.h"#include "ivtv-fileops.h"#include "ivtv-vbi.h"#include "ivtv-routing.h"#include "ivtv-streams.h"#include "ivtv-yuv.h"#include "ivtv-ioctl.h"#include "ivtv-gpio.h"#include "ivtv-controls.h"#include "ivtv-cards.h"#include <media/saa7127.h>#include <media/tveeprom.h>#include <media/v4l2-chip-ident.h>#include <linux/dvb/audio.h>#include <linux/i2c-id.h>u16 service2vbi(int type){	switch (type) {		case V4L2_SLICED_TELETEXT_B:			return IVTV_SLICED_TYPE_TELETEXT_B;		case V4L2_SLICED_CAPTION_525:			return IVTV_SLICED_TYPE_CAPTION_525;		case V4L2_SLICED_WSS_625:			return IVTV_SLICED_TYPE_WSS_625;		case V4L2_SLICED_VPS:			return IVTV_SLICED_TYPE_VPS;		default:			return 0;	}}static int valid_service_line(int field, int line, int is_pal){	return (is_pal && line >= 6 && (line != 23 || field == 0)) ||	       (!is_pal && line >= 10 && line < 22);}static u16 select_service_from_set(int field, int line, u16 set, int is_pal){	u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525);	int i;	set = set & valid_set;	if (set == 0 || !valid_service_line(field, line, is_pal)) {		return 0;	}	if (!is_pal) {		if (line == 21 && (set & V4L2_SLICED_CAPTION_525))			return V4L2_SLICED_CAPTION_525;	}	else {		if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS))			return V4L2_SLICED_VPS;		if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625))			return V4L2_SLICED_WSS_625;		if (line == 23)			return 0;	}	for (i = 0; i < 32; i++) {		if ((1 << i) & set)			return 1 << i;	}	return 0;}void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal){	u16 set = fmt->service_set;	int f, l;	fmt->service_set = 0;	for (f = 0; f < 2; f++) {		for (l = 0; l < 24; l++) {			fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal);		}	}}static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal){	int f, l;	u16 set = 0;	for (f = 0; f < 2; f++) {		for (l = 0; l < 24; l++) {			fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal);			set |= fmt->service_lines[f][l];		}	}	return set != 0;}u16 get_service_set(struct v4l2_sliced_vbi_format *fmt){	int f, l;	u16 set = 0;	for (f = 0; f < 2; f++) {		for (l = 0; l < 24; l++) {			set |= fmt->service_lines[f][l];		}	}	return set;}static const struct {	v4l2_std_id  std;	char        *name;} enum_stds[] = {	{ V4L2_STD_PAL_BG | V4L2_STD_PAL_H, "PAL-BGH" },	{ V4L2_STD_PAL_DK,    "PAL-DK"    },	{ V4L2_STD_PAL_I,     "PAL-I"     },	{ V4L2_STD_PAL_M,     "PAL-M"     },	{ V4L2_STD_PAL_N,     "PAL-N"     },	{ V4L2_STD_PAL_Nc,    "PAL-Nc"    },	{ V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, "SECAM-BGH" },	{ V4L2_STD_SECAM_DK,  "SECAM-DK"  },	{ V4L2_STD_SECAM_L,   "SECAM-L"   },	{ V4L2_STD_SECAM_LC,  "SECAM-L'"  },	{ V4L2_STD_NTSC_M,    "NTSC-M"    },	{ V4L2_STD_NTSC_M_JP, "NTSC-J"    },	{ V4L2_STD_NTSC_M_KR, "NTSC-K"    },};static const struct v4l2_standard ivtv_std_60hz ={	.frameperiod = {.numerator = 1001, .denominator = 30000},	.framelines = 525,};static const struct v4l2_standard ivtv_std_50hz ={	.frameperiod = {.numerator = 1, .denominator = 25},	.framelines = 625,};void ivtv_set_osd_alpha(struct ivtv *itv){	ivtv_vapi(itv, CX2341X_OSD_SET_GLOBAL_ALPHA, 3,		itv->osd_global_alpha_state, itv->osd_global_alpha, !itv->osd_local_alpha_state);	ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_chroma_key_state, itv->osd_chroma_key);}int ivtv_set_speed(struct ivtv *itv, int speed){	u32 data[CX2341X_MBOX_MAX_DATA];	struct ivtv_stream *s;	int single_step = (speed == 1 || speed == -1);	DEFINE_WAIT(wait);	if (speed == 0) speed = 1000;	/* No change? */	if (speed == itv->speed && !single_step)		return 0;	s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];	if (single_step && (speed < 0) == (itv->speed < 0)) {		/* Single step video and no need to change direction */		ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0);		itv->speed = speed;		return 0;	}	if (single_step)		/* Need to change direction */		speed = speed < 0 ? -1000 : 1000;	data[0] = (speed > 1000 || speed < -1000) ? 0x80000000 : 0;	data[0] |= (speed > 1000 || speed < -1500) ? 0x40000000 : 0;	data[1] = (speed < 0);	data[2] = speed < 0 ? 3 : 7;	data[3] = itv->params.video_b_frames;	data[4] = (speed == 1500 || speed == 500) ? itv->speed_mute_audio : 0;	data[5] = 0;	data[6] = 0;	if (speed == 1500 || speed == -1500) data[0] |= 1;	else if (speed == 2000 || speed == -2000) data[0] |= 2;	else if (speed > -1000 && speed < 0) data[0] |= (-1000 / speed);	else if (speed < 1000 && speed > 0) data[0] |= (1000 / speed);	/* If not decoding, just change speed setting */	if (atomic_read(&itv->decoding) > 0) {		int got_sig = 0;		/* Stop all DMA and decoding activity */		ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, 0);		/* Wait for any DMA to finish */		prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);		while (itv->i_flags & IVTV_F_I_DMA) {			got_sig = signal_pending(current);			if (got_sig)				break;			got_sig = 0;			schedule();		}		finish_wait(&itv->dma_waitq, &wait);		if (got_sig)			return -EINTR;		/* Change Speed safely */		ivtv_api(itv, CX2341X_DEC_SET_PLAYBACK_SPEED, 7, data);		IVTV_DEBUG_INFO("Setting Speed to 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",				data[0], data[1], data[2], data[3], data[4], data[5], data[6]);	}	if (single_step) {		speed = (speed < 0) ? -1 : 1;		ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0);	}	itv->speed = speed;	return 0;}static int ivtv_validate_speed(int cur_speed, int new_speed){	int fact = new_speed < 0 ? -1 : 1;	int s;	if (new_speed < 0) new_speed = -new_speed;	if (cur_speed < 0) cur_speed = -cur_speed;	if (cur_speed <= new_speed) {		if (new_speed > 1500) return fact * 2000;		if (new_speed > 1000) return fact * 1500;	}	else {		if (new_speed >= 2000) return fact * 2000;		if (new_speed >= 1500) return fact * 1500;		if (new_speed >= 1000) return fact * 1000;	}	if (new_speed == 0) return 1000;	if (new_speed == 1 || new_speed == 1000) return fact * new_speed;	s = new_speed;	new_speed = 1000 / new_speed;	if (1000 / cur_speed == new_speed)		new_speed += (cur_speed < s) ? -1 : 1;	if (new_speed > 60) return 1000 / (fact * 60);	return 1000 / (fact * new_speed);}static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id,		struct video_command *vc, int try){	struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))		return -EINVAL;	switch (vc->cmd) {	case VIDEO_CMD_PLAY: {		vc->flags = 0;		vc->play.speed = ivtv_validate_speed(itv->speed, vc->play.speed);		if (vc->play.speed < 0)			vc->play.format = VIDEO_PLAY_FMT_GOP;		if (try) break;		if (ivtv_set_output_mode(itv, OUT_MPG) != OUT_MPG)			return -EBUSY;		if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) {			/* forces ivtv_set_speed to be called */			itv->speed = 0;		}		return ivtv_start_decoding(id, vc->play.speed);	}	case VIDEO_CMD_STOP:		vc->flags &= VIDEO_CMD_STOP_IMMEDIATELY|VIDEO_CMD_STOP_TO_BLACK;		if (vc->flags & VIDEO_CMD_STOP_IMMEDIATELY)			vc->stop.pts = 0;		if (try) break;		if (atomic_read(&itv->decoding) == 0)			return 0;		if (itv->output_mode != OUT_MPG)			return -EBUSY;		itv->output_mode = OUT_NONE;		return ivtv_stop_v4l2_decode_stream(s, vc->flags, vc->stop.pts);	case VIDEO_CMD_FREEZE:		vc->flags &= VIDEO_CMD_FREEZE_TO_BLACK;		if (try) break;		if (itv->output_mode != OUT_MPG)			return -EBUSY;		if (atomic_read(&itv->decoding) > 0) {			ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1,				(vc->flags & VIDEO_CMD_FREEZE_TO_BLACK) ? 1 : 0);			set_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags);		}		break;	case VIDEO_CMD_CONTINUE:		vc->flags = 0;		if (try) break;		if (itv->output_mode != OUT_MPG)			return -EBUSY;		if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) {			int speed = itv->speed;			itv->speed = 0;			return ivtv_start_decoding(id, speed);		}		break;	default:		return -EINVAL;	}	return 0;}static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg){	struct v4l2_register *regs = arg;	unsigned long flags;	volatile u8 __iomem *reg_start;	if (!capable(CAP_SYS_ADMIN))		return -EPERM;	if (regs->reg >= IVTV_REG_OFFSET && regs->reg < IVTV_REG_OFFSET + IVTV_REG_SIZE)		reg_start = itv->reg_mem - IVTV_REG_OFFSET;	else if (itv->has_cx23415 && regs->reg >= IVTV_DECODER_OFFSET &&			regs->reg < IVTV_DECODER_OFFSET + IVTV_DECODER_SIZE)		reg_start = itv->dec_mem - IVTV_DECODER_OFFSET;	else if (regs->reg >= 0 && regs->reg < IVTV_ENCODER_SIZE)		reg_start = itv->enc_mem;	else		return -EINVAL;	spin_lock_irqsave(&ivtv_cards_lock, flags);	if (cmd == VIDIOC_DBG_G_REGISTER) {		regs->val = readl(regs->reg + reg_start);	} else {		writel(regs->val, regs->reg + reg_start);	}	spin_unlock_irqrestore(&ivtv_cards_lock, flags);	return 0;}static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fmt){	switch (fmt->type) {	case V4L2_BUF_TYPE_VIDEO_OUTPUT:		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))			return -EINVAL;		fmt->fmt.pix.width = itv->main_rect.width;		fmt->fmt.pix.height = itv->main_rect.height;		fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;		fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;		if (itv->output_mode == OUT_UDMA_YUV) {			switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) {			case IVTV_YUV_MODE_INTERLACED:				fmt->fmt.pix.field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ?					V4L2_FIELD_INTERLACED_BT : V4L2_FIELD_INTERLACED_TB;				break;			case IVTV_YUV_MODE_PROGRESSIVE:				fmt->fmt.pix.field = V4L2_FIELD_NONE;				break;			default:				fmt->fmt.pix.field = V4L2_FIELD_ANY;				break;			}			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;			/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */			fmt->fmt.pix.sizeimage =				fmt->fmt.pix.height * fmt->fmt.pix.width +				fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);		}		else if (itv->output_mode == OUT_YUV ||				streamtype == IVTV_ENC_STREAM_TYPE_YUV ||				streamtype == IVTV_DEC_STREAM_TYPE_YUV) {			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;			/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */			fmt->fmt.pix.sizeimage =				fmt->fmt.pix.height * fmt->fmt.pix.width +				fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);		} else {			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;			fmt->fmt.pix.sizeimage = 128 * 1024;		}		break;	case V4L2_BUF_TYPE_VIDEO_CAPTURE:		fmt->fmt.pix.width = itv->params.width;		fmt->fmt.pix.height = itv->params.height;		fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;		fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;		if (streamtype == IVTV_ENC_STREAM_TYPE_YUV ||				streamtype == IVTV_DEC_STREAM_TYPE_YUV) {			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;			/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */			fmt->fmt.pix.sizeimage =				fmt->fmt.pix.height * fmt->fmt.pix.width +				fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);		} else {			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;			fmt->fmt.pix.sizeimage = 128 * 1024;		}		break;	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))			return -EINVAL;		fmt->fmt.win.chromakey = itv->osd_chroma_key;		fmt->fmt.win.global_alpha = itv->osd_global_alpha;		break;	case V4L2_BUF_TYPE_VBI_CAPTURE:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -