Enscript Output

extractedLnx/linux/drivers/media/video/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;
			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);

			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm);
			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.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 valid parameters */
			if (vw.width < BUZ_MIN_WIDTH || vw.height < BUZ_MIN_HEIGHT ||
			    vw.width > BUZ_MAX_WIDTH || vw.height > BUZ_MAX_HEIGHT) {
				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;

			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;
			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm);
			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.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 > KMALLOC_MAXSIZE)
				br.size = KMALLOC_MAXSIZE;

			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;
			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
			i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.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.