cx18-ioctl.c

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

C
962
字号
/* *  cx18 ioctl system call * *  Derived from ivtv-ioctl.c * *  Copyright (C) 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 "cx18-driver.h"#include "cx18-io.h"#include "cx18-version.h"#include "cx18-mailbox.h"#include "cx18-i2c.h"#include "cx18-queue.h"#include "cx18-fileops.h"#include "cx18-vbi.h"#include "cx18-audio.h"#include "cx18-video.h"#include "cx18-streams.h"#include "cx18-ioctl.h"#include "cx18-gpio.h"#include "cx18-controls.h"#include "cx18-cards.h"#include "cx18-av-core.h"#include <media/tveeprom.h>#include <media/v4l2-chip-ident.h>#include <linux/i2c-id.h>u16 cx18_service2vbi(int type){	switch (type) {	case V4L2_SLICED_TELETEXT_B:		return CX18_SLICED_TYPE_TELETEXT_B;	case V4L2_SLICED_CAPTION_525:		return CX18_SLICED_TYPE_CAPTION_525;	case V4L2_SLICED_WSS_625:		return CX18_SLICED_TYPE_WSS_625;	case V4L2_SLICED_VPS:		return CX18_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 cx18_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);	}}#if 0static 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;}#endifu16 cx18_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 int cx18_g_fmt_vid_cap(struct file *file, void *fh,				struct v4l2_format *fmt){	struct cx18_open_id *id = fh;	struct cx18 *cx = id->cx;	struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;	pixfmt->width = cx->params.width;	pixfmt->height = cx->params.height;	pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;	pixfmt->field = V4L2_FIELD_INTERLACED;	pixfmt->priv = 0;	if (id->type == CX18_ENC_STREAM_TYPE_YUV) {		pixfmt->pixelformat = V4L2_PIX_FMT_HM12;		/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */		pixfmt->sizeimage =			pixfmt->height * pixfmt->width +			pixfmt->height * (pixfmt->width / 2);		pixfmt->bytesperline = 720;	} else {		pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;		pixfmt->sizeimage = 128 * 1024;		pixfmt->bytesperline = 0;	}	return 0;}static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,				struct v4l2_format *fmt){	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;	struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi;	vbifmt->sampling_rate = 27000000;	vbifmt->offset = 248;	vbifmt->samples_per_line = cx->vbi.raw_decoder_line_size - 4;	vbifmt->sample_format = V4L2_PIX_FMT_GREY;	vbifmt->start[0] = cx->vbi.start[0];	vbifmt->start[1] = cx->vbi.start[1];	vbifmt->count[0] = vbifmt->count[1] = cx->vbi.count;	vbifmt->flags = 0;	vbifmt->reserved[0] = 0;	vbifmt->reserved[1] = 0;	return 0;}static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh,					struct v4l2_format *fmt){#if 0	/* Supported by the cx23418 but not yet implemented. */	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;	vbifmt->reserved[0] = 0;	vbifmt->reserved[1] = 0;	vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;	memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));	cx18_av_cmd(cx, VIDIOC_G_FMT, fmt);	vbifmt->service_set = cx18_get_service_set(vbifmt);	return 0;#else	return -EINVAL;#endif}static int cx18_try_fmt_vid_cap(struct file *file, void *fh,				struct v4l2_format *fmt){	struct cx18_open_id *id = fh;	struct cx18 *cx = id->cx;	int w = fmt->fmt.pix.width;	int h = fmt->fmt.pix.height;	w = min(w, 720);	w = max(w, 1);	h = min(h, cx->is_50hz ? 576 : 480);	h = max(h, 2);	cx18_g_fmt_vid_cap(file, fh, fmt);	fmt->fmt.pix.width = w;	fmt->fmt.pix.height = h;	return 0;}static int cx18_try_fmt_vbi_cap(struct file *file, void *fh,				struct v4l2_format *fmt){	return cx18_g_fmt_vbi_cap(file, fh, fmt);}static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh,					struct v4l2_format *fmt){#if 0	/* Supported by the cx23418 but not yet implemented. */	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;	vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;	vbifmt->reserved[0] = 0;	vbifmt->reserved[1] = 0;	if (vbifmt->service_set)		cx18_expand_service_set(vbifmt, cx->is_50hz);	check_service_set(vbifmt, cx->is_50hz);	vbifmt->service_set = cx18_get_service_set(vbifmt);	return 0;#else	return -EINVAL;#endif}static int cx18_s_fmt_vid_cap(struct file *file, void *fh,				struct v4l2_format *fmt){	struct cx18_open_id *id = fh;	struct cx18 *cx = id->cx;	int ret;	int w, h;	ret = v4l2_prio_check(&cx->prio, &id->prio);	if (ret)		return ret;	ret = cx18_try_fmt_vid_cap(file, fh, fmt);	if (ret)		return ret;	w = fmt->fmt.pix.width;	h = fmt->fmt.pix.height;	if (cx->params.width == w && cx->params.height == h)		return 0;	if (atomic_read(&cx->ana_capturing) > 0)		return -EBUSY;	cx->params.width = w;	cx->params.height = h;	cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);	return cx18_g_fmt_vid_cap(file, fh, fmt);}static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,				struct v4l2_format *fmt){	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 (id->type == CX18_ENC_STREAM_TYPE_VBI &&			cx->vbi.sliced_in->service_set &&			atomic_read(&cx->ana_capturing) > 0)		return -EBUSY;	cx->vbi.sliced_in->service_set = 0;	cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);	return cx18_g_fmt_vbi_cap(file, fh, fmt);}static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,					struct v4l2_format *fmt){#if 0	/* Supported by the cx23418 but not yet implemented. */	struct cx18_open_id *id = fh;	struct cx18 *cx = id->cx;	int ret;	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;	ret = v4l2_prio_check(&cx->prio, &id->prio);	if (ret)		return ret;	ret = cx18_try_fmt_sliced_vbi_cap(file, fh, fmt);	if (ret)		return ret;	if (check_service_set(vbifmt, cx->is_50hz) == 0)		return -EINVAL;	if (atomic_read(&cx->ana_capturing) > 0 &&			cx->vbi.sliced_in->service_set == 0)		return -EBUSY;	cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);	memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));	return 0;#else	return -EINVAL;#endif}static int cx18_g_chip_ident(struct file *file, void *fh,				struct v4l2_chip_ident *chip){	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;	chip->ident = V4L2_IDENT_NONE;	chip->revision = 0;	if (chip->match_type == V4L2_CHIP_MATCH_HOST) {		if (v4l2_chip_match_host(chip->match_type, chip->match_chip))			chip->ident = V4L2_IDENT_CX23418;		return 0;	}	if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)		return cx18_i2c_id(cx, chip->match_chip, VIDIOC_G_CHIP_IDENT,					chip);	if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR)		return cx18_call_i2c_client(cx, chip->match_chip,						VIDIOC_G_CHIP_IDENT, chip);	return -EINVAL;}#ifdef CONFIG_VIDEO_ADV_DEBUGstatic int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg){	struct v4l2_register *regs = arg;	unsigned long flags;	if (!capable(CAP_SYS_ADMIN))		return -EPERM;	if (regs->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)		return -EINVAL;	spin_lock_irqsave(&cx18_cards_lock, flags);	if (cmd == VIDIOC_DBG_G_REGISTER)		regs->val = cx18_read_enc(cx, regs->reg);	else		cx18_write_enc(cx, regs->val, regs->reg);	spin_unlock_irqrestore(&cx18_cards_lock, flags);	return 0;}static int cx18_g_register(struct file *file, void *fh,				struct v4l2_register *reg){	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;	if (v4l2_chip_match_host(reg->match_type, reg->match_chip))		return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg);	if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)		return cx18_i2c_id(cx, reg->match_chip, VIDIOC_DBG_G_REGISTER,					reg);	return cx18_call_i2c_client(cx, reg->match_chip, VIDIOC_DBG_G_REGISTER,					reg);}static int cx18_s_register(struct file *file, void *fh,				struct v4l2_register *reg){	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;	if (v4l2_chip_match_host(reg->match_type, reg->match_chip))		return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg);	if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)		return cx18_i2c_id(cx, reg->match_chip, VIDIOC_DBG_S_REGISTER,					reg);	return cx18_call_i2c_client(cx, reg->match_chip, VIDIOC_DBG_S_REGISTER,					reg);}#endifstatic int cx18_g_priority(struct file *file, void *fh, enum v4l2_priority *p){	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;	*p = v4l2_prio_max(&cx->prio);	return 0;}static int cx18_s_priority(struct file *file, void *fh, enum v4l2_priority prio){	struct cx18_open_id *id = fh;	struct cx18 *cx = id->cx;	return v4l2_prio_change(&cx->prio, &id->prio, prio);}static int cx18_querycap(struct file *file, void *fh,				struct v4l2_capability *vcap){	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;	strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));	strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));	snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(cx->dev));	vcap->version = CX18_DRIVER_VERSION; 	    /* version */	vcap->capabilities = cx->v4l2_cap; 	    /* capabilities */	return 0;}static int cx18_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin){	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;	return cx18_get_audio_input(cx, vin->index, vin);}static int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin){	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;	vin->index = cx->audio_input;	return cx18_get_audio_input(cx, vin->index, vin);}static int cx18_s_audio(struct file *file, void *fh, struct v4l2_audio *vout){	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;	if (vout->index >= cx->nof_audio_inputs)		return -EINVAL;	cx->audio_input = vout->index;	cx18_audio_set_io(cx);	return 0;}static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin){	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;	/* set it to defaults from our table */	return cx18_get_input(cx, vin->index, vin);}static int cx18_cropcap(struct file *file, void *fh,			struct v4l2_cropcap *cropcap){	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;	if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		return -EINVAL;	cropcap->bounds.top = cropcap->bounds.left = 0;	cropcap->bounds.width = 720;	cropcap->bounds.height = cx->is_50hz ? 576 : 480;	cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10;	cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11;	cropcap->defrect = cropcap->bounds;	return 0;}static int cx18_s_crop(struct file *file, void *fh, struct v4l2_crop *crop){	struct cx18_open_id *id = fh;	struct cx18 *cx = id->cx;	int ret;

⌨️ 快捷键说明

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