Enscript Output

extractedLnx/linux/drivers/char/bttv.c_bttv_ioctl.c

static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
{
	struct bttv *btv=(struct bttv *)dev;
 	int i;

	switch (cmd) {
	case VIDIOCGCAP:
	{
		struct video_capability b;
		strcpy(b.name,btv->video_dev.name);
		b.type = VID_TYPE_CAPTURE|
			((tvcards[btv->type].tuner != -1) ? VID_TYPE_TUNER : 0) |
			VID_TYPE_OVERLAY|
			VID_TYPE_CLIPPING|
			VID_TYPE_FRAMERAM|
			VID_TYPE_SCALES;
		b.channels = tvcards[btv->type].video_inputs;
		b.audios = tvcards[btv->type].audio_inputs;
		b.maxwidth = tvnorms[btv->win.norm].swidth;
		b.maxheight = tvnorms[btv->win.norm].sheight;
		b.minwidth = 32;
		b.minheight = 32;
		if(copy_to_user(arg,&b,sizeof(b)))
			return -EFAULT;
		return 0;
	}
	case VIDIOCGCHAN:
	{
		struct video_channel v;
		if(copy_from_user(&v, arg,sizeof(v)))
			return -EFAULT;
		v.flags=VIDEO_VC_AUDIO;
		v.tuners=0;
		v.type=VIDEO_TYPE_CAMERA;
		v.norm = btv->win.norm;
		if (v.channel>=tvcards[btv->type].video_inputs)
			return -EINVAL;
		if(v.channel==tvcards[btv->type].tuner) 
		{
			strcpy(v.name,"Television");
			v.flags|=VIDEO_VC_TUNER;
			v.type=VIDEO_TYPE_TV;
			v.tuners=1;
		} 
		else if(v.channel==tvcards[btv->type].svhs) 
			strcpy(v.name,"S-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;
		if(copy_from_user(&v, arg,sizeof(v)))
			return -EFAULT;
		
		if (v.channel>tvcards[btv->type].video_inputs)
			return -EINVAL;
		if (v.norm > (sizeof(tvnorms)/sizeof(*tvnorms)))
			return -EOPNOTSUPP;

		call_i2c_clients(btv,cmd,&v);
		down(&btv->lock);
		bt848_muxsel(btv, v.channel);
		btv->channel=v.channel;
		if (btv->win.norm != v.norm) {
			btv->win.norm = v.norm;
			make_vbitab(btv);
			bt848_set_winsize(btv);
		}
		up(&btv->lock);
		return 0;
	}
	case VIDIOCGTUNER:
	{
		struct video_tuner v;
		if(copy_from_user(&v,arg,sizeof(v))!=0)
			return -EFAULT;
		if(v.tuner||btv->channel)	/* Only tuner 0 */
			return -EINVAL;
		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;
		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;
		if(copy_from_user(&v, arg, sizeof(v)))
			return -EFAULT;
		/* Only one channel has a tuner */
		if(v.tuner!=tvcards[btv->type].tuner)
			return -EINVAL;
 				
		if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC
		   &&v.mode!=VIDEO_MODE_SECAM)
			return -EOPNOTSUPP;
		call_i2c_clients(btv,cmd,&v);
		if (btv->win.norm != v.mode) {
			btv->win.norm = v.mode;
                        down(&btv->lock);
			make_vbitab(btv);
			bt848_set_winsize(btv);
			up(&btv->lock);
		}
		return 0;
	}
	case VIDIOCGPICT:
	{
		struct video_picture p=btv->picture;
		if(btv->win.depth==8)
			p.palette=VIDEO_PALETTE_HI240;
		if(btv->win.depth==15)
			p.palette=VIDEO_PALETTE_RGB555;
		if(btv->win.depth==16)
			p.palette=VIDEO_PALETTE_RGB565;
		if(btv->win.depth==24)
			p.palette=VIDEO_PALETTE_RGB24;
		if(btv->win.depth==32)
			p.palette=VIDEO_PALETTE_RGB32;
			
		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;
		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;
		int on;
			
		if(copy_from_user(&vw,arg,sizeof(vw)))
			return -EFAULT;
				
		if(vw.flags || vw.width < 16 || vw.height < 16) 
		{
                        down(&btv->lock);
			bt848_cap(btv,0);
			up(&btv->lock);
			return -EINVAL;
		}		
		if (btv->win.bpp < 4) 
		{	/* adjust and align writes */
			vw.x = (vw.x + 3) & ~3;
			vw.width &= ~3;
		}
		down(&btv->lock);
		btv->win.use_yuv=0;
		btv->win.x=vw.x;
		btv->win.y=vw.y;
		btv->win.width=vw.width;
		btv->win.height=vw.height;

		on=(btv->cap&3);
			
		bt848_cap(btv,0);
		bt848_set_winsize(btv);
		up(&btv->lock);

		/*
		 *	Do any clips.
		 */
		if(vw.clipcount<0) {
			if((vcp=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL)
				return -ENOMEM;
			if(copy_from_user(vcp, vw.clips,
					  VIDEO_CLIPMAP_SIZE)) {
				vfree(vcp);
				return -EFAULT;
			}
		} else if (vw.clipcount) {
			if((vcp=vmalloc(sizeof(struct video_clip)*
					(vw.clipcount))) == NULL)
				return -ENOMEM;
			if(copy_from_user(vcp,vw.clips,
					  sizeof(struct video_clip)*
					  vw.clipcount)) {
				vfree(vcp);
				return -EFAULT;
			}
		}
		down(&btv->lock);
		make_clip_tab(btv, vcp, vw.clipcount);
		if (vw.clipcount != 0)
			vfree(vcp);
		if(on && btv->win.vidadr!=0)
			bt848_cap(btv,1);
		up(&btv->lock);
		return 0;
	}
	case VIDIOCSWIN2:
	{
		/* experimental -- right now it handles unclipped yuv data only */
		struct video_window2 vo;
		__u32 fbsize;
		int on;
			
		if(copy_from_user(&vo,arg,sizeof(vo)))
			return -EFAULT;

		fbsize = btv->win.sheight * btv->win.bpl;
		if (vo.start + vo.pitch*vo.height > fbsize)
			return -EINVAL;
                if (vo.palette != VIDEO_PALETTE_YUV422)
			return -EINVAL;
		
		down(&btv->lock);
		btv->win.use_yuv=1;
		memcpy(&btv->win.win2,&vo,sizeof(vo));
		btv->win.width=vo.width;
		btv->win.height=vo.height;

		on=(btv->cap&3);
		bt848_cap(btv,0);
		bt848_set_winsize(btv);
		make_clip_tab(btv, NULL, 0);
		if(on && btv->win.vidadr!=0)
			bt848_cap(btv,1);
		up(&btv->lock);
		return 0;
	}
	case VIDIOCGWIN:
	{
		struct video_window vw;
		/* Oh for a COBOL move corresponding .. */
		vw.x=btv->win.x;
		vw.y=btv->win.y;
		vw.width=btv->win.width;
		vw.height=btv->win.height;
		vw.chromakey=0;
		vw.flags=0;
		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 (0 == btv->win.use_yuv && (btv->win.width==0 || btv->win.height==0))
			return -EINVAL;
		down(&btv->lock);
		if(v==0)
			bt848_cap(btv,0);
		else
			bt848_cap(btv,1);
		up(&btv->lock);
		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;
			
		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));
		bt848_set_winsize(btv);
		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;
		call_i2c_clients(btv,cmd,&v);
		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;
		call_i2c_clients(btv,cmd,&v);

		if (btv->type == BTTV_TERRATV) {
			v.mode  = VIDEO_SOUND_MONO;
			v.mode |= VIDEO_SOUND_STEREO;
			v.mode |= VIDEO_SOUND_LANG1|VIDEO_SOUND_LANG2;

		} else if (btv->audio_chip == TDA9840) {
			/* begin of Horrible Hack <grin@tolna.net> */
			v.flags|=VIDEO_AUDIO_VOLUME;
			v.mode  = VIDEO_SOUND_MONO;
			v.mode |= VIDEO_SOUND_STEREO;
			v.mode |= VIDEO_SOUND_LANG1|VIDEO_SOUND_LANG2;
			v.volume = 32768;       /* fixme */
			v.step = 4096;
		}

#if 0
#warning this should be handled by tda9855.c
		else if (btv->audio_chip == TDA9850) {
			unsigned char ALR1;
			v.flags|=VIDEO_AUDIO_VOLUME;
			ALR1 = I2CRead(btv, I2C_TDA9850|1);
			v.mode = VIDEO_SOUND_MONO;
			v.mode |= (ALR1 & 32) ? VIDEO_SOUND_STEREO:0;
			v.mode |= (ALR1 & 32) ? VIDEO_SOUND_LANG1:0;
			v.volume = 32768;       /* fixme */
			v.step = 4096;
		}
#endif
		if(copy_to_user(arg,&v,sizeof(v)))
			return -EFAULT;
		return 0;
	}
	case VIDIOCSAUDIO:
	{
		struct video_audio v;

		if(copy_from_user(&v,arg, sizeof(v)))
			return -EFAULT;
		down(&btv->lock);
		if(v.flags&VIDEO_AUDIO_MUTE)
			audio(btv, AUDIO_MUTE, 1);
		/* One audio source per tuner -- huh? <GA> */
		if(v.audio<0 || v.audio >= tvcards[btv->type].audio_inputs) {
			up(&btv->lock);
			return -EINVAL;
		}
		/* bt848_muxsel(btv,v.audio); */
		if(!(v.flags&VIDEO_AUDIO_MUTE))
			audio(btv, AUDIO_UNMUTE, 1);

		up(&btv->lock);
		call_i2c_clients(btv,cmd,&v);
		down(&btv->lock);
		
		if (btv->type == BTTV_TERRATV) {
			unsigned int con = 0;
			btor(0x180000, BT848_GPIO_OUT_EN);
			if (v.mode & VIDEO_SOUND_LANG2)
				con = 0x080000;
			if (v.mode & VIDEO_SOUND_STEREO)
				con = 0x180000;
			btaor(con, ~0x180000, BT848_GPIO_DATA);

		} else if (btv->type == BTTV_WINVIEW_601) { 
			/* PT2254A programming Jon Tombs, jon@gte.esi.us.es */
			int bits_out, loops, vol, data;
			
			/* 32 levels logarithmic */
			vol = 32 - ((v.volume>>11));
			/* units */
			bits_out = (PT2254_DBS_IN_2>>(vol%5));
			/* tens */
			bits_out |= (PT2254_DBS_IN_10>>(vol/5));
			bits_out |= PT2254_L_CHANEL | PT2254_R_CHANEL;
			data = btread(BT848_GPIO_DATA);
			data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA|
				  WINVIEW_PT2254_STROBE);
			for (loops = 17; loops >= 0 ; loops--) {
                                if (bits_out & (1<<loops))
					data |=  WINVIEW_PT2254_DATA;
                                else
					data &= ~WINVIEW_PT2254_DATA;
				btwrite(data, BT848_GPIO_DATA);
				udelay(5);
				data |= WINVIEW_PT2254_CLK;
				btwrite(data, BT848_GPIO_DATA);
				udelay(5);
				data &= ~WINVIEW_PT2254_CLK;
				btwrite(data, BT848_GPIO_DATA);
			}
			data |=  WINVIEW_PT2254_STROBE;
			data &= ~WINVIEW_PT2254_DATA;
			btwrite(data, BT848_GPIO_DATA);
			udelay(10);                     
			data &= ~WINVIEW_PT2254_STROBE;
			btwrite(data, BT848_GPIO_DATA);

#if 0
#warning this should be handled by tda9855.c
		} else if (btv->audio_chip == TDA9850) {
			unsigned char con3 = 0;
			if (v.mode & VIDEO_SOUND_LANG1)
				con3 = 0x80;	/* sap */
			if (v.mode & VIDEO_SOUND_STEREO)
				con3 = 0x40;	/* stereo */
			I2CWrite(btv, I2C_TDA9850,
				 TDA9850_CON3, con3, 1);
			if (v.flags & VIDEO_AUDIO_VOLUME)
				I2CWrite(btv, I2C_TDA9850,
					 TDA9850_CON4,
					 (v.volume>>12) & 15, 1);
#endif
		}
		btv->audio_dev=v;
		up(&btv->lock);
		return 0;
	}

	case VIDIOCSYNC:
		if(copy_from_user((void *)&i,arg,sizeof(int)))
			return -EFAULT;
		switch (btv->frame_stat[i]) {
		case GBUFFER_UNUSED:
			return -EINVAL;
		case GBUFFER_GRABBING:
			while(btv->frame_stat[i]==GBUFFER_GRABBING) {
				interruptible_sleep_on(&btv->capq);
				if(signal_pending(current))
					return -EINTR;
			}
                                /* fall */
		case GBUFFER_DONE:
			btv->frame_stat[i] = GBUFFER_UNUSED;
			break;
		}
		return 0;

	case BTTV_FIELDNR: 
		if(copy_to_user((void *) arg, (void *) &btv->last_field, 
				sizeof(btv->last_field)))
			return -EFAULT;
		break;
      
	case BTTV_PLLSET: {
		struct bttv_pll_info p;
		if(!capable(CAP_SYS_ADMIN))
			return -EPERM;
		if(copy_from_user(&p , (void *) arg, sizeof(btv->pll)))
			return -EFAULT;
		down(&btv->lock);
		btv->pll.pll_ifreq = p.pll_ifreq;
		btv->pll.pll_ofreq = p.pll_ofreq;
		btv->pll.pll_crystal = p.pll_crystal;
		up(&btv->lock);

		break;
	}

	case VIDIOCMCAPTURE:
	{
		struct video_mmap vm;
		int ret;
		if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm)))
			return -EFAULT;
		if (btv->frame_stat[vm.frame] == GBUFFER_GRABBING)
			return -EBUSY;
		down(&btv->lock);
		ret = vgrab(btv, &vm);
		up(&btv->lock);
		return ret;
	}
		
	case VIDIOCGMBUF:
	{
		struct video_mbuf vm;
		memset(&vm, 0 , sizeof(vm));
		vm.size=BTTV_MAX_FBUF*MAX_GBUFFERS;
		vm.frames=MAX_GBUFFERS;
		vm.offsets[0]=0;
		vm.offsets[1]=BTTV_MAX_FBUF;
		if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
			return -EFAULT;
		return 0;
	}
		
	case VIDIOCGUNIT:
	{
		struct video_unit vu;
		vu.video=btv->video_dev.minor;
		vu.vbi=btv->vbi_dev.minor;
		if(btv->radio_dev.minor!=-1)
			vu.radio=btv->radio_dev.minor;
		else
			vu.radio=VIDEO_NO_UNIT;
		vu.audio=VIDEO_NO_UNIT;
#if 0
		AUDIO(AUDC_GET_UNIT, &vu.audio);
#endif
		vu.teletext=VIDEO_NO_UNIT;
		if(copy_to_user((void *)arg, (void *)&vu, sizeof(vu)))
			return -EFAULT;
		return 0;
	}
		
	case BTTV_BURST_ON:
	{
		burst(1);
		return 0;
	}

	case BTTV_BURST_OFF:
	{
		burst(0);
		return 0;
	}

	case BTTV_VERSION:
	{
		return BTTV_VERSION_CODE;
	}
                        
	case BTTV_PICNR:
	{
		/* return picture;*/
		return  0;
	}
                        
	default:
		return -ENOIOCTLCMD;
	}
	return 0;
}

Generated by GNU enscript 1.6.4.