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

📄 bttv-driver.c

📁 V4l driver for DVB HD
💻 C
📖 第 1 页 / 共 5 页
字号:
	}	/* alloc + fill struct bttv_buffer (if changed) */	if (buf->vb.width != width || buf->vb.height != height ||	    buf->vb.field != field ||	    buf->tvnorm != btv->tvnorm || buf->fmt != fmt) {		buf->vb.width  = width;		buf->vb.height = height;		buf->vb.field  = field;		buf->tvnorm    = btv->tvnorm;		buf->fmt       = fmt;		redo_dma_risc = 1;	}	/* alloc risc memory */	if (STATE_NEEDS_INIT == buf->vb.state) {		redo_dma_risc = 1;		if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf)))			goto fail;	}	if (redo_dma_risc)		if (0 != (rc = bttv_buffer_risc(btv,buf)))			goto fail;	buf->vb.state = STATE_PREPARED;	return 0; fail:	bttv_dma_free(q,btv,buf);	return rc;}static intbuffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size){	struct bttv_fh *fh = q->priv_data;	*size = fh->fmt->depth*fh->width*fh->height >> 3;	if (0 == *count)		*count = gbuffers;	while (*size * *count > gbuffers * gbufsize)		(*count)--;	return 0;}static intbuffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,	       enum v4l2_field field){	struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);	struct bttv_fh *fh = q->priv_data;	return bttv_prepare_buffer(q,fh->btv, buf, fh->fmt,				   fh->width, fh->height, field);}static voidbuffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb){	struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);	struct bttv_fh *fh = q->priv_data;	struct bttv    *btv = fh->btv;	buf->vb.state = STATE_QUEUED;	list_add_tail(&buf->vb.queue,&btv->capture);	if (!btv->curr.frame_irq) {		btv->loop_irq |= 1;		bttv_set_dma(btv, 0x03);	}}static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb){	struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);	struct bttv_fh *fh = q->priv_data;	bttv_dma_free(&fh->cap,fh->btv,buf);}static struct videobuf_queue_ops bttv_video_qops = {	.buf_setup    = buffer_setup,	.buf_prepare  = buffer_prepare,	.buf_queue    = buffer_queue,	.buf_release  = buffer_release,};static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg){	switch (cmd) {	case BTTV_VERSION:		return BTTV_VERSION_CODE;	/* ***  v4l1  *** ************************************************ */	case VIDIOCGFREQ:	{		unsigned long *freq = arg;		*freq = btv->freq;		return 0;	}	case VIDIOCSFREQ:	{		struct v4l2_frequency freq;		memset(&freq, 0, sizeof(freq));		freq.frequency = *(unsigned long *)arg;		mutex_lock(&btv->lock);		freq.type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;		btv->freq = *(unsigned long *)arg;		bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,&freq);		if (btv->has_matchbox && btv->radio_user)			tea5757_set_freq(btv,*(unsigned long *)arg);		mutex_unlock(&btv->lock);		return 0;	}	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;		mutex_lock(&btv->lock);		set_tvnorm(btv,v->mode);		bttv_call_i2c_clients(btv,cmd,v);		mutex_unlock(&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;		mutex_lock(&btv->lock);		if (channel == btv->input &&		    v->norm == btv->tvnorm) {			/* nothing to do */			mutex_unlock(&btv->lock);			return 0;		}		btv->tvnorm = v->norm;		set_input(btv,v->channel);		mutex_unlock(&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;		mutex_lock(&btv->lock);		bttv_call_i2c_clients(btv,cmd,v);		/* card specific hooks */		if (btv->audio_hook)			btv->audio_hook(btv,v,0);		mutex_unlock(&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;		mutex_lock(&btv->lock);		audio_mute(btv, (v->flags&VIDEO_AUDIO_MUTE) ? 1 : 0);		bttv_call_i2c_clients(btv,cmd,v);		/* card specific hooks */		if (btv->audio_hook)			btv->audio_hook(btv,v,1);		mutex_unlock(&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;		mutex_lock(&btv->lock);		set_tvnorm(btv,i);		i2c_vidiocschan(btv);		mutex_unlock(&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;		mutex_lock(&btv->lock);		set_input(btv,*i);		mutex_unlock(&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;		mutex_lock(&btv->lock);		memset(t,0,sizeof(*t));		t->rxsubchans = V4L2_TUNER_SUB_MONO;		bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);		strcpy(t->name, "Television");		t->capability = V4L2_TUNER_CAP_NORM;		t->type       = V4L2_TUNER_ANALOG_TV;		if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)			t->signal = 0xffff;		if (btv->audio_hook) {			/* Hmmm ... */			struct video_audio va;			memset(&va, 0, sizeof(struct video_audio));			btv->audio_hook(btv,&va,0);			t->audmode    = V4L2_TUNER_MODE_MONO;			t->rxsubchans = V4L2_TUNER_SUB_MONO;			if(va.mode & VIDEO_SOUND_STEREO) {				t->audmode    = V4L2_TUNER_MODE_STEREO;				t->rxsubchans = V4L2_TUNER_SUB_STEREO;			}			if(va.mode & VIDEO_SOUND_LANG2) {				t->audmode    = V4L2_TUNER_MODE_LANG1;				t->rxsubchans = V4L2_TUNER_SUB_LANG1					| V4L2_TUNER_SUB_LANG2;			}		}		/* FIXME: fill capability+audmode */		mutex_unlock(&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;		mutex_lock(&btv->lock);		bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t);		if (btv->audio_hook) {			struct video_audio va;			memset(&va, 0, sizeof(struct video_audio));			if (t->audmode == V4L2_TUNER_MODE_MONO)				va.mode = VIDEO_SOUND_MONO;			else if (t->audmode == V4L2_TUNER_MODE_STEREO ||				 t->audmode == V4L2_TUNER_MODE_LANG1_LANG2)				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;			btv->audio_hook(btv,&va,1);		}		mutex_unlock(&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;		mutex_lock(&btv->lock);		btv->freq = f->frequency;		bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,f);		if (btv->has_matchbox && btv->radio_user)			tea5757_set_freq(btv,btv->freq);		mutex_unlock(&btv->lock);		return 0;	}	case VIDIOC_LOG_STATUS:	{		printk(KERN_INFO "bttv%d: =================  START STATUS CARD #%d  =================\n", btv->c.nr, btv->c.nr);		bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);		printk(KERN_INFO "bttv%d: ==================  END STATUS CARD #%d  ==================\n", btv->c.nr, btv->c.nr);		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 */

⌨️ 快捷键说明

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