extractedLnx/linux-2.2.26/drivers/char/buz.c_zoran_ioctl.c
static int zoran_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
{
struct zoran *zr = (struct zoran *) dev;
switch (cmd) {
case VIDIOCGCAP:
{
struct video_capability b;
IOCTL_DEBUG(printk("buz ioctl VIDIOCGCAP\n"));
strncpy(b.name, zr->video_dev.name, sizeof(b.name));
b.type = VID_TYPE_CAPTURE |
VID_TYPE_OVERLAY |
VID_TYPE_CLIPPING |
VID_TYPE_FRAMERAM |
VID_TYPE_SCALES;
/* theoretically we could also flag VID_TYPE_SUBCAPTURE
but this is not even implemented in the BTTV driver */
b.channels = 2; /* composite, svhs */
b.audios = 0;
b.maxwidth = BUZ_MAX_WIDTH;
b.maxheight = BUZ_MAX_HEIGHT;
b.minwidth = BUZ_MIN_WIDTH;
b.minheight = BUZ_MIN_HEIGHT;
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;
}
IOCTL_DEBUG(printk("buz ioctl VIDIOCGCHAN for channel %d\n", v.channel));
switch (v.channel) {
case 0:
strcpy(v.name, "Composite");
break;
case 1:
strcpy(v.name, "SVHS");
break;
default:
return -EINVAL;
}
v.tuners = 0;
v.flags = 0;
v.type = VIDEO_TYPE_CAMERA;
v.norm = zr->params.norm;
if (copy_to_user(arg, &v, sizeof(v))) {
return -EFAULT;
}
return 0;
}
/* RJ: the documentation at http://roadrunner.swansea.linux.org.uk/v4lapi.shtml says:
* "The VIDIOCSCHAN ioctl takes an integer argument and switches the capture to this input."
* ^^^^^^^
* The famos BTTV driver has it implemented with a struct video_channel argument
* and we follow it for compatibility reasons
*
* BTW: this is the only way the user can set the norm!
*/
case VIDIOCSCHAN:
{
struct video_channel v;
int input, norm;
int on, res;
if (copy_from_user(&v, arg, sizeof(v))) {
return -EFAULT;
}
IOCTL_DEBUG(printk("buz ioctl VIDIOCSCHAN: channel=%d, norm=%d\n", v.channel, v.norm));
switch (v.channel) {
case 0:
input = 3;
break;
case 1:
input = 7;
break;
default:
return -EINVAL;
}
if (v.norm != VIDEO_MODE_PAL
&& v.norm != VIDEO_MODE_NTSC) {
return -EINVAL;
}
zr->params.norm = v.norm;
zr->params.input = v.channel;
/* We switch overlay off and on since a change in the norm
needs different VFE settings */
on = zr->v4l_overlay_active && !zr->v4l_memgrab_active;
if (on)
zr36057_overlay(zr, 0);
norm = zr->params.norm;
i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm);
i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &norm);
if (on)
zr36057_overlay(zr, 1);
/* Make sure the changes come into effect */
res = wait_grab_pending(zr);
if (res)
return res;
return 0;
}
case VIDIOCGTUNER:
case VIDIOCSTUNER:
return -EINVAL;
case VIDIOCGPICT:
{
struct video_picture p = zr->picture;
IOCTL_DEBUG(printk("buz ioctl VIDIOCGPICT\n"));
p.depth = zr->buffer.depth;
switch (zr->buffer.depth) {
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;
}
return 0;
}
case VIDIOCSPICT:
{
struct video_picture p;
if (copy_from_user(&p, arg, sizeof(p))) {
return -EFAULT;
}
i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &p);
IOCTL_DEBUG(printk("buz ioctl VIDIOCSPICT bri=%d hue=%d col=%d con=%d dep=%d pal=%d\n",
p.brightness, p.hue, p.colour, p.contrast, p.depth, p.palette));
/* The depth and palette values have no meaning to us,
should we return -EINVAL if they don't fit ? */
zr->picture = p;
return 0;
}
case VIDIOCCAPTURE:
{
int v, res;
if (copy_from_user(&v, arg, sizeof(v))) {
return -EFAULT;
}
IOCTL_DEBUG(printk("buz ioctl VIDIOCCAPTURE: %d\n", v));
/* If there is nothing to do, return immediatly */
if ((v && zr->v4l_overlay_active) || (!v && !zr->v4l_overlay_active))
return 0;
if (v == 0) {
zr->v4l_overlay_active = 0;
if (!zr->v4l_memgrab_active)
zr36057_overlay(zr, 0);
/* When a grab is running, the video simply won't be switched on any more */
} else {
if (!zr->buffer_set || !zr->window_set) {
return -EINVAL;
}
zr->v4l_overlay_active = 1;
if (!zr->v4l_memgrab_active)
zr36057_overlay(zr, 1);
/* When a grab is running, the video will be switched on when grab is finished */
}
/* Make sure the changes come into effect */
res = wait_grab_pending(zr);
if (res)
return res;
return 0;
}
case VIDIOCGWIN:
{
IOCTL_DEBUG(printk("buz ioctl VIDIOCGWIN\n"));
if (copy_to_user(arg, &zr->window, sizeof(zr->window))) {
return -EFAULT;
}
return 0;
}
case VIDIOCSWIN:
{
struct video_clip *vcp;
struct video_window vw;
int on, end, res;
if (copy_from_user(&vw, arg, sizeof(vw))) {
return -EFAULT;
}
IOCTL_DEBUG(printk("buz ioctl VIDIOCSWIN: x=%d y=%d w=%d h=%d clipcount=%d\n", vw.x, vw.y, vw.width, vw.height, vw.clipcount));
if (!zr->buffer_set) {
return -EINVAL;
}
/*
* The video front end needs 4-byte alinged line sizes, we correct that
* silently here if necessary
*/
if (zr->buffer.depth == 15 || zr->buffer.depth == 16) {
end = (vw.x + vw.width) & ~1; /* round down */
vw.x = (vw.x + 1) & ~1; /* round up */
vw.width = end - vw.x;
}
if (zr->buffer.depth == 24) {
end = (vw.x + vw.width) & ~3; /* round down */
vw.x = (vw.x + 3) & ~3; /* round up */
vw.width = end - vw.x;
}
#if 0
// At least xawtv seems to care about the following - just leave it away
/*
* Also corrected silently (as long as window fits at all):
* video not fitting the screen
*/
#if 0
if (vw.x < 0 || vw.y < 0 || vw.x + vw.width > zr->buffer.width ||
vw.y + vw.height > zr->buffer.height) {
printk(BUZ_ERR ": VIDIOCSWIN: window does not fit frame buffer: %dx%d+%d*%d\n",
vw.width, vw.height, vw.x, vw.y);
return -EINVAL;
}
#else
if (vw.x < 0)
vw.x = 0;
if (vw.y < 0)
vw.y = 0;
if (vw.x + vw.width > zr->buffer.width)
vw.width = zr->buffer.width - vw.x;
if (vw.y + vw.height > zr->buffer.height)
vw.height = zr->buffer.height - vw.y;
#endif
#endif
/* Check for vaild parameters */
if (vw.width < BUZ_MIN_WIDTH || vw.height < BUZ_MIN_HEIGHT ||
vw.width > BUZ_MAX_WIDTH || vw.height > BUZ_MAX_HEIGHT ||
vw.clipcount < 0 || vw.clipcount > 2048) {
return -EINVAL;
}
#ifdef XAWTV_HACK
if (vw.width > 720)
vw.width = 720;
#endif
zr->window.x = vw.x;
zr->window.y = vw.y;
zr->window.width = vw.width;
zr->window.height = vw.height;
zr->window.chromakey = 0;
zr->window.flags = 0; // RJ: Is this intended for interlace on/off ?
zr->window.clips = NULL;
zr->window.clipcount = vw.clipcount;
/*
* If an overlay is running, we have to switch it off
* and switch it on again in order to get the new settings in effect.
*
* We also want to avoid that the overlay mask is written
* when an overlay is running.
*/
on = zr->v4l_overlay_active && !zr->v4l_memgrab_active;
if (on)
zr36057_overlay(zr, 0);
/*
* Write the overlay mask if clips are wanted.
*/
if (vw.clipcount) {
vcp = vmalloc(sizeof(struct video_clip) * (vw.clipcount + 4));
if (vcp == NULL) {
return -ENOMEM;
}
if (copy_from_user(vcp, vw.clips, sizeof(struct video_clip) * vw.clipcount)) {
vfree(vcp);
return -EFAULT;
}
write_overlay_mask(zr, vcp, vw.clipcount);
vfree(vcp);
}
if (on)
zr36057_overlay(zr, 1);
zr->window_set = 1;
/* Make sure the changes come into effect */
res = wait_grab_pending(zr);
if (res)
return res;
return 0;
}
case VIDIOCGFBUF:
{
IOCTL_DEBUG(printk("buz ioctl VIDIOCGFBUF\n"));
if (copy_to_user(arg, &zr->buffer, sizeof(zr->buffer))) {
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;
IOCTL_DEBUG(printk("buz ioctl VIDIOCSFBUF: base=0x%x w=%d h=%d depth=%d bpl=%d\n", (u32) v.base, v.width, v.height, v.depth, v.bytesperline));
if (zr->v4l_overlay_active) {
/* Has the user gotten crazy ... ? */
return -EINVAL;
}
if (v.depth != 15
&& v.depth != 16
&& v.depth != 24
&& v.depth != 32) {
return -EINVAL;
}
if (v.height <= 0 || v.width <= 0 || v.bytesperline <= 0) {
return -EINVAL;
}
if (v.bytesperline & 3) {
return -EINVAL;
}
if (v.base) {
zr->buffer.base = (void *) ((unsigned long) v.base & ~3);
}
zr->buffer.height = v.height;
zr->buffer.width = v.width;
zr->buffer.depth = v.depth;
zr->buffer.bytesperline = v.bytesperline;
if (zr->buffer.base)
zr->buffer_set = 1;
zr->window_set = 0; /* The user should set new window parameters */
return 0;
}
/* RJ: what is VIDIOCKEY intended to do ??? */
case VIDIOCGFREQ:
case VIDIOCSFREQ:
case VIDIOCGAUDIO:
case VIDIOCSAUDIO:
return -EINVAL;
case VIDIOCSYNC:
{
int v;
if (copy_from_user(&v, arg, sizeof(v))) {
return -EFAULT;
}
IOCTL_DEBUG(printk("buz ioctl VIDIOCSYNC %d\n", v));
return v4l_sync(zr, v);
}
case VIDIOCMCAPTURE:
{
struct video_mmap vm;
if (copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) {
return -EFAULT;
}
IOCTL_DEBUG(printk("buz ioctl VIDIOCMCAPTURE frame=%d geom=%dx%d fmt=%d\n",
vm.frame, vm.height, vm.width, vm.format));
return v4l_grab(zr, &vm);
}
case VIDIOCGMBUF:
{
struct video_mbuf vm;
int i;
IOCTL_DEBUG(printk("buz ioctl VIDIOCGMBUF\n"));
vm.size = v4l_nbufs * v4l_bufsize;
vm.frames = v4l_nbufs;
for (i = 0; i < v4l_nbufs; i++) {
vm.offsets[i] = i * v4l_bufsize;
}
/* The next mmap will map the V4L buffers */
zr->map_mjpeg_buffers = 0;
if (copy_to_user(arg, &vm, sizeof(vm))) {
return -EFAULT;
}
return 0;
}
case VIDIOCGUNIT:
{
struct video_unit vu;
IOCTL_DEBUG(printk("buz ioctl VIDIOCGUNIT\n"));
vu.video = zr->video_dev.minor;
vu.vbi = VIDEO_NO_UNIT;
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;
return 0;
}
/*
* RJ: In principal we could support subcaptures for V4L grabbing.
* Not even the famous BTTV driver has them, however.
* If there should be a strong demand, one could consider
* to implement them.
*/
case VIDIOCGCAPTURE:
case VIDIOCSCAPTURE:
return -EINVAL;
case BUZIOC_G_PARAMS:
{
IOCTL_DEBUG(printk("buz ioctl BUZIOC_G_PARAMS\n"));
if (copy_to_user(arg, &(zr->params), sizeof(zr->params)))
return -EFAULT;
return 0;
}
case BUZIOC_S_PARAMS:
{
struct zoran_params bp;
int input, on, norm;
if (zr->codec_mode != BUZ_MODE_IDLE) {
return -EINVAL;
}
if (copy_from_user(&bp, arg, sizeof(bp))) {
return -EFAULT;
}
IOCTL_DEBUG(printk("buz ioctl BUZIOC_S_PARAMS\n"));
/* Check the params first before overwriting our internal values */
if (zoran_check_params(zr, &bp))
return -EINVAL;
zr->params = bp;
/* Make changes of input and norm go into effect immediatly */
/* We switch overlay off and on since a change in the norm
needs different VFE settings */
on = zr->v4l_overlay_active && !zr->v4l_memgrab_active;
if (on)
zr36057_overlay(zr, 0);
input = zr->params.input == 0 ? 3 : 7;
norm = zr->params.norm;
i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm);
i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &norm);
if (on)
zr36057_overlay(zr, 1);
if (copy_to_user(arg, &bp, sizeof(bp))) {
return -EFAULT;
}
return 0;
}
case BUZIOC_REQBUFS:
{
struct zoran_requestbuffers br;
if (zr->jpg_buffers_allocated) {
return -EINVAL;
}
if (copy_from_user(&br, arg, sizeof(br))) {
return -EFAULT;
}
IOCTL_DEBUG(printk("buz ioctl BUZIOC_REQBUFS count = %lu size=%lu\n",
br.count, br.size));
/* Enforce reasonable lower and upper limits */
if (br.count < 4)
br.count = 4; /* Could be choosen smaller */
if (br.count > BUZ_MAX_FRAME)
br.count = BUZ_MAX_FRAME;
br.size = PAGE_ALIGN(br.size);
if (br.size < 8192)
br.size = 8192; /* Arbitrary */
/* br.size is limited by 1 page for the stat_com tables to a Maximum of 2 MB */
if (br.size > (512 * 1024))
br.size = (512 * 1024); /* 512 K should be enough */
if (zr->need_contiguous && br.size > MAX_KMALLOC_MEM)
br.size = MAX_KMALLOC_MEM;
zr->jpg_nbufs = br.count;
zr->jpg_bufsize = br.size;
if (jpg_fbuffer_alloc(zr))
return -ENOMEM;
/* The next mmap will map the MJPEG buffers */
zr->map_mjpeg_buffers = 1;
if (copy_to_user(arg, &br, sizeof(br))) {
return -EFAULT;
}
return 0;
}
case BUZIOC_QBUF_CAPT:
{
int nb;
if (copy_from_user((void *) &nb, (void *) arg, sizeof(int))) {
return -EFAULT;
}
IOCTL_DEBUG(printk("buz ioctl BUZIOC_QBUF_CAPT %d\n", nb));
return jpg_qbuf(zr, nb, BUZ_MODE_MOTION_COMPRESS);
}
case BUZIOC_QBUF_PLAY:
{
int nb;
if (copy_from_user((void *) &nb, (void *) arg, sizeof(int))) {
return -EFAULT;
}
IOCTL_DEBUG(printk("buz ioctl BUZIOC_QBUF_PLAY %d\n", nb));
return jpg_qbuf(zr, nb, BUZ_MODE_MOTION_DECOMPRESS);
}
case BUZIOC_SYNC:
{
struct zoran_sync bs;
int res;
IOCTL_DEBUG(printk("buz ioctl BUZIOC_SYNC\n"));
res = jpg_sync(zr, &bs);
if (copy_to_user(arg, &bs, sizeof(bs))) {
return -EFAULT;
}
return res;
}
case BUZIOC_G_STATUS:
{
struct zoran_status bs;
int norm, input, status;
if (zr->codec_mode != BUZ_MODE_IDLE) {
return -EINVAL;
}
if (copy_from_user(&bs, arg, sizeof(bs))) {
return -EFAULT;
}
IOCTL_DEBUG(printk("buz ioctl BUZIOC_G_STATUS\n"));
switch (bs.input) {
case 0:
input = 3;
break;
case 1:
input = 7;
break;
default:
return -EINVAL;
}
/* Set video norm to VIDEO_MODE_AUTO */
norm = VIDEO_MODE_AUTO;
i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm);
/* sleep 1 second */
schedule_timeout(HZ);
/* Get status of video decoder */
i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_GET_STATUS, &status);
bs.signal = (status & DECODER_STATUS_GOOD) ? 1 : 0;
bs.norm = (status & DECODER_STATUS_NTSC) ? VIDEO_MODE_NTSC : VIDEO_MODE_PAL;
bs.color = (status & DECODER_STATUS_COLOR) ? 1 : 0;
/* restore previous input and norm */
input = zr->params.input == 0 ? 3 : 7;
norm = zr->params.norm;
i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm);
if (copy_to_user(arg, &bs, sizeof(bs))) {
return -EFAULT;
}
return 0;
}
default:
return -ENOIOCTLCMD;
}
return 0;
}
Generated by GNU enscript 1.6.4.