cx18-ioctl.c

来自「trident tm5600的linux驱动」· C语言 代码 · 共 962 行 · 第 1/2 页

C
962
字号
	ret = v4l2_prio_check(&cx->prio, &id->prio);	if (ret)		return ret;	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		return -EINVAL;	return cx18_av_cmd(cx, VIDIOC_S_CROP, crop);}static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop){	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		return -EINVAL;	return cx18_av_cmd(cx, VIDIOC_G_CROP, crop);}static int cx18_enum_fmt_vid_cap(struct file *file, void *fh,					struct v4l2_fmtdesc *fmt){	static struct v4l2_fmtdesc formats[] = {		{ 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,		  "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 }		},		{ 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED,		  "MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 }		}	};	if (fmt->index > 1)		return -EINVAL;	*fmt = formats[fmt->index];	return 0;}static int cx18_g_input(struct file *file, void *fh, unsigned int *i){	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;	*i = cx->active_input;	return 0;}int cx18_s_input(struct file *file, void *fh, unsigned int inp){	struct cx18_open_id *id = fh;	struct cx18 *cx = id->cx;	int ret;	ret = v4l2_prio_check(&cx->prio, &id->prio);	if (ret)		return ret;	if (inp < 0 || inp >= cx->nof_inputs)		return -EINVAL;	if (inp == cx->active_input) {		CX18_DEBUG_INFO("Input unchanged\n");		return 0;	}	CX18_DEBUG_INFO("Changing input from %d to %d\n",			cx->active_input, inp);	cx->active_input = inp;	/* Set the audio input to whatever is appropriate for the input type. */	cx->audio_input = cx->card->video_inputs[inp].audio_index;	/* prevent others from messing with the streams until	   we're finished changing inputs. */	cx18_mute(cx);	cx18_video_set_io(cx);	cx18_audio_set_io(cx);	cx18_unmute(cx);	return 0;}static int cx18_g_frequency(struct file *file, void *fh,				struct v4l2_frequency *vf){	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;	if (vf->tuner != 0)		return -EINVAL;	cx18_call_i2c_clients(cx, VIDIOC_G_FREQUENCY, vf);	return 0;}int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf){	struct cx18_open_id *id = fh;	struct cx18 *cx = id->cx;	int ret;	ret = v4l2_prio_check(&cx->prio, &id->prio);	if (ret)		return ret;	if (vf->tuner != 0)		return -EINVAL;	cx18_mute(cx);	CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency);	cx18_call_i2c_clients(cx, VIDIOC_S_FREQUENCY, vf);	cx18_unmute(cx);	return 0;}static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std){	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;	*std = cx->std;	return 0;}int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std){	struct cx18_open_id *id = fh;	struct cx18 *cx = id->cx;	int ret;	ret = v4l2_prio_check(&cx->prio, &id->prio);	if (ret)		return ret;	if ((*std & V4L2_STD_ALL) == 0)		return -EINVAL;	if (*std == cx->std)		return 0;	if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ||	    atomic_read(&cx->ana_capturing) > 0) {		/* Switching standard would turn off the radio or mess		   with already running streams, prevent that by		   returning EBUSY. */		return -EBUSY;	}	cx->std = *std;	cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;	cx->params.is_50hz = cx->is_50hz = !cx->is_60hz;	cx->params.width = 720;	cx->params.height = cx->is_50hz ? 576 : 480;	cx->vbi.count = cx->is_50hz ? 18 : 12;	cx->vbi.start[0] = cx->is_50hz ? 6 : 10;	cx->vbi.start[1] = cx->is_50hz ? 318 : 273;	cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284;	CX18_DEBUG_INFO("Switching standard to %llx.\n",			(unsigned long long) cx->std);	/* Tuner */	cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);	return 0;}static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt){	struct cx18_open_id *id = fh;	struct cx18 *cx = id->cx;	int ret;	ret = v4l2_prio_check(&cx->prio, &id->prio);	if (ret)		return ret;	if (vt->index != 0)		return -EINVAL;	/* Setting tuner can only set audio mode */	cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt);	return 0;}static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt){	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;	if (vt->index != 0)		return -EINVAL;	cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt);	if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {		strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));		vt->type = V4L2_TUNER_RADIO;	} else {		strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name));		vt->type = V4L2_TUNER_ANALOG_TV;	}	return 0;}static int cx18_g_sliced_vbi_cap(struct file *file, void *fh,					struct v4l2_sliced_vbi_cap *cap){#if 0	/* Supported by the cx23418 but not yet implemented. */	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;	int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;	int f, l;	if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {		for (f = 0; f < 2; f++) {			for (l = 0; l < 24; l++) {				if (valid_service_line(f, l, cx->is_50hz))					cap->service_lines[f][l] = set;			}		}		return 0;	}#endif	return -EINVAL;}static int cx18_g_enc_index(struct file *file, void *fh,				struct v4l2_enc_idx *idx){#if 0	/* Supported by the cx23418 but not yet implemented. */	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;	int i;	idx->entries = (cx->pgm_info_write_idx + CX18_MAX_PGM_INDEX			- cx->pgm_info_read_idx) % CX18_MAX_PGM_INDEX;	if (idx->entries > V4L2_ENC_IDX_ENTRIES)		idx->entries = V4L2_ENC_IDX_ENTRIES;	for (i = 0; i < idx->entries; i++)		idx->entry[i] = cx->pgm_info [(cx->pgm_info_read_idx + i)							% CX18_MAX_PGM_INDEX];	cx->pgm_info_read_idx =		(cx->pgm_info_read_idx + idx->entries) % CX18_MAX_PGM_INDEX;	return 0;#else	return -EINVAL;#endif}static int cx18_encoder_cmd(struct file *file, void *fh,				struct v4l2_encoder_cmd *enc){	struct cx18_open_id *id = fh;	struct cx18 *cx = id->cx;	u32 h;	switch (enc->cmd) {	case V4L2_ENC_CMD_START:		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");		enc->flags = 0;		return cx18_start_capture(id);	case V4L2_ENC_CMD_STOP:		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");		enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;		cx18_stop_capture(id,				  enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);		break;	case V4L2_ENC_CMD_PAUSE:		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");		enc->flags = 0;		if (!atomic_read(&cx->ana_capturing))			return -EPERM;		if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))			return 0;		h = cx18_find_handle(cx);		if (h == CX18_INVALID_TASK_HANDLE) {			CX18_ERR("Can't find valid task handle for "				 "V4L2_ENC_CMD_PAUSE\n");			return -EBADFD;		}		cx18_mute(cx);		cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, h);		break;	case V4L2_ENC_CMD_RESUME:		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");		enc->flags = 0;		if (!atomic_read(&cx->ana_capturing))			return -EPERM;		if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))			return 0;		h = cx18_find_handle(cx);		if (h == CX18_INVALID_TASK_HANDLE) {			CX18_ERR("Can't find valid task handle for "				 "V4L2_ENC_CMD_RESUME\n");			return -EBADFD;		}		cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, h);		cx18_unmute(cx);		break;	default:		CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);		return -EINVAL;	}	return 0;}static int cx18_try_encoder_cmd(struct file *file, void *fh,				struct v4l2_encoder_cmd *enc){	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;	switch (enc->cmd) {	case V4L2_ENC_CMD_START:		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");		enc->flags = 0;		break;	case V4L2_ENC_CMD_STOP:		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");		enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;		break;	case V4L2_ENC_CMD_PAUSE:		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");		enc->flags = 0;		break;	case V4L2_ENC_CMD_RESUME:		CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");		enc->flags = 0;		break;	default:		CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);		return -EINVAL;	}	return 0;}static int cx18_log_status(struct file *file, void *fh){	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;	struct v4l2_input vidin;	struct v4l2_audio audin;	int i;	CX18_INFO("=================  START STATUS CARD #%d  =================\n", cx->num);	if (cx->hw_flags & CX18_HW_TVEEPROM) {		struct tveeprom tv;		cx18_read_eeprom(cx, &tv);	}	cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL);	cx18_get_input(cx, cx->active_input, &vidin);	cx18_get_audio_input(cx, cx->audio_input, &audin);	CX18_INFO("Video Input: %s\n", vidin.name);	CX18_INFO("Audio Input: %s\n", audin.name);	mutex_lock(&cx->gpio_lock);	CX18_INFO("GPIO:  direction 0x%08x, value 0x%08x\n",		cx->gpio_dir, cx->gpio_val);	mutex_unlock(&cx->gpio_lock);	CX18_INFO("Tuner: %s\n",		test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ?  "Radio" : "TV");	cx2341x_log_status(&cx->params, cx->name);	CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);	for (i = 0; i < CX18_MAX_STREAMS; i++) {		struct cx18_stream *s = &cx->streams[i];		if (s->v4l2dev == NULL || s->buffers == 0)			continue;		CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",			  s->name, s->s_flags,			  (s->buffers - atomic_read(&s->q_free.buffers))				* 100 / s->buffers,			  (s->buffers * s->buf_size) / 1024, s->buffers);	}	CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",			(long long)cx->mpg_data_received,			(long long)cx->vbi_data_inserted);	cx18_log_statistics(cx);	CX18_INFO("==================  END STATUS CARD #%d  ==================\n", cx->num);	return 0;}static int cx18_default(struct file *file, void *fh, int cmd, void *arg){	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;	switch (cmd) {	case VIDIOC_INT_S_AUDIO_ROUTING: {		struct v4l2_routing *route = arg;		CX18_DEBUG_IOCTL("VIDIOC_INT_S_AUDIO_ROUTING(%d, %d)\n",			route->input, route->output);		cx18_audio_set_route(cx, route);		break;	}	case VIDIOC_INT_RESET: {		u32 val = *(u32 *)arg;		if ((val == 0) || (val & 0x01))			cx18_reset_ir_gpio(&cx->i2c_algo_cb_data[0]);		break;	}	default:		return -EINVAL;	}	return 0;}int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,		    unsigned long arg){	struct video_device *vfd = video_devdata(filp);	struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;	struct cx18 *cx = id->cx;	int res;	mutex_lock(&cx->serialize_lock);	if (cx18_debug & CX18_DBGFLG_IOCTL)		vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;	res = video_ioctl2(inode, filp, cmd, arg);	vfd->debug = 0;	mutex_unlock(&cx->serialize_lock);	return res;}static const struct v4l2_ioctl_ops cx18_ioctl_ops = {	.vidioc_querycap                = cx18_querycap,	.vidioc_g_priority              = cx18_g_priority,	.vidioc_s_priority              = cx18_s_priority,	.vidioc_s_audio                 = cx18_s_audio,	.vidioc_g_audio                 = cx18_g_audio,	.vidioc_enumaudio               = cx18_enumaudio,	.vidioc_enum_input              = cx18_enum_input,	.vidioc_cropcap                 = cx18_cropcap,	.vidioc_s_crop                  = cx18_s_crop,	.vidioc_g_crop                  = cx18_g_crop,	.vidioc_g_input                 = cx18_g_input,	.vidioc_s_input                 = cx18_s_input,	.vidioc_g_frequency             = cx18_g_frequency,	.vidioc_s_frequency             = cx18_s_frequency,	.vidioc_s_tuner                 = cx18_s_tuner,	.vidioc_g_tuner                 = cx18_g_tuner,	.vidioc_g_enc_index             = cx18_g_enc_index,	.vidioc_g_std                   = cx18_g_std,	.vidioc_s_std                   = cx18_s_std,	.vidioc_log_status              = cx18_log_status,	.vidioc_enum_fmt_vid_cap        = cx18_enum_fmt_vid_cap,	.vidioc_encoder_cmd             = cx18_encoder_cmd,	.vidioc_try_encoder_cmd         = cx18_try_encoder_cmd,	.vidioc_g_fmt_vid_cap           = cx18_g_fmt_vid_cap,	.vidioc_g_fmt_vbi_cap           = cx18_g_fmt_vbi_cap,	.vidioc_g_fmt_sliced_vbi_cap    = cx18_g_fmt_sliced_vbi_cap,	.vidioc_s_fmt_vid_cap           = cx18_s_fmt_vid_cap,	.vidioc_s_fmt_vbi_cap           = cx18_s_fmt_vbi_cap,	.vidioc_s_fmt_sliced_vbi_cap    = cx18_s_fmt_sliced_vbi_cap,	.vidioc_try_fmt_vid_cap         = cx18_try_fmt_vid_cap,	.vidioc_try_fmt_vbi_cap         = cx18_try_fmt_vbi_cap,	.vidioc_try_fmt_sliced_vbi_cap  = cx18_try_fmt_sliced_vbi_cap,	.vidioc_g_sliced_vbi_cap        = cx18_g_sliced_vbi_cap,	.vidioc_g_chip_ident            = cx18_g_chip_ident,#ifdef CONFIG_VIDEO_ADV_DEBUG	.vidioc_g_register              = cx18_g_register,	.vidioc_s_register              = cx18_s_register,#endif	.vidioc_default                 = cx18_default,	.vidioc_queryctrl               = cx18_queryctrl,	.vidioc_querymenu               = cx18_querymenu,	.vidioc_g_ext_ctrls             = cx18_g_ext_ctrls,	.vidioc_s_ext_ctrls             = cx18_s_ext_ctrls,	.vidioc_try_ext_ctrls           = cx18_try_ext_ctrls,};void cx18_set_funcs(struct video_device *vdev){	vdev->ioctl_ops = &cx18_ioctl_ops;}

⌨️ 快捷键说明

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