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

📄 bttv-driver.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
	case VIDIOCGTUNER:	{		struct video_tuner *v = arg;		if (UNSET == bttv_tvcards[btv->c.type].tuner)			return -EINVAL;		if (v->tuner) /* Only tuner 0 */			return -EINVAL;		strcpy(v->name, "Television");		v->rangelow  = 0;		v->rangehigh = 0x7FFFFFFF;		v->flags     = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;		v->mode      = btv->tvnorm;		v->signal    = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0;		bttv_call_i2c_clients(btv,cmd,v);		return 0;	}	case VIDIOCSTUNER:	{		struct video_tuner *v = arg;		if (v->tuner) /* Only tuner 0 */			return -EINVAL;		if (v->mode >= BTTV_TVNORMS)			return -EINVAL;		down(&btv->lock);		set_tvnorm(btv,v->mode);		bttv_call_i2c_clients(btv,cmd,v);		up(&btv->lock);		return 0;	}	case VIDIOCGCHAN:	{		struct video_channel *v = arg;		unsigned int channel = v->channel;		if (channel >= bttv_tvcards[btv->c.type].video_inputs)			return -EINVAL;		v->tuners=0;		v->flags = VIDEO_VC_AUDIO;		v->type = VIDEO_TYPE_CAMERA;		v->norm = btv->tvnorm;		if (channel == bttv_tvcards[btv->c.type].tuner)  {			strcpy(v->name,"Television");			v->flags|=VIDEO_VC_TUNER;			v->type=VIDEO_TYPE_TV;			v->tuners=1;		} else if (channel == btv->svhs) {			strcpy(v->name,"S-Video");		} else {			sprintf(v->name,"Composite%d",channel);		}		return 0;	}	case VIDIOCSCHAN:	{		struct video_channel *v = arg;		unsigned int channel = v->channel;		if (channel >= bttv_tvcards[btv->c.type].video_inputs)			return -EINVAL;		if (v->norm >= BTTV_TVNORMS)			return -EINVAL;		down(&btv->lock);		if (channel == btv->input &&		    v->norm == btv->tvnorm) {			/* nothing to do */			up(&btv->lock);			return 0;		}		btv->tvnorm = v->norm;		set_input(btv,v->channel);		up(&btv->lock);		return 0;	}	case VIDIOCGAUDIO:	{		struct video_audio *v = arg;		memset(v,0,sizeof(*v));		strcpy(v->name,"Television");		v->flags |= VIDEO_AUDIO_MUTABLE;		v->mode  = VIDEO_SOUND_MONO;		down(&btv->lock);		bttv_call_i2c_clients(btv,cmd,v);		/* card specific hooks */		if (btv->audio_hook)			btv->audio_hook(btv,v,0);		up(&btv->lock);		return 0;	}	case VIDIOCSAUDIO:	{		struct video_audio *v = arg;		unsigned int audio = v->audio;		if (audio >= bttv_tvcards[btv->c.type].audio_inputs)			return -EINVAL;		down(&btv->lock);		audio_mux(btv, (v->flags&VIDEO_AUDIO_MUTE) ? AUDIO_MUTE : AUDIO_UNMUTE);		bttv_call_i2c_clients(btv,cmd,v);		/* card specific hooks */		if (btv->audio_hook)			btv->audio_hook(btv,v,1);		up(&btv->lock);		return 0;	}	/* ***  v4l2  *** ************************************************ */	case VIDIOC_ENUMSTD:	{		struct v4l2_standard *e = arg;		unsigned int index = e->index;		if (index >= BTTV_TVNORMS)			return -EINVAL;		v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id,					 bttv_tvnorms[e->index].name);		e->index = index;		return 0;	}	case VIDIOC_G_STD:	{		v4l2_std_id *id = arg;		*id = bttv_tvnorms[btv->tvnorm].v4l2_id;		return 0;	}	case VIDIOC_S_STD:	{		v4l2_std_id *id = arg;		unsigned int i;		for (i = 0; i < BTTV_TVNORMS; i++)			if (*id & bttv_tvnorms[i].v4l2_id)				break;		if (i == BTTV_TVNORMS)			return -EINVAL;		down(&btv->lock);		set_tvnorm(btv,i);		i2c_vidiocschan(btv);		up(&btv->lock);		return 0;	}	case VIDIOC_QUERYSTD:	{		v4l2_std_id *id = arg;		if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)			*id = V4L2_STD_625_50;		else			*id = V4L2_STD_525_60;		return 0;	}	case VIDIOC_ENUMINPUT:	{		struct v4l2_input *i = arg;		unsigned int n;		n = i->index;		if (n >= bttv_tvcards[btv->c.type].video_inputs)			return -EINVAL;		memset(i,0,sizeof(*i));		i->index    = n;		i->type     = V4L2_INPUT_TYPE_CAMERA;		i->audioset = 0;		if (i->index == bttv_tvcards[btv->c.type].tuner) {			sprintf(i->name, "Television");			i->type  = V4L2_INPUT_TYPE_TUNER;			i->tuner = 0;		} else if (i->index == btv->svhs) {			sprintf(i->name, "S-Video");		} else {			sprintf(i->name,"Composite%d",i->index);		}		if (i->index == btv->input) {			__u32 dstatus = btread(BT848_DSTATUS);			if (0 == (dstatus & BT848_DSTATUS_PRES))				i->status |= V4L2_IN_ST_NO_SIGNAL;			if (0 == (dstatus & BT848_DSTATUS_HLOC))				i->status |= V4L2_IN_ST_NO_H_LOCK;		}		for (n = 0; n < BTTV_TVNORMS; n++)			i->std |= bttv_tvnorms[n].v4l2_id;		return 0;	}	case VIDIOC_G_INPUT:	{		int *i = arg;		*i = btv->input;		return 0;	}	case VIDIOC_S_INPUT:	{		unsigned int *i = arg;		if (*i > bttv_tvcards[btv->c.type].video_inputs)			return -EINVAL;		down(&btv->lock);		set_input(btv,*i);		up(&btv->lock);		return 0;	}	case VIDIOC_G_TUNER:	{		struct v4l2_tuner *t = arg;		if (UNSET == bttv_tvcards[btv->c.type].tuner)			return -EINVAL;		if (0 != t->index)			return -EINVAL;		down(&btv->lock);		memset(t,0,sizeof(*t));		strcpy(t->name, "Television");		t->type       = V4L2_TUNER_ANALOG_TV;		t->capability = V4L2_TUNER_CAP_NORM;		t->rxsubchans = V4L2_TUNER_SUB_MONO;		if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)			t->signal = 0xffff;		{			struct video_tuner tuner;			memset(&tuner, 0, sizeof (tuner));			tuner.rangehigh = 0xffffffffUL;			bttv_call_i2c_clients(btv, VIDIOCGTUNER, &tuner);			t->rangelow = tuner.rangelow;			t->rangehigh = tuner.rangehigh;		}		{			/* Hmmm ... */			struct video_audio va;			memset(&va, 0, sizeof(struct video_audio));			bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);			if (btv->audio_hook)				btv->audio_hook(btv,&va,0);			if(va.mode & VIDEO_SOUND_STEREO) {				t->audmode     = V4L2_TUNER_MODE_STEREO;				t->rxsubchans |= V4L2_TUNER_SUB_STEREO;			}			if(va.mode & VIDEO_SOUND_LANG1) {				t->audmode    = V4L2_TUNER_MODE_LANG1;				t->rxsubchans = V4L2_TUNER_SUB_LANG1					| V4L2_TUNER_SUB_LANG2;			}		}		/* FIXME: fill capability+audmode */		up(&btv->lock);		return 0;	}	case VIDIOC_S_TUNER:	{		struct v4l2_tuner *t = arg;		if (UNSET == bttv_tvcards[btv->c.type].tuner)			return -EINVAL;		if (0 != t->index)			return -EINVAL;		down(&btv->lock);		{			struct video_audio va;			memset(&va, 0, sizeof(struct video_audio));			bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);			if (t->audmode == V4L2_TUNER_MODE_MONO)				va.mode = VIDEO_SOUND_MONO;			else if (t->audmode == V4L2_TUNER_MODE_STEREO)				va.mode = VIDEO_SOUND_STEREO;			else if (t->audmode == V4L2_TUNER_MODE_LANG1)				va.mode = VIDEO_SOUND_LANG1;			else if (t->audmode == V4L2_TUNER_MODE_LANG2)				va.mode = VIDEO_SOUND_LANG2;			bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va);			if (btv->audio_hook)				btv->audio_hook(btv,&va,1);		}		up(&btv->lock);		return 0;	}	case VIDIOC_G_FREQUENCY:	{		struct v4l2_frequency *f = arg;		memset(f,0,sizeof(*f));		f->type = V4L2_TUNER_ANALOG_TV;		f->frequency = btv->freq;		return 0;	}	case VIDIOC_S_FREQUENCY:	{		struct v4l2_frequency *f = arg;		if (unlikely(f->tuner != 0))			return -EINVAL;		if (unlikely (f->type != V4L2_TUNER_ANALOG_TV))			return -EINVAL;		down(&btv->lock);		btv->freq = f->frequency;		bttv_call_i2c_clients(btv,VIDIOCSFREQ,&btv->freq);		if (btv->has_matchbox && btv->radio_user)			tea5757_set_freq(btv,btv->freq);		up(&btv->lock);		return 0;	}	case VIDIOC_LOG_STATUS:	{		bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);		return 0;	}	default:		return -ENOIOCTLCMD;	}	return 0;}static int verify_window(const struct bttv_tvnorm *tvn,			 struct v4l2_window *win, int fixup){	enum v4l2_field field;	int maxw, maxh;	if (win->w.width  < 48 || win->w.height < 32)		return -EINVAL;	if (win->clipcount > 2048)		return -EINVAL;	field = win->field;	maxw  = tvn->swidth;	maxh  = tvn->sheight;	if (V4L2_FIELD_ANY == field) {		field = (win->w.height > maxh/2)			? V4L2_FIELD_INTERLACED			: V4L2_FIELD_TOP;	}	switch (field) {	case V4L2_FIELD_TOP:	case V4L2_FIELD_BOTTOM:		maxh = maxh / 2;		break;	case V4L2_FIELD_INTERLACED:		break;	default:		return -EINVAL;	}	if (!fixup && (win->w.width > maxw || win->w.height > maxh))		return -EINVAL;	if (win->w.width > maxw)		win->w.width = maxw;	if (win->w.height > maxh)		win->w.height = maxh;	win->field = field;	return 0;}static int setup_window(struct bttv_fh *fh, struct bttv *btv,			struct v4l2_window *win, int fixup){	struct v4l2_clip *clips = NULL;	int n,size,retval = 0;	if (NULL == fh->ovfmt)		return -EINVAL;	if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))		return -EINVAL;	retval = verify_window(&bttv_tvnorms[btv->tvnorm],win,fixup);	if (0 != retval)		return retval;	/* copy clips  --  luckily v4l1 + v4l2 are binary	   compatible here ...*/	n = win->clipcount;	size = sizeof(*clips)*(n+4);	clips = kmalloc(size,GFP_KERNEL);	if (NULL == clips)		return -ENOMEM;	if (n > 0) {		if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) {			kfree(clips);			return -EFAULT;		}	}	/* clip against screen */	if (NULL != btv->fbuf.base)		n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,				      &win->w, clips, n);	btcx_sort_clips(clips,n);	/* 4-byte alignments */	switch (fh->ovfmt->depth) {	case 8:	case 24:		btcx_align(&win->w, clips, n, 3);		break;	case 16:		btcx_align(&win->w, clips, n, 1);		break;	case 32:		/* no alignment fixups needed */		break;	default:		BUG();	}	down(&fh->cap.lock);		kfree(fh->ov.clips);	fh->ov.clips    = clips;	fh->ov.nclips   = n;	fh->ov.w        = win->w;	fh->ov.field    = win->field;	fh->ov.setup_ok = 1;	btv->init.ov.w.width   = win->w.width;	btv->init.ov.w.height  = win->w.height;	btv->init.ov.field     = win->field;	/* update overlay if needed */	retval = 0;	if (check_btres(fh, RESOURCE_OVERLAY)) {		struct bttv_buffer *new;		new = videobuf_alloc(sizeof(*new));		bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);		retval = bttv_switch_overlay(btv,fh,new);	}	up(&fh->cap.lock);	return retval;}/* ----------------------------------------------------------------------- */static struct videobuf_queue* bttv_queue(struct bttv_fh *fh){	struct videobuf_queue* q = NULL;	switch (fh->type) {	case V4L2_BUF_TYPE_VIDEO_CAPTURE:		q = &fh->cap;		break;	case V4L2_BUF_TYPE_VBI_CAPTURE:		q = &fh->vbi;		break;	default:		BUG();	}	return q;}static int bttv_resource(struct bttv_fh *fh){	int res = 0;	switch (fh->type) {	case V4L2_BUF_TYPE_VIDEO_CAPTURE:		res = RESOURCE_VIDEO;		break;	case V4L2_BUF_TYPE_VBI_CAPTURE:		res = RESOURCE_VBI;		break;	default:		BUG();	}	return res;}static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type){	struct videobuf_queue *q = bttv_queue(fh);	int res = bttv_resource(fh);	if (check_btres(fh,res))		return -EBUSY;	if (videobuf_queue_is_busy(q))		return -EBUSY;	fh->type = type;	return 0;}static voidpix_format_set_size     (struct v4l2_pix_format *       f,			 const struct bttv_format *     fmt,			 unsigned int                   width,			 unsigned int                   height){	f->width = width;	f->height = height;	if (fmt->flags & FORMAT_FLAGS_PLANAR) {		f->bytesperline = width; /* Y plane */		f->sizeimage = (width * height * fmt->depth) >> 3;	} else {		f->bytesperline = (width * fmt->depth) >> 3;		f->sizeimage = height * f->bytesperline;	}}static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f){	switch (f->type) {

⌨️ 快捷键说明

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