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.