extractedLnx/linux/drivers/char/zr36120.c_zoran_ioctl.c
static
int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
{
struct zoran* ztv = (struct zoran*)dev;
switch (cmd) {
case VIDIOCGCAP:
{
struct video_capability c;
DEBUG(printk(CARD_DEBUG "VIDIOCGCAP\n",CARD));
strcpy(c.name,ztv->video_dev.name);
c.type = VID_TYPE_CAPTURE|
VID_TYPE_OVERLAY|
VID_TYPE_CLIPPING|
VID_TYPE_FRAMERAM|
VID_TYPE_SCALES;
if (ztv->have_tuner)
c.type |= VID_TYPE_TUNER;
if (ztv->have_decoder) {
c.channels = ztv->card->video_inputs;
c.audios = ztv->card->audio_inputs;
} else
/* no decoder -> no channels */
c.channels = c.audios = 0;
c.maxwidth = 768;
c.maxheight = 576;
c.minwidth = 32;
c.minheight = 32;
if (copy_to_user(arg,&c,sizeof(c)))
return -EFAULT;
break;
}
case VIDIOCGCHAN:
{
struct video_channel v;
int mux;
if (copy_from_user(&v, arg,sizeof(v)))
return -EFAULT;
DEBUG(printk(CARD_DEBUG "VIDIOCGCHAN(%d)\n",CARD,v.channel));
v.flags=VIDEO_VC_AUDIO
#ifdef VIDEO_VC_NORM
|VIDEO_VC_NORM
#endif
;
v.tuners=0;
v.type=VIDEO_TYPE_CAMERA;
#ifdef I_EXPECT_POSSIBLE_NORMS_IN_THE_API
v.norm=VIDEO_MODE_PAL|
VIDEO_MODE_NTSC|
VIDEO_MODE_SECAM;
#else
v.norm=VIDEO_MODE_PAL;
#endif
/* too many inputs? no decoder -> no channels */
if (!ztv->have_decoder || v.channel >= ztv->card->video_inputs)
return -EINVAL;
/* now determine the name of the channel */
mux = ztv->card->video_mux[v.channel];
if (mux & IS_TUNER) {
/* lets assume only one tuner, yes? */
strcpy(v.name,"Television");
v.type = VIDEO_TYPE_TV;
if (ztv->have_tuner) {
v.flags |= VIDEO_VC_TUNER;
v.tuners = 1;
}
}
else if (mux & IS_SVHS)
sprintf(v.name,"S-Video-%d",v.channel);
else
sprintf(v.name,"CVBS-%d",v.channel);
if (copy_to_user(arg,&v,sizeof(v)))
return -EFAULT;
break;
}
case VIDIOCSCHAN:
{ /* set video channel */
struct video_channel v;
if (copy_from_user(&v, arg,sizeof(v)))
return -EFAULT;
DEBUG(printk(CARD_DEBUG "VIDIOCSCHAN(%d,%d)\n",CARD,v.channel,v.norm));
/* too many inputs? no decoder -> no channels */
if (!ztv->have_decoder || v.channel >= ztv->card->video_inputs)
return -EINVAL;
if (v.norm != VIDEO_MODE_PAL &&
v.norm != VIDEO_MODE_NTSC &&
v.norm != VIDEO_MODE_SECAM &&
v.norm != VIDEO_MODE_AUTO)
return -EOPNOTSUPP;
/* make it happen, nr1! */
return zoran_muxsel(ztv,v.channel,v.norm);
}
case VIDIOCGTUNER:
{
struct video_tuner v;
if (copy_from_user(&v, arg,sizeof(v)))
return -EFAULT;
DEBUG(printk(CARD_DEBUG "VIDIOCGTUNER(%d)\n",CARD,v.tuner));
/* Only no or one tuner for now */
if (!ztv->have_tuner || v.tuner)
return -EINVAL;
strcpy(v.name,"Television");
v.rangelow = 0;
v.rangehigh = ~0;
v.flags = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
v.mode = ztv->norm;
v.signal = 0xFFFF; /* unknown */
if (copy_to_user(arg,&v,sizeof(v)))
return -EFAULT;
break;
}
case VIDIOCSTUNER:
{
struct video_tuner v;
if (copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
DEBUG(printk(CARD_DEBUG "VIDIOCSTUNER(%d,%d)\n",CARD,v.tuner,v.mode));
/* Only no or one tuner for now */
if (!ztv->have_tuner || v.tuner)
return -EINVAL;
/* and it only has certain valid modes */
if( v.mode != VIDEO_MODE_PAL &&
v.mode != VIDEO_MODE_NTSC &&
v.mode != VIDEO_MODE_SECAM)
return -EOPNOTSUPP;
/* engage! */
return zoran_muxsel(ztv,v.tuner,v.mode);
}
case VIDIOCGPICT:
{
struct video_picture p = ztv->picture;
DEBUG(printk(CARD_DEBUG "VIDIOCGPICT\n",CARD));
p.depth = ztv->depth;
switch (p.depth) {
case 8: p.palette=VIDEO_PALETTE_YUV422;
break;
case 15: p.palette=VIDEO_PALETTE_RGB555;
break;
case 16: p.palette=VIDEO_PALETTE_RGB565;
break;
case 24: p.palette=VIDEO_PALETTE_RGB24;
break;
case 32: p.palette=VIDEO_PALETTE_RGB32;
break;
}
if (copy_to_user(arg, &p, sizeof(p)))
return -EFAULT;
break;
}
case VIDIOCSPICT:
{
struct video_picture p;
if (copy_from_user(&p, arg,sizeof(p)))
return -EFAULT;
DEBUG(printk(CARD_DEBUG "VIDIOCSPICT(%d,%d,%d,%d,%d,%d,%d)\n",CARD,p.brightness,p.hue,p.colour,p.contrast,p.whiteness,p.depth,p.palette));
/* depth must match with framebuffer */
if (p.depth != ztv->depth)
return -EINVAL;
/* check if palette matches this bpp */
if (p.palette>NRPALETTES ||
palette2fmt[p.palette].bpp != ztv->overinfo.bpp)
return -EINVAL;
write_lock_irq(&ztv->lock);
ztv->overinfo.format = p.palette;
ztv->picture = p;
write_unlock_irq(&ztv->lock);
/* tell the decoder */
i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &p);
break;
}
case VIDIOCGWIN:
{
struct video_window vw;
DEBUG(printk(CARD_DEBUG "VIDIOCGWIN\n",CARD));
read_lock(&ztv->lock);
vw.x = ztv->overinfo.x;
vw.y = ztv->overinfo.y;
vw.width = ztv->overinfo.w;
vw.height = ztv->overinfo.h;
vw.chromakey= 0;
vw.flags = 0;
if (ztv->vidInterlace)
vw.flags|=VIDEO_WINDOW_INTERLACE;
read_unlock(&ztv->lock);
if (copy_to_user(arg,&vw,sizeof(vw)))
return -EFAULT;
break;
}
case VIDIOCSWIN:
{
struct video_window vw;
struct video_clip *vcp;
int on;
if (copy_from_user(&vw,arg,sizeof(vw)))
return -EFAULT;
DEBUG(printk(CARD_DEBUG "VIDIOCSWIN(%d,%d,%d,%d,%x,%d)\n",CARD,vw.x,vw.y,vw.width,vw.height,vw.flags,vw.clipcount));
if (vw.flags)
return -EINVAL;
if (vw.clipcount>256)
return -EDOM; /* Too many! */
/*
* Do any clips.
*/
vcp = vmalloc(sizeof(struct video_clip)*(vw.clipcount+4));
if (vcp==NULL)
return -ENOMEM;
if (vw.clipcount && copy_from_user(vcp,vw.clips,sizeof(struct video_clip)*vw.clipcount))
return -EFAULT;
on = ztv->running;
if (on)
zoran_cap(ztv, 0);
/*
* strange, it seems xawtv sometimes calls us with 0
* width and/or height. Ignore these values
*/
if (vw.x == 0)
vw.x = ztv->overinfo.x;
if (vw.y == 0)
vw.y = ztv->overinfo.y;
/* by now we are committed to the new data... */
write_lock_irq(&ztv->lock);
ztv->overinfo.x = vw.x;
ztv->overinfo.y = vw.y;
ztv->overinfo.w = vw.width;
ztv->overinfo.h = vw.height;
write_unlock_irq(&ztv->lock);
/*
* Impose display clips
*/
if (vw.x+vw.width > ztv->swidth)
new_clip(&vw, vcp, ztv->swidth-vw.x, 0, vw.width-1, vw.height-1);
if (vw.y+vw.height > ztv->sheight)
new_clip(&vw, vcp, 0, ztv->sheight-vw.y, vw.width-1, vw.height-1);
/* built the requested clipping zones */
zoran_set_geo(ztv, &ztv->overinfo);
zoran_built_overlay(ztv, vw.clipcount, vcp);
vfree(vcp);
/* if we were on, restart the video engine */
if (on)
zoran_cap(ztv, 1);
break;
}
case VIDIOCCAPTURE:
{
int v;
get_user_ret(v,(int*)arg, -EFAULT);
DEBUG(printk(CARD_DEBUG "VIDIOCCAPTURE(%d)\n",CARD,v));
if (v==0) {
clear_bit(STATE_OVERLAY, &ztv->state);
zoran_cap(ztv, 1);
}
else {
/* is VIDIOCSFBUF, VIDIOCSWIN done? */
if (ztv->overinfo.busadr==0 || ztv->overinfo.w==0 || ztv->overinfo.h==0)
return -EINVAL;
set_bit(STATE_OVERLAY, &ztv->state);
zoran_cap(ztv, 1);
}
break;
}
case VIDIOCGFBUF:
{
struct video_buffer v;
DEBUG(printk(CARD_DEBUG "VIDIOCGFBUF\n",CARD));
read_lock(&ztv->lock);
v.base = (void *)ztv->overinfo.busadr;
v.height = ztv->sheight;
v.width = ztv->swidth;
v.depth = ztv->depth;
v.bytesperline = ztv->overinfo.bpl;
read_unlock(&ztv->lock);
if(copy_to_user(arg, &v,sizeof(v)))
return -EFAULT;
break;
}
case VIDIOCSFBUF:
{
struct video_buffer v;
#if LINUX_VERSION_CODE >= 0x020100
if(!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_ADMIN))
#else
if(!suser())
#endif
return -EPERM;
if (copy_from_user(&v, arg,sizeof(v)))
return -EFAULT;
DEBUG(printk(CARD_DEBUG "VIDIOCSFBUF(%p,%d,%d,%d,%d)\n",CARD,v.base, v.width,v.height,v.depth,v.bytesperline));
if (v.depth!=15 && v.depth!=16 && v.depth!=24 && v.depth!=32)
return -EINVAL;
if (v.bytesperline<1)
return -EINVAL;
if (ztv->running)
return -EBUSY;
write_lock_irq(&ztv->lock);
ztv->overinfo.busadr = (ulong)v.base;
ztv->sheight = v.height;
ztv->swidth = v.width;
ztv->depth = v.depth; /* bits per pixel */
ztv->overinfo.bpp = ((v.depth+1)&0x38)/8;/* bytes per pixel */
ztv->overinfo.bpl = v.bytesperline; /* bytes per line */
write_unlock_irq(&ztv->lock);
break;
}
case VIDIOCKEY:
{
/* Will be handled higher up .. */
break;
}
case VIDIOCSYNC:
{
int i;
get_user_ret(i,(int*)arg, -EFAULT);
DEBUG(printk(CARD_DEBUG "VIDEOCSYNC(%d)\n",CARD,i));
if (i<0 || i>ZORAN_MAX_FBUFFERS)
return -EINVAL;
switch (ztv->grabinfo[i].status) {
case FBUFFER_FREE:
return -EINVAL;
case FBUFFER_BUSY:
/* wait till this buffer gets grabbed */
while (ztv->grabinfo[i].status == FBUFFER_BUSY) {
interruptible_sleep_on(&ztv->grabq);
/* see if a signal did it */
if (signal_pending(current))
return -EINTR;
}
/* don't fall through; a DONE buffer is not UNUSED */
break;
case FBUFFER_DONE:
ztv->grabinfo[i].status = FBUFFER_FREE;
/* tell ppl we have a spare buffer */
wake_up_interruptible(&ztv->grabq);
break;
}
DEBUG(printk(CARD_DEBUG "VIDEOCSYNC(%d) returns\n",CARD,i));
break;
}
case VIDIOCMCAPTURE:
{
struct video_mmap vm;
struct vidinfo* frame;
if (copy_from_user(&vm,arg,sizeof(vm)))
return -EFAULT;
DEBUG(printk(CARD_DEBUG "VIDIOCMCAPTURE(%d,(%d,%d),%d)\n",CARD,vm.frame,vm.width,vm.height,vm.format));
if (vm.frame<0 || vm.frame>ZORAN_MAX_FBUFFERS ||
vm.width<32 || vm.width>768 ||
vm.height<32 || vm.height>576 ||
vm.format>NRPALETTES ||
palette2fmt[vm.format].mode == 0)
return -EINVAL;
/* we are allowed to take over UNUSED and DONE buffers */
frame = &ztv->grabinfo[vm.frame];
if (frame->status == FBUFFER_BUSY)
return -EBUSY;
/* setup the other parameters if they are given */
write_lock_irq(&ztv->lock);
frame->w = vm.width;
frame->h = vm.height;
frame->format = vm.format;
frame->bpp = palette2fmt[frame->format].bpp;
frame->bpl = frame->w*frame->bpp;
frame->status = FBUFFER_BUSY;
frame->next = 0;
{ /* add to tail of queue */
struct vidinfo* oldframe = ztv->workqueue;
if (!oldframe) ztv->workqueue = frame;
else {
while (oldframe->next) oldframe = oldframe->next;
oldframe->next = frame;
}
}
write_unlock_irq(&ztv->lock);
zoran_cap(ztv, 1);
break;
}
case VIDIOCGMBUF:
{
struct video_mbuf mb;
int i;
DEBUG(printk(CARD_DEBUG "VIDIOCGMBUF\n",CARD));
mb.size = ZORAN_MAX_FBUFSIZE;
mb.frames = ZORAN_MAX_FBUFFERS;
for (i=0; i<ZORAN_MAX_FBUFFERS; i++)
mb.offsets[i] = i*ZORAN_MAX_FBUFFER;
if(copy_to_user(arg, &mb,sizeof(mb)))
return -EFAULT;
break;
}
case VIDIOCGUNIT:
{
struct video_unit vu;
DEBUG(printk(CARD_DEBUG "VIDIOCGUNIT\n",CARD));
vu.video = ztv->video_dev.minor;
vu.vbi = ztv->vbi_dev.minor;
vu.radio = VIDEO_NO_UNIT;
vu.audio = VIDEO_NO_UNIT;
vu.teletext = VIDEO_NO_UNIT;
if(copy_to_user(arg, &vu,sizeof(vu)))
return -EFAULT;
break;
}
case VIDIOCGFREQ:
{
unsigned long v = ztv->tuner_freq;
if (copy_to_user(arg,&v,sizeof(v)))
return -EFAULT;
DEBUG(printk(CARD_DEBUG "VIDIOCGFREQ\n",CARD));
break;
}
case VIDIOCSFREQ:
{
unsigned long v;
if (copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
DEBUG(printk(CARD_DEBUG "VIDIOCSFREQ\n",CARD));
if (ztv->have_tuner) {
int fixme = v;
if (i2c_control_device(&(ztv->i2c), I2C_DRIVERID_TUNER, TUNER_SET_TVFREQ, &fixme) < 0)
return -EAGAIN;
}
ztv->tuner_freq = v;
break;
}
/* Why isn't this in the API?
* And why doesn't it take a buffer number?
case BTTV_FIELDNR:
{
unsigned long v = ztv->lastfieldnr;
if (copy_to_user(arg,&v,sizeof(v)))
return -EFAULT;
DEBUG(printk(CARD_DEBUG "BTTV_FIELDNR\n",CARD));
break;
}
*/
default:
return -ENOIOCTLCMD;
}
return 0;
}
Generated by GNU enscript 1.6.4.