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

📄 bttv-driver.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
📖 第 1 页 / 共 5 页
字号:
{	struct bttv *btv=(struct bttv *)dev; 	unsigned long irq_flags;	int need_wait;	down(&btv->lock);	btv->user--;	spin_lock_irqsave(&btv->s_lock, irq_flags);	need_wait = (-1 != btv->gq_grab);	btv->gq_start = 0;	btv->gq_in = 0;	btv->gq_out = 0;	btv->gq_grab = -1;	btv->scr_on = 0;	btv->risc_cap_odd = 0;	btv->risc_cap_even = 0;	bt848_set_risc_jmps(btv,-1);	spin_unlock_irqrestore(&btv->s_lock, irq_flags);	/*	 *	A word of warning. At this point the chip	 *	is still capturing because its FIFO hasn't emptied	 *	and the DMA control operations are posted PCI 	 *	operations.	 */	btread(BT848_I2C); 	/* This fixes the PCI posting delay */		if (need_wait) {		/*		 *	This is sucky but right now I can't find a good way to		 *	be sure its safe to free the buffer. We wait 5-6 fields		 *	which is more than sufficient to be sure.		 */		current->state = TASK_UNINTERRUPTIBLE;		schedule_timeout(HZ/10);	/* Wait 1/10th of a second */	}		/*	 *	We have allowed it to drain.	 */	if(btv->fbuffer)		rvfree((void *) btv->fbuffer, gbuffers*gbufsize);	btv->fbuffer=0;	up(&btv->lock);}/***********************************//* ioctls and supporting functions *//***********************************/static inline void bt848_bright(struct bttv *btv, uint bright){	btwrite(bright&0xff, BT848_BRIGHT);}static inline void bt848_hue(struct bttv *btv, uint hue){	btwrite(hue&0xff, BT848_HUE);}static inline void bt848_contrast(struct bttv *btv, uint cont){	unsigned int conthi;	conthi=(cont>>6)&4;	btwrite(cont&0xff, BT848_CONTRAST_LO);	btaor(conthi, ~4, BT848_E_CONTROL);	btaor(conthi, ~4, BT848_O_CONTROL);}static inline void bt848_sat_u(struct bttv *btv, unsigned long data){	u32 datahi;	datahi=(data>>7)&2;	btwrite(data&0xff, BT848_SAT_U_LO);	btaor(datahi, ~2, BT848_E_CONTROL);	btaor(datahi, ~2, BT848_O_CONTROL);}static inline void bt848_sat_v(struct bttv *btv, unsigned long data){	u32 datahi;	datahi=(data>>8)&1;	btwrite(data&0xff, BT848_SAT_V_LO);	btaor(datahi, ~1, BT848_E_CONTROL);	btaor(datahi, ~1, BT848_O_CONTROL);}/* *	ioctl routine */static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg){	struct bttv *btv=(struct bttv *)dev; 	unsigned long irq_flags; 	int ret = 0;	if (bttv_debug > 1)		printk("bttv%d: ioctl 0x%x\n",btv->nr,cmd);	switch (cmd) {	case VIDIOCGCAP:	{		struct video_capability b;		strcpy(b.name,btv->video_dev.name);		b.type = VID_TYPE_CAPTURE|			((bttv_tvcards[btv->type].tuner != UNSET) ? VID_TYPE_TUNER : 0) |			VID_TYPE_OVERLAY|			VID_TYPE_CLIPPING|			VID_TYPE_FRAMERAM|			VID_TYPE_SCALES;		b.channels = bttv_tvcards[btv->type].video_inputs;		b.audios = bttv_tvcards[btv->type].audio_inputs;		b.maxwidth = tvnorms[btv->win.norm].swidth;		b.maxheight = tvnorms[btv->win.norm].sheight;		b.minwidth = 48;		b.minheight = 32;		if(copy_to_user(arg,&b,sizeof(b)))			return -EFAULT;		return 0;	}	case VIDIOCGCHAN:	{		struct video_channel v;		unsigned int  channel;		if(copy_from_user(&v, arg,sizeof(v)))			return -EFAULT;		channel = v.channel;		if (channel>=bttv_tvcards[btv->type].video_inputs)			return -EINVAL;		v.flags=VIDEO_VC_AUDIO;		v.tuners=0;		v.type=VIDEO_TYPE_CAMERA;		v.norm = btv->win.norm;		if(channel==bttv_tvcards[btv->type].tuner) 		{			strcpy(v.name,"Television");			v.flags|=VIDEO_VC_TUNER;			v.type=VIDEO_TYPE_TV;			v.tuners=1;		} 		else if (channel==bttv_tvcards[btv->type].svhs) 			strcpy(v.name,"S-Video");		else if (bttv_tvcards[btv->type].muxsel[v.channel] < 0)			strcpy(v.name,"Digital Video");		else			sprintf(v.name,"Composite%d",v.channel);				if(copy_to_user(arg,&v,sizeof(v)))			return -EFAULT;		return 0;	}	/*	 *	Each channel has 1 tuner	 */	case VIDIOCSCHAN:	{		struct video_channel v;		unsigned int  channel;		if(copy_from_user(&v, arg,sizeof(v)))			return -EFAULT;		channel = v.channel;				if (channel>bttv_tvcards[btv->type].video_inputs)			return -EINVAL;		if (v.norm > TVNORMS)			return -EOPNOTSUPP;		bttv_call_i2c_clients(btv,cmd,&v);		down(&btv->lock);		bt848_muxsel(btv, channel);		bttv_set_norm(btv, v.norm);		up(&btv->lock);		return 0;	}	case VIDIOCGTUNER:	{		struct video_tuner v;		if(copy_from_user(&v,arg,sizeof(v))!=0)			return -EFAULT;#if 0 /* tuner.signal might be of intrest for non-tuner sources too ... */		if(v.tuner||btv->channel)	/* Only tuner 0 */			return -EINVAL;#endif		strcpy(v.name, "Television");		v.rangelow=0;		v.rangehigh=0xFFFFFFFF;		v.flags=VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;		v.mode = btv->win.norm;		v.signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0;		bttv_call_i2c_clients(btv,cmd,&v);		if(copy_to_user(arg,&v,sizeof(v)))			return -EFAULT;		return 0;	}	/* We have but one tuner */	case VIDIOCSTUNER:	{		struct video_tuner v;		unsigned int tuner;				if(copy_from_user(&v, arg, sizeof(v)))			return -EFAULT;		tuner = v.tuner;		/* Only one channel has a tuner */		if(tuner!=bttv_tvcards[btv->type].tuner)			return -EINVAL; 						if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC		   &&v.mode!=VIDEO_MODE_SECAM)			return -EOPNOTSUPP;		bttv_call_i2c_clients(btv,cmd,&v);		if (btv->win.norm != v.mode) {                        down(&btv->lock);			bttv_set_norm(btv,v.mode);			up(&btv->lock);		}		return 0;	}	case VIDIOCGPICT:	{		struct video_picture p=btv->picture;		if(copy_to_user(arg, &p, sizeof(p)))			return -EFAULT;		return 0;	}	case VIDIOCSPICT:	{		struct video_picture p;		if (copy_from_user(&p, arg,sizeof(p)))			return -EFAULT;		if (p.palette > PALETTEFMT_MAX)			return -EINVAL;		if (UNSET == palette2fmt[p.palette])			return -EINVAL;		down(&btv->lock);		/* We want -128 to 127 we get 0-65535 */		bt848_bright(btv, (p.brightness>>8)-128);		/* 0-511 for the colour */		bt848_sat_u(btv, p.colour>>7);		bt848_sat_v(btv, ((p.colour>>7)*201L)/237);		/* -128 to 127 */		bt848_hue(btv, (p.hue>>8)-128);		/* 0-511 */		bt848_contrast(btv, p.contrast>>7);		btv->picture = p;		up(&btv->lock);		return 0;	}	case VIDIOCSWIN:	{		struct video_window vw;		struct video_clip *vcp = NULL;					if(copy_from_user(&vw,arg,sizeof(vw)))			return -EFAULT;		down(&btv->lock);		if(vw.flags || vw.width < 16 || vw.height < 16) 		{			spin_lock_irqsave(&btv->s_lock, irq_flags);			btv->scr_on = 0;			bt848_set_risc_jmps(btv,-1);			spin_unlock_irqrestore(&btv->s_lock, irq_flags);			up(&btv->lock);			return -EINVAL;		}		if (btv->win.bpp < 4) 		{	/* adjust and align writes */			vw.x = (vw.x + 3) & ~3;			vw.width &= ~3;		}		if (btv->needs_restart)			bt848_restart(btv);		btv->win.x=vw.x;		btv->win.y=vw.y;		btv->win.width=vw.width;		btv->win.height=vw.height;				spin_lock_irqsave(&btv->s_lock, irq_flags);		bt848_set_risc_jmps(btv,0);		bt848_set_winsize(btv);		spin_unlock_irqrestore(&btv->s_lock, irq_flags);		/*		 *	Do any clips.		 */		if(vw.clipcount<0) {			if((vcp=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) {				up(&btv->lock);				return -ENOMEM;			}			if(copy_from_user(vcp, vw.clips,					  VIDEO_CLIPMAP_SIZE)) {				up(&btv->lock);				vfree(vcp);				return -EFAULT;			}		} else if (vw.clipcount > 2048) {			up(&btv->lock);			return -EINVAL;		} else if (vw.clipcount) {			if((vcp=vmalloc(sizeof(struct video_clip)*					(vw.clipcount))) == NULL) {				up(&btv->lock);				return -ENOMEM;			}			if(copy_from_user(vcp,vw.clips,					  sizeof(struct video_clip)*					  vw.clipcount)) {				up(&btv->lock);				vfree(vcp);				return -EFAULT;			}		}		make_clip_tab(btv, vcp, vw.clipcount);		if (vw.clipcount != 0)			vfree(vcp);		spin_lock_irqsave(&btv->s_lock, irq_flags);		bt848_set_risc_jmps(btv,-1);		spin_unlock_irqrestore(&btv->s_lock, irq_flags);		up(&btv->lock);		return 0;	}	case VIDIOCGWIN:	{		struct video_window vw;		memset(&vw,0,sizeof(vw));		vw.x=btv->win.x;		vw.y=btv->win.y;		vw.width=btv->win.width;		vw.height=btv->win.height;		if(btv->win.interlace)			vw.flags|=VIDEO_WINDOW_INTERLACE;		if(copy_to_user(arg,&vw,sizeof(vw)))			return -EFAULT;		return 0;	}	case VIDIOCCAPTURE:	{		int v;		if(copy_from_user(&v, arg,sizeof(v)))			return -EFAULT;		if(btv->win.vidadr == 0)			return -EINVAL;		if (btv->win.width==0 || btv->win.height==0)			return -EINVAL;		if (1 == no_overlay)			return -EIO;		spin_lock_irqsave(&btv->s_lock, irq_flags);		if (v == 1 && btv->win.vidadr != 0)			btv->scr_on = 1;		if (v == 0)			btv->scr_on = 0;		bt848_set_risc_jmps(btv,-1);		spin_unlock_irqrestore(&btv->s_lock, irq_flags);		return 0;	}	case VIDIOCGFBUF:	{		struct video_buffer v;		v.base=(void *)btv->win.vidadr;		v.height=btv->win.sheight;		v.width=btv->win.swidth;		v.depth=btv->win.depth;		v.bytesperline=btv->win.bpl;		if(copy_to_user(arg, &v,sizeof(v)))			return -EFAULT;		return 0;				}	case VIDIOCSFBUF:	{		struct video_buffer v;		if(!capable(CAP_SYS_ADMIN) &&		   !capable(CAP_SYS_RAWIO))			return -EPERM;		if(copy_from_user(&v, arg,sizeof(v)))			return -EFAULT;		if(v.depth!=8 && v.depth!=15 && v.depth!=16 && 		   v.depth!=24 && v.depth!=32 && v.width > 16 &&		   v.height > 16 && v.bytesperline > 16)			return -EINVAL;		down(&btv->lock);		if (v.base)			btv->win.vidadr=(unsigned long)v.base;		btv->win.sheight=v.height;		btv->win.swidth=v.width;		btv->win.bpp=((v.depth+7)&0x38)/8;		btv->win.depth=v.depth;		btv->win.bpl=v.bytesperline;#if 0 /* was broken for ages and nobody noticed.  Looks like we don't need	 it any more as everybody explicitly sets the palette using VIDIOCSPICT	 these days */		/* set sefault color format */		switch (v.depth) {		case  8: btv->picture.palette = VIDEO_PALETTE_HI240;  break;		case 15: btv->picture.palette = VIDEO_PALETTE_RGB555; break;		case 16: btv->picture.palette = VIDEO_PALETTE_RGB565; break;		case 24: btv->picture.palette = VIDEO_PALETTE_RGB24;  break;		case 32: btv->picture.palette = VIDEO_PALETTE_RGB32;  break;		}#endif			if (bttv_debug)			printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n",			       v.base, v.width,v.height, btv->win.bpp, btv->win.bpl);		spin_lock_irqsave(&btv->s_lock, irq_flags);		bt848_set_winsize(btv);		spin_unlock_irqrestore(&btv->s_lock, irq_flags);		up(&btv->lock);		return 0;			}	case VIDIOCKEY:	{		/* Will be handled higher up .. */		return 0;	}	case VIDIOCGFREQ:	{		unsigned long v=btv->win.freq;		if(copy_to_user(arg,&v,sizeof(v)))			return -EFAULT;		return 0;	}	case VIDIOCSFREQ:	{		unsigned long v;		if(copy_from_user(&v, arg, sizeof(v)))			return -EFAULT;		btv->win.freq=v;		bttv_call_i2c_clients(btv,cmd,&v);#if 1		if (btv->radio && btv->has_matchbox)			tea5757_set_freq(btv,v);#endif		return 0;	}		case VIDIOCGAUDIO:	{		struct video_audio v;		v=btv->audio_dev;		v.flags&=~(VIDEO_AUDIO_MUTE|VIDEO_AUDIO_MUTABLE);		v.flags|=VIDEO_AUDIO_MUTABLE;		strcpy(v.name,"TV");		v.mode = VIDEO_SOUND_MONO;		bttv_call_i2c_clients(btv,cmd,&v);		/* card specific hooks */		if (btv->audio_hook)			btv->audio_hook(btv,&v,0);		if(copy_to_user(arg,&v,sizeof(v)))			return -EFAULT;		return 0;	}	case VIDIOCSAUDIO:	{		struct video_audio v;		unsigned int n;		if(copy_from_user(&v,arg, sizeof(v)))			return -EFAULT;		n = v.audio;		if(n >= bttv_tvcards[btv->type].audio_inputs)			return -EINVAL;		down(&btv->lock);		if(v.flags&VIDEO_AUDIO_MUTE)			audio(btv, AUDIO_MUTE);		/* bt848_muxsel(btv,v.audio); */		if(!(v.flags&VIDEO_AUDIO_MUTE))			audio(btv, AUDIO_UNMUTE);		bttv_call_i2c_clients(btv,cmd,&v);				/* card specific hooks */		if (btv->audio_hook)			btv->audio_hook(btv,&v,1);		btv->audio_dev=v;		up(&btv->lock);		return 0;	}	case VIDIOCSYNC:	{		DECLARE_WAITQUEUE(wait, current);		unsigned int i;		if(copy_from_user((void *)&i,arg,sizeof(int)))			return -EFAULT;		if (i >= gbuffers)			return -EINVAL;		switch (btv->gbuf[i].stat) {		case GBUFFER_UNUSED:

⌨️ 快捷键说明

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