extractedLnx/linux-2.4.37/drivers/media/video/planb.c_planb_ioctl.c
static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
{
struct planb *pb=(struct planb *)dev->priv;
switch (cmd)
{
case VIDIOCGCAP:
{
struct video_capability b;
DBG("PlanB: IOCTL VIDIOCGCAP\n");
strcpy (b.name, pb->video_dev.name);
b.type = VID_TYPE_OVERLAY | VID_TYPE_CLIPPING |
VID_TYPE_FRAMERAM | VID_TYPE_SCALES |
VID_TYPE_CAPTURE;
b.channels = 2; /* composite & svhs */
b.audios = 0;
b.maxwidth = PLANB_MAXPIXELS;
b.maxheight = PLANB_MAXLINES;
b.minwidth = 32; /* wild guess */
b.minheight = 32;
if (copy_to_user(arg,&b,sizeof(b)))
return -EFAULT;
return 0;
}
case VIDIOCSFBUF:
{
struct video_buffer v;
unsigned int fmt;
DBG("PlanB: IOCTL VIDIOCSFBUF\n");
if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
return -EPERM;
if (copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
planb_lock(pb);
switch(v.depth) {
/* xawtv only asks for 8 bit in static grey, but
* there is no way to know what it really means.. */
case 8:
fmt = VIDEO_PALETTE_GREY;
break;
case 15:
fmt = VIDEO_PALETTE_RGB555;
break;
case 32:
fmt = VIDEO_PALETTE_RGB32;
break;
/* We don't deliver these two... */
case 16:
case 24:
default:
planb_unlock(pb);
return -EINVAL;
}
if (palette2fmt[fmt].bpp * v.width > v.bytesperline) {
planb_unlock(pb);
return -EINVAL;
}
pb->win.bpp = palette2fmt[fmt].bpp;
pb->win.color_fmt = fmt;
pb->fb.phys = (unsigned long) v.base;
pb->win.sheight = v.height;
pb->win.swidth = v.width;
pb->picture.depth = pb->win.depth = v.depth;
pb->win.bpl = pb->win.bpp * pb->win.swidth;
pb->win.pad = v.bytesperline - pb->win.bpl;
DBG("PlanB: Display at %p is %d by %d, bytedepth %d,"
" bpl %d (+ %d)\n", v.base, v.width,v.height,
pb->win.bpp, pb->win.bpl, pb->win.pad);
pb->cmd_buff_inited = 0;
if(pb->overlay) {
suspend_overlay(pb);
fill_cmd_buff(pb);
resume_overlay(pb);
}
planb_unlock(pb);
return 0;
}
case VIDIOCGFBUF:
{
struct video_buffer v;
DBG("PlanB: IOCTL VIDIOCGFBUF\n");
v.base = (void *)pb->fb.phys;
v.height = pb->win.sheight;
v.width = pb->win.swidth;
v.depth = pb->win.depth;
v.bytesperline = pb->win.bpl + pb->win.pad;
if (copy_to_user(arg, &v, sizeof(v)))
return -EFAULT;
return 0;
}
case VIDIOCCAPTURE:
{
int i;
if(copy_from_user(&i, arg, sizeof(i)))
return -EFAULT;
if(i==0) {
DBG("PlanB: IOCTL VIDIOCCAPTURE Stop\n");
if (!(pb->overlay))
return 0;
planb_lock(pb);
pb->overlay = 0;
overlay_stop(pb);
planb_unlock(pb);
} else {
DBG("PlanB: IOCTL VIDIOCCAPTURE Start\n");
if (pb->fb.phys == 0 ||
pb->win.width == 0 ||
pb->win.height == 0)
return -EINVAL;
if (pb->overlay)
return 0;
planb_lock(pb);
pb->overlay = 1;
if(!(pb->cmd_buff_inited))
fill_cmd_buff(pb);
overlay_start(pb);
planb_unlock(pb);
}
return 0;
}
case VIDIOCGCHAN:
{
struct video_channel v;
DBG("PlanB: IOCTL VIDIOCGCHAN\n");
if(copy_from_user(&v, arg,sizeof(v)))
return -EFAULT;
v.flags = 0;
v.tuners = 0;
v.type = VIDEO_TYPE_CAMERA;
v.norm = pb->win.norm;
switch(v.channel)
{
case 0:
strcpy(v.name,"Composite");
break;
case 1:
strcpy(v.name,"SVHS");
break;
default:
return -EINVAL;
break;
}
if(copy_to_user(arg,&v,sizeof(v)))
return -EFAULT;
return 0;
}
case VIDIOCSCHAN:
{
struct video_channel v;
DBG("PlanB: IOCTL VIDIOCSCHAN\n");
if(copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
if (v.norm != pb->win.norm) {
int i, maxlines;
switch (v.norm)
{
case VIDEO_MODE_PAL:
case VIDEO_MODE_SECAM:
maxlines = PLANB_MAXLINES;
break;
case VIDEO_MODE_NTSC:
maxlines = PLANB_NTSC_MAXLINES;
break;
default:
DBG(" invalid norm %d.\n", v.norm);
return -EINVAL;
break;
}
planb_lock(pb);
/* empty the grabbing queue */
while(pb->grabbing)
interruptible_sleep_on(&pb->capq);
pb->maxlines = maxlines;
pb->win.norm = v.norm;
/* Stop overlay if running */
suspend_overlay(pb);
for(i = 0; i < MAX_GBUFFERS; i++)
pb->gbuf[i].norm_switch = 1;
/* I know it's an overkill, but.... */
fill_cmd_buff(pb);
/* ok, now init it accordingly */
saa_init_regs (pb);
/* restart overlay if it was running */
resume_overlay(pb);
planb_unlock(pb);
}
switch(v.channel)
{
case 0: /* Composite */
saa_set (SAA7196_IOCC,
((saa_regs[pb->win.norm][SAA7196_IOCC] &
~7) | 3), pb);
break;
case 1: /* SVHS */
saa_set (SAA7196_IOCC,
((saa_regs[pb->win.norm][SAA7196_IOCC] &
~7) | 4), pb);
break;
default:
DBG(" invalid channel %d.\n", v.channel);
return -EINVAL;
break;
}
return 0;
}
case VIDIOCGPICT:
{
struct video_picture vp = pb->picture;
DBG("PlanB: IOCTL VIDIOCGPICT\n");
vp.palette = pb->win.color_fmt;
if(copy_to_user(arg,&vp,sizeof(vp)))
return -EFAULT;
return 0;
}
case VIDIOCSPICT:
{
struct video_picture vp;
DBG("PlanB: IOCTL VIDIOCSPICT\n");
if(copy_from_user(&vp,arg,sizeof(vp)))
return -EFAULT;
pb->picture = vp;
/* Should we do sanity checks here? */
planb_lock(pb);
saa_set (SAA7196_BRIG, (unsigned char)
((pb->picture.brightness) >> 8), pb);
saa_set (SAA7196_HUEC, (unsigned char)
((pb->picture.hue) >> 8) ^ 0x80, pb);
saa_set (SAA7196_CSAT, (unsigned char)
((pb->picture.colour) >> 9), pb);
saa_set (SAA7196_CONT, (unsigned char)
((pb->picture.contrast) >> 9), pb);
planb_unlock(pb);
return 0;
}
case VIDIOCSWIN:
{
struct video_window vw;
struct video_clip clip;
int i;
DBG("PlanB: IOCTL VIDIOCSWIN\n");
if(copy_from_user(&vw,arg,sizeof(vw)))
return -EFAULT;
planb_lock(pb);
/* Stop overlay if running */
suspend_overlay(pb);
pb->win.interlace = (vw.height > pb->maxlines/2)? 1: 0;
if (pb->win.x != vw.x ||
pb->win.y != vw.y ||
pb->win.width != vw.width ||
pb->win.height != vw.height ||
!pb->cmd_buff_inited) {
pb->win.x = vw.x;
pb->win.y = vw.y;
pb->win.width = vw.width;
pb->win.height = vw.height;
fill_cmd_buff(pb);
}
DBG("PlanB: Window at (%d,%d) size %dx%d\n", vw.x, vw.y, vw.width,
vw.height);
/* Reset clip mask */
memset ((void *) pb->mask, 0xff, (pb->maxlines
* ((PLANB_MAXPIXELS + 7) & ~7)) / 8);
/* Add any clip rects */
for (i = 0; i < vw.clipcount; i++) {
if (copy_from_user(&clip, vw.clips + i,
sizeof(struct video_clip)))
return -EFAULT;
add_clip(pb, &clip);
}
/* restart overlay if it was running */
resume_overlay(pb);
planb_unlock(pb);
return 0;
}
case VIDIOCGWIN:
{
struct video_window vw;
DBG("PlanB: IOCTL VIDIOCGWIN\n");
vw.x=pb->win.x;
vw.y=pb->win.y;
vw.width=pb->win.width;
vw.height=pb->win.height;
vw.chromakey=0;
vw.flags=0;
if(pb->win.interlace)
vw.flags|=VIDEO_WINDOW_INTERLACE;
if(copy_to_user(arg,&vw,sizeof(vw)))
return -EFAULT;
return 0;
}
case VIDIOCSYNC: {
int i;
gbuf_ptr gbuf;
DBG("PlanB: IOCTL VIDIOCSYNC\n");
if(copy_from_user((void *)&i,arg,sizeof(int)))
return -EFAULT;
DBG("PlanB: sync to frame %d\n", i);
if(i > (MAX_GBUFFERS - 1) || i < 0)
return -EINVAL;
gbuf = &pb->gbuf[i];
chk_grab:
switch (*gbuf->status) {
case GBUFFER_UNUSED:
return -EINVAL;
case GBUFFER_GRABBING:
DBG("PlanB: waiting for grab"
" done (%d)\n", i);
interruptible_sleep_on(&pb->capq);
if(signal_pending(current))
return -EINTR;
goto chk_grab;
case GBUFFER_DONE:
*gbuf->status = GBUFFER_UNUSED;
break;
}
return 0;
}
case VIDIOCMCAPTURE:
{
struct video_mmap vm;
int fr;
DBG("PlanB: IOCTL VIDIOCMCAPTURE\n");
if(copy_from_user((void *) &vm,(void *)arg,sizeof(vm)))
return -EFAULT;
fr = vm.frame;
if(fr > (MAX_GBUFFERS - 1) || fr < 0)
return -EINVAL;
if (*pb->gbuf[fr].status != GBUFFER_UNUSED)
return -EBUSY;
return vgrab(pb, &vm);
}
case VIDIOCGMBUF:
{
int i;
struct video_mbuf vm;
DBG("PlanB: IOCTL VIDIOCGMBUF\n");
memset(&vm, 0 , sizeof(vm));
vm.size = PLANB_MAX_FBUF * MAX_GBUFFERS;
vm.frames = MAX_GBUFFERS;
for(i = 0; i<MAX_GBUFFERS; i++)
vm.offsets[i] = PLANB_MAX_FBUF * i;
if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
return -EFAULT;
return 0;
}
case VIDIOCGUNIT:
{
struct video_unit vu;
DBG("PlanB: IOCTL VIDIOCGUNIT\n");
vu.video=pb->video_dev.minor;
vu.vbi=pb->vbi_dev.minor;
vu.radio=VIDEO_NO_UNIT;
vu.audio=VIDEO_NO_UNIT;
vu.teletext=VIDEO_NO_UNIT;
if(copy_to_user((void *)arg, (void *)&vu, sizeof(vu)))
return -EFAULT;
return 0;
}
case PLANBIOCGSAAREGS:
{
struct planb_saa_regs preg;
DBG("PlanB: IOCTL PLANBIOCGSAAREGS\n");
if(copy_from_user(&preg, arg, sizeof(preg)))
return -EFAULT;
if(preg.addr >= SAA7196_NUMREGS)
return -EINVAL;
preg.val = saa_regs[pb->win.norm][preg.addr];
if(copy_to_user((void *)arg, (void *)&preg,
sizeof(preg)))
return -EFAULT;
return 0;
}
case PLANBIOCSSAAREGS:
{
struct planb_saa_regs preg;
DBG("PlanB: IOCTL PLANBIOCSSAAREGS\n");
if(copy_from_user(&preg, arg, sizeof(preg)))
return -EFAULT;
if(preg.addr >= SAA7196_NUMREGS)
return -EINVAL;
saa_set (preg.addr, preg.val, pb);
return 0;
}
case PLANBIOCGSTAT:
{
struct planb_stat_regs pstat;
DBG("PlanB: IOCTL PLANBIOCGSTAT\n");
pstat.ch1_stat = readl(&pb->planb_base->ch1.status);
pstat.ch2_stat = readl(&pb->planb_base->ch2.status);
pstat.ch1_cmdbase = (unsigned long)pb->vid_cbo.start;
pstat.ch2_cmdbase = (unsigned long)pb->clip_cbo.start;
pstat.ch1_cmdptr = readl(&pb->planb_base->ch1.cmdptr);
pstat.ch2_cmdptr = readl(&pb->planb_base->ch2.cmdptr);
pstat.saa_stat0 = saa_status(0, pb);
pstat.saa_stat1 = saa_status(1, pb);
if(copy_to_user((void *)arg, (void *)&pstat,
sizeof(pstat)))
return -EFAULT;
return 0;
}
case PLANBIOCSMODE: {
int v;
DBG("PlanB: IOCTL PLANBIOCSMODE\n");
if(copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
switch(v)
{
case PLANB_TV_MODE:
saa_set (SAA7196_STDC,
(saa_regs[pb->win.norm][SAA7196_STDC] &
0x7f), pb);
break;
case PLANB_VTR_MODE:
saa_set (SAA7196_STDC,
(saa_regs[pb->win.norm][SAA7196_STDC] |
0x80), pb);
break;
default:
return -EINVAL;
break;
}
pb->win.mode = v;
return 0;
}
case PLANBIOCGMODE: {
int v=pb->win.mode;
DBG("PlanB: IOCTL PLANBIOCGMODE\n");
if(copy_to_user(arg,&v,sizeof(v)))
return -EFAULT;
return 0;
}
#ifdef PLANB_GSCANLINE
case PLANBG_GRAB_BPL: {
int v=pb->gbytes_per_line;
DBG("PlanB: IOCTL PLANBG_GRAB_BPL\n");
if(copy_to_user(arg,&v,sizeof(v)))
return -EFAULT;
return 0;
}
#endif /* PLANB_GSCANLINE */
/* These serve only for debugging... */
#ifdef DEBUG
case PLANB_INTR_DEBUG: {
int i;
DBG("PlanB: IOCTL PLANB_INTR_DEBUG\n");
if(copy_from_user(&i, arg, sizeof(i)))
return -EFAULT;
/* avoid hang ups all together */
for (i = 0; i < MAX_GBUFFERS; i++) {
if(*pb->gbuf[i].status == GBUFFER_GRABBING) {
*pb->gbuf[i].status = GBUFFER_DONE;
}
}
if(pb->grabbing)
pb->grabbing--;
wake_up_interruptible(&pb->capq);
return 0;
}
case PLANB_INV_REGS: {
int i;
struct planb_any_regs any;
DBG("PlanB: IOCTL PLANB_INV_REGS\n");
if(copy_from_user(&any, arg, sizeof(any)))
return -EFAULT;
if(any.offset < 0 || any.offset + any.bytes > 0x400)
return -EINVAL;
if(any.bytes > 128)
return -EINVAL;
for (i = 0; i < any.bytes; i++) {
any.data[i] =
readb((unsigned char *)pb->planb_base
+ any.offset + i);
}
if(copy_to_user(arg,&any,sizeof(any)))
return -EFAULT;
return 0;
}
case PLANBIOCGDBDMABUF:
{
struct planb_buf_regs buf;
dbdma_cmd_ptr dc;
int i;
DBG("PlanB: IOCTL PLANBIOCGDBDMABUF\n");
if(copy_from_user(&buf, arg, sizeof(buf)))
return -EFAULT;
buf.end &= ~0xf;
if( (buf.start < 0) || (buf.end < 0x10) ||
(buf.end < buf.start+0x10) ||
(buf.end > 2*pb->tab_size) )
return -EINVAL;
printk ("PlanB DBDMA command buffer:\n");
for (i=(buf.start>>4); i<=(buf.end>>4); i++) {
printk(" 0x%04x:", i<<4);
dc = pb->vid_cbo.start + i;
printk (" %04x %04x %08x %08x %04x %04x\n",
dc->req_count, dc->command, dc->phy_addr,
dc->cmd_dep, dc->res_count, dc->xfer_status);
}
return 0;
}
#endif /* DEBUG */
default:
{
DBG("PlanB: Unimplemented IOCTL: %d (0x%x)\n", cmd, cmd);
return -ENOIOCTLCMD;
}
/* Some IOCTLs are currently unsupported on PlanB */
case VIDIOCGTUNER: {
DBG("PlanB: IOCTL VIDIOCGTUNER\n");
goto unimplemented; }
case VIDIOCSTUNER: {
DBG("PlanB: IOCTL VIDIOCSTUNER\n");
goto unimplemented; }
case VIDIOCSFREQ: {
DBG("PlanB: IOCTL VIDIOCSFREQ\n");
goto unimplemented; }
case VIDIOCGFREQ: {
DBG("PlanB: IOCTL VIDIOCGFREQ\n");
goto unimplemented; }
case VIDIOCKEY: {
DBG("PlanB: IOCTL VIDIOCKEY\n");
goto unimplemented; }
case VIDIOCSAUDIO: {
DBG("PlanB: IOCTL VIDIOCSAUDIO\n");
goto unimplemented; }
case VIDIOCGAUDIO: {
DBG("PlanB: IOCTL VIDIOCGAUDIO\n");
goto unimplemented; }
unimplemented:
DBG(" Unimplemented\n");
return -ENOIOCTLCMD;
}
return 0;
}
Generated by GNU enscript 1.6.4.