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

📄 cx88-video.c

📁 底层驱动开发
💻 C
📖 第 1 页 / 共 4 页
字号:
		case V4L2_FIELD_BOTTOM:			maxh = maxh / 2;			break;		case V4L2_FIELD_INTERLACED:			break;		default:			return -EINVAL;		}		f->fmt.pix.field = field;		if (f->fmt.pix.height < 32)			f->fmt.pix.height = 32;		if (f->fmt.pix.height > maxh)			f->fmt.pix.height = maxh;		if (f->fmt.pix.width < 48)			f->fmt.pix.width = 48;		if (f->fmt.pix.width > maxw)			f->fmt.pix.width = maxw;		f->fmt.pix.width &= ~0x03;		f->fmt.pix.bytesperline =			(f->fmt.pix.width * fmt->depth) >> 3;		f->fmt.pix.sizeimage =			f->fmt.pix.height * f->fmt.pix.bytesperline;		return 0;	}	case V4L2_BUF_TYPE_VBI_CAPTURE:		cx8800_vbi_fmt(dev, f);		return 0;	default:		return -EINVAL;	}}static int cx8800_s_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh,			struct v4l2_format *f){	int err;	switch (f->type) {	case V4L2_BUF_TYPE_VIDEO_CAPTURE:		err = cx8800_try_fmt(dev,fh,f);		if (0 != err)			return err;		fh->fmt        = format_by_fourcc(f->fmt.pix.pixelformat);		fh->width      = f->fmt.pix.width;		fh->height     = f->fmt.pix.height;		fh->vidq.field = f->fmt.pix.field;		return 0;	case V4L2_BUF_TYPE_VBI_CAPTURE:		cx8800_vbi_fmt(dev, f);		return 0;	default:		return -EINVAL;	}}/* * This function is _not_ called directly, but from * video_generic_ioctl (and maybe others).  userspace * copying is done already, arg is a kernel pointer. */static int video_do_ioctl(struct inode *inode, struct file *file,			  unsigned int cmd, void *arg){	struct cx8800_fh  *fh   = file->private_data;	struct cx8800_dev *dev  = fh->dev;	struct cx88_core  *core = dev->core;	int err;	if (video_debug > 1)		cx88_print_ioctl(core->name,cmd);	switch (cmd) {	/* --- capabilities ------------------------------------------ */	case VIDIOC_QUERYCAP:	{		struct v4l2_capability *cap = arg;		memset(cap,0,sizeof(*cap));		strcpy(cap->driver, "cx8800");		strlcpy(cap->card, cx88_boards[core->board].name,			sizeof(cap->card));		sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));		cap->version = CX88_VERSION_CODE;		cap->capabilities =			V4L2_CAP_VIDEO_CAPTURE |			V4L2_CAP_READWRITE     |			V4L2_CAP_STREAMING     |			V4L2_CAP_VBI_CAPTURE   |			V4L2_CAP_VIDEO_OVERLAY |			0;		if (UNSET != core->tuner_type)			cap->capabilities |= V4L2_CAP_TUNER;		return 0;	}	/* --- capture ioctls ---------------------------------------- */	case VIDIOC_ENUM_FMT:	{		struct v4l2_fmtdesc *f = arg;		enum v4l2_buf_type type;		unsigned int index;		index = f->index;		type  = f->type;		switch (type) {		case V4L2_BUF_TYPE_VIDEO_CAPTURE:			if (index >= ARRAY_SIZE(formats))				return -EINVAL;			memset(f,0,sizeof(*f));			f->index = index;			f->type  = type;			strlcpy(f->description,formats[index].name,sizeof(f->description));			f->pixelformat = formats[index].fourcc;			break;		default:			return -EINVAL;		}		return 0;	}	case VIDIOC_G_FMT:	{		struct v4l2_format *f = arg;		return cx8800_g_fmt(dev,fh,f);	}	case VIDIOC_S_FMT:	{		struct v4l2_format *f = arg;		return cx8800_s_fmt(dev,fh,f);	}	case VIDIOC_TRY_FMT:	{		struct v4l2_format *f = arg;		return cx8800_try_fmt(dev,fh,f);	}	/* --- streaming capture ------------------------------------- */	case VIDIOCGMBUF:	{		struct video_mbuf *mbuf = arg;		struct videobuf_queue *q;		struct v4l2_requestbuffers req;		unsigned int i;		q = get_queue(fh);		memset(&req,0,sizeof(req));		req.type   = q->type;		req.count  = 8;		req.memory = V4L2_MEMORY_MMAP;		err = videobuf_reqbufs(q,&req);		if (err < 0)			return err;		memset(mbuf,0,sizeof(*mbuf));		mbuf->frames = req.count;		mbuf->size   = 0;		for (i = 0; i < mbuf->frames; i++) {			mbuf->offsets[i]  = q->bufs[i]->boff;			mbuf->size       += q->bufs[i]->bsize;		}		return 0;	}	case VIDIOC_REQBUFS:		return videobuf_reqbufs(get_queue(fh), arg);	case VIDIOC_QUERYBUF:		return videobuf_querybuf(get_queue(fh), arg);	case VIDIOC_QBUF:		return videobuf_qbuf(get_queue(fh), arg);	case VIDIOC_DQBUF:		return videobuf_dqbuf(get_queue(fh), arg,					file->f_flags & O_NONBLOCK);	case VIDIOC_STREAMON:	{		int res = get_ressource(fh);		if (!res_get(dev,fh,res))			return -EBUSY;		return videobuf_streamon(get_queue(fh));	}	case VIDIOC_STREAMOFF:	{		int res = get_ressource(fh);		err = videobuf_streamoff(get_queue(fh));		if (err < 0)			return err;		res_free(dev,fh,res);		return 0;	}	default:		return cx88_do_ioctl( inode, file, fh->radio, core, cmd, arg, video_do_ioctl );	}	return 0;}int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,                  struct cx88_core *core, unsigned int cmd, void *arg, v4l2_kioctl driver_ioctl){	int err;	if (video_debug > 1)		cx88_print_ioctl(core->name,cmd);	printk( KERN_INFO "CORE IOCTL: 0x%x\n", cmd );	cx88_print_ioctl(core->name,cmd);	dprintk( 1, "CORE IOCTL: 0x%x\n", cmd );	switch (cmd) {	/* ---------- tv norms ---------- */	case VIDIOC_ENUMSTD:	{		struct v4l2_standard *e = arg;		unsigned int i;		i = e->index;		if (i >= ARRAY_SIZE(tvnorms))			return -EINVAL;		err = v4l2_video_std_construct(e, tvnorms[e->index].id,					       tvnorms[e->index].name);		e->index = i;		if (err < 0)			return err;		return 0;	}	case VIDIOC_G_STD:	{		v4l2_std_id *id = arg;		*id = core->tvnorm->id;		return 0;	}	case VIDIOC_S_STD:	{		v4l2_std_id *id = arg;		unsigned int i;		for(i = 0; i < ARRAY_SIZE(tvnorms); i++)			if (*id & tvnorms[i].id)				break;		if (i == ARRAY_SIZE(tvnorms))			return -EINVAL;		down(&core->lock);		cx88_set_tvnorm(core,&tvnorms[i]);		up(&core->lock);		return 0;	}	/* ------ input switching ---------- */	case VIDIOC_ENUMINPUT:	{		static const char *iname[] = {			[ CX88_VMUX_COMPOSITE1 ] = "Composite1",			[ CX88_VMUX_COMPOSITE2 ] = "Composite2",			[ CX88_VMUX_COMPOSITE3 ] = "Composite3",			[ CX88_VMUX_COMPOSITE4 ] = "Composite4",			[ CX88_VMUX_SVIDEO     ] = "S-Video",			[ CX88_VMUX_TELEVISION ] = "Television",			[ CX88_VMUX_CABLE      ] = "Cable TV",			[ CX88_VMUX_DVB        ] = "DVB",			[ CX88_VMUX_DEBUG      ] = "for debug only",		};		struct v4l2_input *i = arg;		unsigned int n;		n = i->index;		if (n >= 4)			return -EINVAL;		if (0 == INPUT(n)->type)			return -EINVAL;		memset(i,0,sizeof(*i));		i->index = n;		i->type  = V4L2_INPUT_TYPE_CAMERA;		strcpy(i->name,iname[INPUT(n)->type]);		if ((CX88_VMUX_TELEVISION == INPUT(n)->type) ||		    (CX88_VMUX_CABLE      == INPUT(n)->type))			i->type = V4L2_INPUT_TYPE_TUNER;		for (n = 0; n < ARRAY_SIZE(tvnorms); n++)			i->std |= tvnorms[n].id;		return 0;	}	case VIDIOC_G_INPUT:	{		unsigned int *i = arg;		*i = core->input;		return 0;	}	case VIDIOC_S_INPUT:	{		unsigned int *i = arg;		if (*i >= 4)			return -EINVAL;		down(&core->lock);		cx88_newstation(core);		video_mux(core,*i);		up(&core->lock);		return 0;	}	/* --- controls ---------------------------------------------- */	case VIDIOC_QUERYCTRL:	{		struct v4l2_queryctrl *c = arg;		int i;		if (c->id <  V4L2_CID_BASE ||		    c->id >= V4L2_CID_LASTP1)			return -EINVAL;		for (i = 0; i < CX8800_CTLS; i++)			if (cx8800_ctls[i].v.id == c->id)				break;		if (i == CX8800_CTLS) {			*c = no_ctl;			return 0;		}		*c = cx8800_ctls[i].v;		return 0;	}	case VIDIOC_G_CTRL:		return get_control(core,arg);	case VIDIOC_S_CTRL:		return set_control(core,arg);	/* --- tuner ioctls ------------------------------------------ */	case VIDIOC_G_TUNER:	{		struct v4l2_tuner *t = arg;		u32 reg;		if (UNSET == core->tuner_type)			return -EINVAL;		if (0 != t->index)			return -EINVAL;		memset(t,0,sizeof(*t));		strcpy(t->name, "Television");		t->type       = V4L2_TUNER_ANALOG_TV;		t->capability = V4L2_TUNER_CAP_NORM;		t->rangehigh  = 0xffffffffUL;		cx88_get_stereo(core ,t);		reg = cx_read(MO_DEVICE_STATUS);                t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;		return 0;	}	case VIDIOC_S_TUNER:	{		struct v4l2_tuner *t = arg;		if (UNSET == core->tuner_type)			return -EINVAL;		if (0 != t->index)			return -EINVAL;		cx88_set_stereo(core, t->audmode, 1);		return 0;	}	case VIDIOC_G_FREQUENCY:	{		struct v4l2_frequency *f = arg;		memset(f,0,sizeof(*f));		if (UNSET == core->tuner_type)			return -EINVAL;		/* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */		f->type = radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;		f->frequency = core->freq;		cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f);		return 0;	}	case VIDIOC_S_FREQUENCY:	{		struct v4l2_frequency *f = arg;		if (UNSET == core->tuner_type)			return -EINVAL;		if (f->tuner != 0)			return -EINVAL;		if (0 == radio && f->type != V4L2_TUNER_ANALOG_TV)			return -EINVAL;		if (1 == radio && f->type != V4L2_TUNER_RADIO)			return -EINVAL;		down(&core->lock);		core->freq = f->frequency;		cx88_newstation(core);		cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f);		/* When changing channels it is required to reset TVAUDIO */		msleep (10);		cx88_set_tvaudio(core);		up(&core->lock);		return 0;	}	default:		return v4l_compat_translate_ioctl(inode,file,cmd,arg,						  driver_ioctl);	}	return 0;}static int video_ioctl(struct inode *inode, struct file *file,		       unsigned int cmd, unsigned long arg){	return video_usercopy(inode, file, cmd, arg, video_do_ioctl);}/* ----------------------------------------------------------- */static int radio_do_ioctl(struct inode *inode, struct file *file,			unsigned int cmd, void *arg){	struct cx8800_fh *fh    = file->private_data;	struct cx8800_dev *dev  = fh->dev;	struct cx88_core  *core = dev->core;	if (video_debug > 1)		cx88_print_ioctl(core->name,cmd);	switch (cmd) {	case VIDIOC_QUERYCAP:	{		struct v4l2_capability *cap = arg;		memset(cap,0,sizeof(*cap));                strcpy(cap->driver, "cx8800");		strlcpy(cap->card, cx88_boards[core->board].name,			sizeof(cap->card));		sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));		cap->version = CX88_VERSION_CODE;		cap->capabilities = V4L2_CAP_TUNER;		return 0;	}	case VIDIOC_G_TUNER:	{		struct v4l2_tuner *t = arg;		if (t->index > 0)			return -EINVAL;		memset(t,0,sizeof(*t));		strcpy(t->name, "Radio");		cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t);		return 0;	}	case VIDIOC_ENUMINPUT:	{		struct v4l2_input *i = arg;		if (i->index != 0)			return -EINVAL;		strcpy(i->name,"Radio");		i->type = V4L2_INPUT_TYPE_TUNER;		return 0;	}	case VIDIOC_G_INPUT:	{		int *i = arg;		*i = 0;		return 0;	}	case VIDIOC_G_AUDIO:	{		struct v4l2_audio *a = arg;		memset(a,0,sizeof(*a));		strcpy(a->name,"Radio");		return 0;	}	case VIDIOC_G_STD:	{		v4l2_std_id *id = arg;		*id = 0;		return 0;	}	case VIDIOCSTUNER:	{		struct video_tuner *v = arg;		if (v->tuner) /* Only tuner 0 */			return -EINVAL;		cx88_call_i2c_clients(core,VIDIOCSTUNER,v);		return 0;	}	case VIDIOC_S_TUNER:	{		struct v4l2_tuner *t = arg;		if (0 != t->index)			return -EINVAL;		cx88_call_i2c_clients(core,VIDIOC_S_TUNER,t);		return 0;	}	case VIDIOC_S_AUDIO:	case VIDIOC_S_INPUT:	case VIDIOC_S_STD:		return 0;	case VIDIOC_QUERYCTRL:	{		struct v4l2_queryctrl *c = arg;		int i;		if (c->id <  V4L2_CID_BASE ||		    c->id >= V4L2_CID_LASTP1)			return -EINVAL;		if (c->id == V4L2_CID_AUDIO_MUTE) {			for (i = 0; i < CX8800_CTLS; i++)

⌨️ 快捷键说明

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