Enscript Output

extractedLnx/linux-2.6.26/drivers/media/video/zoran_driver.c_zoran_do_ioctl.c

static int
zoran_do_ioctl (struct inode *inode,
		struct file  *file,
		unsigned int  cmd,
		void         *arg)
{
	struct zoran_fh *fh = file->private_data;
	struct zoran *zr = fh->zr;
	/* CAREFUL: used in multiple places here */
	struct zoran_jpg_settings settings;

	/* we might have older buffers lying around... We don't want
	 * to wait, but we do want to try cleaning them up ASAP. So
	 * we try to obtain the lock and free them. If that fails, we
	 * don't do anything and wait for the next turn. In the end,
	 * zoran_close() or a new allocation will still free them...
	 * This is just a 'the sooner the better' extra 'feature'
	 *
	 * We don't free the buffers right on munmap() because that
	 * causes oopses (kfree() inside munmap() oopses for no
	 * apparent reason - it's also not reproduceable in any way,
	 * but moving the free code outside the munmap() handler fixes
	 * all this... If someone knows why, please explain me (Ronald)
	 */
	if (mutex_trylock(&zr->resource_lock)) {
		/* we obtained it! Let's try to free some things */
		if (fh->jpg_buffers.ready_to_be_freed)
			jpg_fbuffer_free(file);
		if (fh->v4l_buffers.ready_to_be_freed)
			v4l_fbuffer_free(file);

		mutex_unlock(&zr->resource_lock);
	}

	switch (cmd) {

	case VIDIOCGCAP:
	{
		struct video_capability *vcap = arg;

		dprintk(3, KERN_DEBUG "%s: VIDIOCGCAP\n", ZR_DEVNAME(zr));

		memset(vcap, 0, sizeof(struct video_capability));
		strncpy(vcap->name, ZR_DEVNAME(zr), sizeof(vcap->name)-1);
		vcap->type = ZORAN_VID_TYPE;

		vcap->channels = zr->card.inputs;
		vcap->audios = 0;
		mutex_lock(&zr->resource_lock);
		vcap->maxwidth = BUZ_MAX_WIDTH;
		vcap->maxheight = BUZ_MAX_HEIGHT;
		vcap->minwidth = BUZ_MIN_WIDTH;
		vcap->minheight = BUZ_MIN_HEIGHT;
		mutex_unlock(&zr->resource_lock);

		return 0;
	}
		break;

	case VIDIOCGCHAN:
	{
		struct video_channel *vchan = arg;
		int channel = vchan->channel;

		dprintk(3, KERN_DEBUG "%s: VIDIOCGCHAN - channel=%d\n",
			ZR_DEVNAME(zr), vchan->channel);

		memset(vchan, 0, sizeof(struct video_channel));
		if (channel > zr->card.inputs || channel < 0) {
			dprintk(1,
				KERN_ERR
				"%s: VIDIOCGCHAN on not existing channel %d\n",
				ZR_DEVNAME(zr), channel);
			return -EINVAL;
		}

		strcpy(vchan->name, zr->card.input[channel].name);

		vchan->tuners = 0;
		vchan->flags = 0;
		vchan->type = VIDEO_TYPE_CAMERA;
		mutex_lock(&zr->resource_lock);
		vchan->norm = zr->norm;
		mutex_unlock(&zr->resource_lock);
		vchan->channel = channel;

		return 0;
	}
		break;

		/* 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 *vchan = arg;
		int res;

		dprintk(3,
			KERN_DEBUG
			"%s: VIDIOCSCHAN - channel=%d, norm=%d\n",
			ZR_DEVNAME(zr), vchan->channel, vchan->norm);

		mutex_lock(&zr->resource_lock);
		if ((res = zoran_set_input(zr, vchan->channel)))
			goto schan_unlock_and_return;
		if ((res = zoran_set_norm(zr, vchan->norm)))
			goto schan_unlock_and_return;

		/* Make sure the changes come into effect */
		res = wait_grab_pending(zr);
	schan_unlock_and_return:
		mutex_unlock(&zr->resource_lock);
		return res;
	}
		break;

	case VIDIOCGPICT:
	{
		struct video_picture *vpict = arg;

		dprintk(3, KERN_DEBUG "%s: VIDIOCGPICT\n", ZR_DEVNAME(zr));

		memset(vpict, 0, sizeof(struct video_picture));
		mutex_lock(&zr->resource_lock);
		vpict->hue = zr->hue;
		vpict->brightness = zr->brightness;
		vpict->contrast = zr->contrast;
		vpict->colour = zr->saturation;
		if (fh->overlay_settings.format) {
			vpict->depth = fh->overlay_settings.format->depth;
			vpict->palette = fh->overlay_settings.format->palette;
		} else {
			vpict->depth = 0;
		}
		mutex_unlock(&zr->resource_lock);

		return 0;
	}
		break;

	case VIDIOCSPICT:
	{
		struct video_picture *vpict = arg;
		int i;

		dprintk(3,
			KERN_DEBUG
			"%s: VIDIOCSPICT - bri=%d, hue=%d, col=%d, con=%d, dep=%d, pal=%d\n",
			ZR_DEVNAME(zr), vpict->brightness, vpict->hue,
			vpict->colour, vpict->contrast, vpict->depth,
			vpict->palette);

		for (i = 0; i < NUM_FORMATS; i++) {
			const struct zoran_format *fmt = &zoran_formats[i];

			if (fmt->palette != -1 &&
			    fmt->flags & ZORAN_FORMAT_OVERLAY &&
			    fmt->palette == vpict->palette &&
			    fmt->depth == vpict->depth)
				break;
		}
		if (i == NUM_FORMATS) {
			dprintk(1,
				KERN_ERR
				"%s: VIDIOCSPICT - Invalid palette %d\n",
				ZR_DEVNAME(zr), vpict->palette);
			return -EINVAL;
		}

		mutex_lock(&zr->resource_lock);

		decoder_command(zr, DECODER_SET_PICTURE, vpict);

		zr->hue = vpict->hue;
		zr->contrast = vpict->contrast;
		zr->saturation = vpict->colour;
		zr->brightness = vpict->brightness;

		fh->overlay_settings.format = &zoran_formats[i];

		mutex_unlock(&zr->resource_lock);

		return 0;
	}
		break;

	case VIDIOCCAPTURE:
	{
		int *on = arg, res;

		dprintk(3, KERN_DEBUG "%s: VIDIOCCAPTURE - on=%d\n",
			ZR_DEVNAME(zr), *on);

		mutex_lock(&zr->resource_lock);
		res = setup_overlay(file, *on);
		mutex_unlock(&zr->resource_lock);

		return res;
	}
		break;

	case VIDIOCGWIN:
	{
		struct video_window *vwin = arg;

		dprintk(3, KERN_DEBUG "%s: VIDIOCGWIN\n", ZR_DEVNAME(zr));

		memset(vwin, 0, sizeof(struct video_window));
		mutex_lock(&zr->resource_lock);
		vwin->x = fh->overlay_settings.x;
		vwin->y = fh->overlay_settings.y;
		vwin->width = fh->overlay_settings.width;
		vwin->height = fh->overlay_settings.height;
		mutex_unlock(&zr->resource_lock);
		vwin->clipcount = 0;
		return 0;
	}
		break;

	case VIDIOCSWIN:
	{
		struct video_window *vwin = arg;
		int res;

		dprintk(3,
			KERN_DEBUG
			"%s: VIDIOCSWIN - x=%d, y=%d, w=%d, h=%d, clipcount=%d\n",
			ZR_DEVNAME(zr), vwin->x, vwin->y, vwin->width,
			vwin->height, vwin->clipcount);

		mutex_lock(&zr->resource_lock);
		res =
		    setup_window(file, vwin->x, vwin->y, vwin->width,
				 vwin->height, vwin->clips,
				 vwin->clipcount, NULL);
		mutex_unlock(&zr->resource_lock);

		return res;
	}
		break;

	case VIDIOCGFBUF:
	{
		struct video_buffer *vbuf = arg;

		dprintk(3, KERN_DEBUG "%s: VIDIOCGFBUF\n", ZR_DEVNAME(zr));

		mutex_lock(&zr->resource_lock);
		*vbuf = zr->buffer;
		mutex_unlock(&zr->resource_lock);
		return 0;
	}
		break;

	case VIDIOCSFBUF:
	{
		struct video_buffer *vbuf = arg;
		int i, res = 0;

		dprintk(3,
			KERN_DEBUG
			"%s: VIDIOCSFBUF - base=%p, w=%d, h=%d, depth=%d, bpl=%d\n",
			ZR_DEVNAME(zr), vbuf->base, vbuf->width,
			vbuf->height, vbuf->depth, vbuf->bytesperline);

		for (i = 0; i < NUM_FORMATS; i++)
			if (zoran_formats[i].depth == vbuf->depth)
				break;
		if (i == NUM_FORMATS) {
			dprintk(1,
				KERN_ERR
				"%s: VIDIOCSFBUF - invalid fbuf depth %d\n",
				ZR_DEVNAME(zr), vbuf->depth);
			return -EINVAL;
		}

		mutex_lock(&zr->resource_lock);
		res =
		    setup_fbuffer(file, vbuf->base, &zoran_formats[i],
				  vbuf->width, vbuf->height,
				  vbuf->bytesperline);
		mutex_unlock(&zr->resource_lock);

		return res;
	}
		break;

	case VIDIOCSYNC:
	{
		int *frame = arg, res;

		dprintk(3, KERN_DEBUG "%s: VIDIOCSYNC - frame=%d\n",
			ZR_DEVNAME(zr), *frame);

		mutex_lock(&zr->resource_lock);
		res = v4l_sync(file, *frame);
		mutex_unlock(&zr->resource_lock);
		if (!res)
			zr->v4l_sync_tail++;
		return res;
	}
		break;

	case VIDIOCMCAPTURE:
	{
		struct video_mmap *vmap = arg;
		int res;

		dprintk(3,
			KERN_DEBUG
			"%s: VIDIOCMCAPTURE - frame=%d, geom=%dx%d, fmt=%d\n",
			ZR_DEVNAME(zr), vmap->frame, vmap->width, vmap->height,
			vmap->format);

		mutex_lock(&zr->resource_lock);
		res = v4l_grab(file, vmap);
		mutex_unlock(&zr->resource_lock);
		return res;
	}
		break;

	case VIDIOCGMBUF:
	{
		struct video_mbuf *vmbuf = arg;
		int i, res = 0;

		dprintk(3, KERN_DEBUG "%s: VIDIOCGMBUF\n", ZR_DEVNAME(zr));

		vmbuf->size =
		    fh->v4l_buffers.num_buffers *
		    fh->v4l_buffers.buffer_size;
		vmbuf->frames = fh->v4l_buffers.num_buffers;
		for (i = 0; i < vmbuf->frames; i++) {
			vmbuf->offsets[i] =
			    i * fh->v4l_buffers.buffer_size;
		}

		mutex_lock(&zr->resource_lock);

		if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) {
			dprintk(1,
				KERN_ERR
				"%s: VIDIOCGMBUF - buffers already allocated\n",
				ZR_DEVNAME(zr));
			res = -EINVAL;
			goto v4l1reqbuf_unlock_and_return;
		}

		if (v4l_fbuffer_alloc(file)) {
			res = -ENOMEM;
			goto v4l1reqbuf_unlock_and_return;
		}

		/* The next mmap will map the V4L buffers */
		fh->map_mode = ZORAN_MAP_MODE_RAW;
	v4l1reqbuf_unlock_and_return:
		mutex_unlock(&zr->resource_lock);

		return res;
	}
		break;

	case VIDIOCGUNIT:
	{
		struct video_unit *vunit = arg;

		dprintk(3, KERN_DEBUG "%s: VIDIOCGUNIT\n", ZR_DEVNAME(zr));

		vunit->video = zr->video_dev->minor;
		vunit->vbi = VIDEO_NO_UNIT;
		vunit->radio = VIDEO_NO_UNIT;
		vunit->audio = VIDEO_NO_UNIT;
		vunit->teletext = VIDEO_NO_UNIT;

		return 0;
	}
		break;

		/*
		 * 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:
	{
		dprintk(3, KERN_ERR "%s: VIDIOCGCAPTURE not supported\n",
			ZR_DEVNAME(zr));
		return -EINVAL;
	}
		break;

	case VIDIOCSCAPTURE:
	{
		dprintk(3, KERN_ERR "%s: VIDIOCSCAPTURE not supported\n",
			ZR_DEVNAME(zr));
		return -EINVAL;
	}
		break;

	case BUZIOC_G_PARAMS:
	{
		struct zoran_params *bparams = arg;

		dprintk(3, KERN_DEBUG "%s: BUZIOC_G_PARAMS\n", ZR_DEVNAME(zr));

		memset(bparams, 0, sizeof(struct zoran_params));
		bparams->major_version = MAJOR_VERSION;
		bparams->minor_version = MINOR_VERSION;

		mutex_lock(&zr->resource_lock);

		bparams->norm = zr->norm;
		bparams->input = zr->input;

		bparams->decimation = fh->jpg_settings.decimation;
		bparams->HorDcm = fh->jpg_settings.HorDcm;
		bparams->VerDcm = fh->jpg_settings.VerDcm;
		bparams->TmpDcm = fh->jpg_settings.TmpDcm;
		bparams->field_per_buff = fh->jpg_settings.field_per_buff;
		bparams->img_x = fh->jpg_settings.img_x;
		bparams->img_y = fh->jpg_settings.img_y;
		bparams->img_width = fh->jpg_settings.img_width;
		bparams->img_height = fh->jpg_settings.img_height;
		bparams->odd_even = fh->jpg_settings.odd_even;

		bparams->quality = fh->jpg_settings.jpg_comp.quality;
		bparams->APPn = fh->jpg_settings.jpg_comp.APPn;
		bparams->APP_len = fh->jpg_settings.jpg_comp.APP_len;
		memcpy(bparams->APP_data,
		       fh->jpg_settings.jpg_comp.APP_data,
		       sizeof(bparams->APP_data));
		bparams->COM_len = zr->jpg_settings.jpg_comp.COM_len;
		memcpy(bparams->COM_data,
		       fh->jpg_settings.jpg_comp.COM_data,
		       sizeof(bparams->COM_data));
		bparams->jpeg_markers =
		    fh->jpg_settings.jpg_comp.jpeg_markers;

		mutex_unlock(&zr->resource_lock);

		bparams->VFIFO_FB = 0;

		return 0;
	}
		break;

	case BUZIOC_S_PARAMS:
	{
		struct zoran_params *bparams = arg;
		int res = 0;

		dprintk(3, KERN_DEBUG "%s: BUZIOC_S_PARAMS\n", ZR_DEVNAME(zr));

		settings.decimation = bparams->decimation;
		settings.HorDcm = bparams->HorDcm;
		settings.VerDcm = bparams->VerDcm;
		settings.TmpDcm = bparams->TmpDcm;
		settings.field_per_buff = bparams->field_per_buff;
		settings.img_x = bparams->img_x;
		settings.img_y = bparams->img_y;
		settings.img_width = bparams->img_width;
		settings.img_height = bparams->img_height;
		settings.odd_even = bparams->odd_even;

		settings.jpg_comp.quality = bparams->quality;
		settings.jpg_comp.APPn = bparams->APPn;
		settings.jpg_comp.APP_len = bparams->APP_len;
		memcpy(settings.jpg_comp.APP_data, bparams->APP_data,
		       sizeof(bparams->APP_data));
		settings.jpg_comp.COM_len = bparams->COM_len;
		memcpy(settings.jpg_comp.COM_data, bparams->COM_data,
		       sizeof(bparams->COM_data));
		settings.jpg_comp.jpeg_markers = bparams->jpeg_markers;

		mutex_lock(&zr->resource_lock);

		if (zr->codec_mode != BUZ_MODE_IDLE) {
			dprintk(1,
				KERN_ERR
				"%s: BUZIOC_S_PARAMS called, but Buz in capture/playback mode\n",
				ZR_DEVNAME(zr));
			res = -EINVAL;
			goto sparams_unlock_and_return;
		}

		/* Check the params first before overwriting our
		 * nternal values */
		if (zoran_check_jpg_settings(zr, &settings)) {
			res = -EINVAL;
			goto sparams_unlock_and_return;
		}

		fh->jpg_settings = settings;
	sparams_unlock_and_return:
		mutex_unlock(&zr->resource_lock);

		return res;
	}
		break;

	case BUZIOC_REQBUFS:
	{
		struct zoran_requestbuffers *breq = arg;
		int res = 0;

		dprintk(3,
			KERN_DEBUG
			"%s: BUZIOC_REQBUFS - count=%lu, size=%lu\n",
			ZR_DEVNAME(zr), breq->count, breq->size);

		/* Enforce reasonable lower and upper limits */
		if (breq->count < 4)
			breq->count = 4;	/* Could be choosen smaller */
		if (breq->count > jpg_nbufs)
			breq->count = jpg_nbufs;
		breq->size = PAGE_ALIGN(breq->size);
		if (breq->size < 8192)
			breq->size = 8192;	/* Arbitrary */
		/* breq->size is limited by 1 page for the stat_com
		 * tables to a Maximum of 2 MB */
		if (breq->size > jpg_bufsize)
			breq->size = jpg_bufsize;
		if (fh->jpg_buffers.need_contiguous &&
		    breq->size > MAX_KMALLOC_MEM)
			breq->size = MAX_KMALLOC_MEM;

		mutex_lock(&zr->resource_lock);

		if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) {
			dprintk(1,
				KERN_ERR
				"%s: BUZIOC_REQBUFS - buffers allready allocated\n",
				ZR_DEVNAME(zr));
			res = -EBUSY;
			goto jpgreqbuf_unlock_and_return;
		}

		fh->jpg_buffers.num_buffers = breq->count;
		fh->jpg_buffers.buffer_size = breq->size;

		if (jpg_fbuffer_alloc(file)) {
			res = -ENOMEM;
			goto jpgreqbuf_unlock_and_return;
		}

		/* The next mmap will map the MJPEG buffers - could
		 * also be *_PLAY, but it doesn't matter here */
		fh->map_mode = ZORAN_MAP_MODE_JPG_REC;
	jpgreqbuf_unlock_and_return:
		mutex_unlock(&zr->resource_lock);

		return res;
	}
		break;

	case BUZIOC_QBUF_CAPT:
	{
		int *frame = arg, res;

		dprintk(3, KERN_DEBUG "%s: BUZIOC_QBUF_CAPT - frame=%d\n",
			ZR_DEVNAME(zr), *frame);

		mutex_lock(&zr->resource_lock);
		res = jpg_qbuf(file, *frame, BUZ_MODE_MOTION_COMPRESS);
		mutex_unlock(&zr->resource_lock);

		return res;
	}
		break;

	case BUZIOC_QBUF_PLAY:
	{
		int *frame = arg, res;

		dprintk(3, KERN_DEBUG "%s: BUZIOC_QBUF_PLAY - frame=%d\n",
			ZR_DEVNAME(zr), *frame);

		mutex_lock(&zr->resource_lock);
		res = jpg_qbuf(file, *frame, BUZ_MODE_MOTION_DECOMPRESS);
		mutex_unlock(&zr->resource_lock);

		return res;
	}
		break;

	case BUZIOC_SYNC:
	{
		struct zoran_sync *bsync = arg;
		int res;

		dprintk(3, KERN_DEBUG "%s: BUZIOC_SYNC\n", ZR_DEVNAME(zr));

		mutex_lock(&zr->resource_lock);
		res = jpg_sync(file, bsync);
		mutex_unlock(&zr->resource_lock);

		return res;
	}
		break;

	case BUZIOC_G_STATUS:
	{
		struct zoran_status *bstat = arg;
		int norm, input, status, res = 0;

		dprintk(3, KERN_DEBUG "%s: BUZIOC_G_STATUS\n", ZR_DEVNAME(zr));

		if (zr->codec_mode != BUZ_MODE_IDLE) {
			dprintk(1,
				KERN_ERR
				"%s: BUZIOC_G_STATUS called but Buz in capture/playback mode\n",
				ZR_DEVNAME(zr));
			return -EINVAL;
		}

		input = zr->card.input[bstat->input].muxsel;
		norm = VIDEO_MODE_AUTO;

		mutex_lock(&zr->resource_lock);

		if (zr->codec_mode != BUZ_MODE_IDLE) {
			dprintk(1,
				KERN_ERR
				"%s: BUZIOC_G_STATUS called, but Buz in capture/playback mode\n",
				ZR_DEVNAME(zr));
			res = -EINVAL;
			goto gstat_unlock_and_return;
		}

		decoder_command(zr, DECODER_SET_INPUT, &input);
		decoder_command(zr, DECODER_SET_NORM, &norm);

		/* sleep 1 second */
		ssleep(1);

		/* Get status of video decoder */
		decoder_command(zr, DECODER_GET_STATUS, &status);

		/* restore previous input and norm */
		input = zr->card.input[zr->input].muxsel;
		decoder_command(zr, DECODER_SET_INPUT, &input);
		decoder_command(zr, DECODER_SET_NORM, &zr->norm);
	gstat_unlock_and_return:
		mutex_unlock(&zr->resource_lock);

		if (!res) {
			bstat->signal =
			    (status & DECODER_STATUS_GOOD) ? 1 : 0;
			if (status & DECODER_STATUS_NTSC)
				bstat->norm = VIDEO_MODE_NTSC;
			else if (status & DECODER_STATUS_SECAM)
				bstat->norm = VIDEO_MODE_SECAM;
			else
				bstat->norm = VIDEO_MODE_PAL;

			bstat->color =
			    (status & DECODER_STATUS_COLOR) ? 1 : 0;
		}

		return res;
	}
		break;

		/* The new video4linux2 capture interface - much nicer than video4linux1, since
		 * it allows for integrating the JPEG capturing calls inside standard v4l2
		 */

	case VIDIOC_QUERYCAP:
	{
		struct v4l2_capability *cap = arg;

		dprintk(3, KERN_DEBUG "%s: VIDIOC_QUERYCAP\n", ZR_DEVNAME(zr));

		memset(cap, 0, sizeof(*cap));
		strncpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card)-1);
		strncpy(cap->driver, "zoran", sizeof(cap->driver)-1);
		snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
			 pci_name(zr->pci_dev));
		cap->version =
		    KERNEL_VERSION(MAJOR_VERSION, MINOR_VERSION,
				   RELEASE_VERSION);
		cap->capabilities = ZORAN_V4L2_VID_FLAGS;

		return 0;
	}
		break;

	case VIDIOC_ENUM_FMT:
	{
		struct v4l2_fmtdesc *fmt = arg;
		int index = fmt->index, num = -1, i, flag = 0, type =
		    fmt->type;

		dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUM_FMT - index=%d\n",
			ZR_DEVNAME(zr), fmt->index);

		switch (fmt->type) {
		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
			flag = ZORAN_FORMAT_CAPTURE;
			break;
		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
			flag = ZORAN_FORMAT_PLAYBACK;
			break;
		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
			flag = ZORAN_FORMAT_OVERLAY;
			break;
		default:
			dprintk(1,
				KERN_ERR
				"%s: VIDIOC_ENUM_FMT - unknown type %d\n",
				ZR_DEVNAME(zr), fmt->type);
			return -EINVAL;
		}

		for (i = 0; i < NUM_FORMATS; i++) {
			if (zoran_formats[i].flags & flag)
				num++;
			if (num == fmt->index)
				break;
		}
		if (fmt->index < 0 /* late, but not too late */  ||
		    i == NUM_FORMATS)
			return -EINVAL;

		memset(fmt, 0, sizeof(*fmt));
		fmt->index = index;
		fmt->type = type;
		strncpy(fmt->description, zoran_formats[i].name, sizeof(fmt->description)-1);
		fmt->pixelformat = zoran_formats[i].fourcc;
		if (zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED)
			fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;

		return 0;
	}
		break;

	case VIDIOC_G_FMT:
	{
		struct v4l2_format *fmt = arg;
		int type = fmt->type;

		dprintk(5, KERN_DEBUG "%s: VIDIOC_G_FMT\n", ZR_DEVNAME(zr));

		memset(fmt, 0, sizeof(*fmt));
		fmt->type = type;

		switch (fmt->type) {
		case V4L2_BUF_TYPE_VIDEO_OVERLAY:

			mutex_lock(&zr->resource_lock);

			fmt->fmt.win.w.left = fh->overlay_settings.x;
			fmt->fmt.win.w.top = fh->overlay_settings.y;
			fmt->fmt.win.w.width = fh->overlay_settings.width;
			fmt->fmt.win.w.height =
			    fh->overlay_settings.height;
			if (fh->overlay_settings.width * 2 >
			    BUZ_MAX_HEIGHT)
				fmt->fmt.win.field = V4L2_FIELD_INTERLACED;
			else
				fmt->fmt.win.field = V4L2_FIELD_TOP;

			mutex_unlock(&zr->resource_lock);

			break;

		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
		case V4L2_BUF_TYPE_VIDEO_OUTPUT:

			mutex_lock(&zr->resource_lock);

			if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
			    fh->map_mode == ZORAN_MAP_MODE_RAW) {

				fmt->fmt.pix.width =
				    fh->v4l_settings.width;
				fmt->fmt.pix.height =
				    fh->v4l_settings.height;
				fmt->fmt.pix.sizeimage =
				    fh->v4l_settings.bytesperline *
				    fh->v4l_settings.height;
				fmt->fmt.pix.pixelformat =
				    fh->v4l_settings.format->fourcc;
				fmt->fmt.pix.colorspace =
				    fh->v4l_settings.format->colorspace;
				fmt->fmt.pix.bytesperline = 0;
				if (BUZ_MAX_HEIGHT <
				    (fh->v4l_settings.height * 2))
					fmt->fmt.pix.field =
					    V4L2_FIELD_INTERLACED;
				else
					fmt->fmt.pix.field =
					    V4L2_FIELD_TOP;

			} else {

				fmt->fmt.pix.width =
				    fh->jpg_settings.img_width /
				    fh->jpg_settings.HorDcm;
				fmt->fmt.pix.height =
				    fh->jpg_settings.img_height /
				    (fh->jpg_settings.VerDcm *
				     fh->jpg_settings.TmpDcm);
				fmt->fmt.pix.sizeimage =
				    zoran_v4l2_calc_bufsize(&fh->
							    jpg_settings);
				fmt->fmt.pix.pixelformat =
				    V4L2_PIX_FMT_MJPEG;
				if (fh->jpg_settings.TmpDcm == 1)
					fmt->fmt.pix.field =
					    (fh->jpg_settings.
					     odd_even ? V4L2_FIELD_SEQ_BT :
					     V4L2_FIELD_SEQ_BT);
				else
					fmt->fmt.pix.field =
					    (fh->jpg_settings.
					     odd_even ? V4L2_FIELD_TOP :
					     V4L2_FIELD_BOTTOM);

				fmt->fmt.pix.bytesperline = 0;
				fmt->fmt.pix.colorspace =
				    V4L2_COLORSPACE_SMPTE170M;
			}

			mutex_unlock(&zr->resource_lock);

			break;

		default:
			dprintk(1,
				KERN_ERR
				"%s: VIDIOC_G_FMT - unsupported type %d\n",
				ZR_DEVNAME(zr), fmt->type);
			return -EINVAL;
		}
		return 0;
	}
		break;

	case VIDIOC_S_FMT:
	{
		struct v4l2_format *fmt = arg;
		int i, res = 0;
		__u32 printformat;

		dprintk(3, KERN_DEBUG "%s: VIDIOC_S_FMT - type=%d, ",
			ZR_DEVNAME(zr), fmt->type);

		switch (fmt->type) {
		case V4L2_BUF_TYPE_VIDEO_OVERLAY:

			dprintk(3, "x=%d, y=%d, w=%d, h=%d, cnt=%d, map=0x%p\n",
				fmt->fmt.win.w.left, fmt->fmt.win.w.top,
				fmt->fmt.win.w.width,
				fmt->fmt.win.w.height,
				fmt->fmt.win.clipcount,
				fmt->fmt.win.bitmap);
			mutex_lock(&zr->resource_lock);
			res =
			    setup_window(file, fmt->fmt.win.w.left,
					 fmt->fmt.win.w.top,
					 fmt->fmt.win.w.width,
					 fmt->fmt.win.w.height,
					 (struct video_clip __user *)
					   fmt->fmt.win.clips,
					 fmt->fmt.win.clipcount,
					 fmt->fmt.win.bitmap);
			mutex_unlock(&zr->resource_lock);
			return res;
			break;

		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
		case V4L2_BUF_TYPE_VIDEO_OUTPUT:

			printformat =
			    __cpu_to_le32(fmt->fmt.pix.pixelformat);
			dprintk(3, "size=%dx%d, fmt=0x%x (%4.4s)\n",
				fmt->fmt.pix.width, fmt->fmt.pix.height,
				fmt->fmt.pix.pixelformat,
				(char *) &printformat);

			if (fmt->fmt.pix.bytesperline > 0) {
				dprintk(5,
					KERN_ERR "%s: bpl not supported\n",
					ZR_DEVNAME(zr));
				return -EINVAL;
			}

			/* we can be requested to do JPEG/raw playback/capture */
			if (!
			    (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
			     (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
			      fmt->fmt.pix.pixelformat ==
			      V4L2_PIX_FMT_MJPEG))) {
				dprintk(1,
					KERN_ERR
					"%s: VIDIOC_S_FMT - unknown type %d/0x%x(%4.4s) combination\n",
					ZR_DEVNAME(zr), fmt->type,
					fmt->fmt.pix.pixelformat,
					(char *) &printformat);
				return -EINVAL;
			}

			if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) {
				mutex_lock(&zr->resource_lock);

				settings = fh->jpg_settings;

				if (fh->v4l_buffers.allocated ||
				    fh->jpg_buffers.allocated) {
					dprintk(1,
						KERN_ERR
						"%s: VIDIOC_S_FMT - cannot change capture mode\n",
						ZR_DEVNAME(zr));
					res = -EBUSY;
					goto sfmtjpg_unlock_and_return;
				}

				/* we actually need to set 'real' parameters now */
				if ((fmt->fmt.pix.height * 2) >
				    BUZ_MAX_HEIGHT)
					settings.TmpDcm = 1;
				else
					settings.TmpDcm = 2;
				settings.decimation = 0;
				if (fmt->fmt.pix.height <=
				    fh->jpg_settings.img_height / 2)
					settings.VerDcm = 2;
				else
					settings.VerDcm = 1;
				if (fmt->fmt.pix.width <=
				    fh->jpg_settings.img_width / 4)
					settings.HorDcm = 4;
				else if (fmt->fmt.pix.width <=
					 fh->jpg_settings.img_width / 2)
					settings.HorDcm = 2;
				else
					settings.HorDcm = 1;
				if (settings.TmpDcm == 1)
					settings.field_per_buff = 2;
				else
					settings.field_per_buff = 1;

				/* check */
				if ((res =
				     zoran_check_jpg_settings(zr,
							      &settings)))
					goto sfmtjpg_unlock_and_return;

				/* it's ok, so set them */
				fh->jpg_settings = settings;

				/* tell the user what we actually did */
				fmt->fmt.pix.width =
				    settings.img_width / settings.HorDcm;
				fmt->fmt.pix.height =
				    settings.img_height * 2 /
				    (settings.TmpDcm * settings.VerDcm);
				if (settings.TmpDcm == 1)
					fmt->fmt.pix.field =
					    (fh->jpg_settings.
					     odd_even ? V4L2_FIELD_SEQ_TB :
					     V4L2_FIELD_SEQ_BT);
				else
					fmt->fmt.pix.field =
					    (fh->jpg_settings.
					     odd_even ? V4L2_FIELD_TOP :
					     V4L2_FIELD_BOTTOM);
				fh->jpg_buffers.buffer_size =
				    zoran_v4l2_calc_bufsize(&fh->
							    jpg_settings);
				fmt->fmt.pix.sizeimage =
				    fh->jpg_buffers.buffer_size;

				/* we hereby abuse this variable to show that
				 * we're gonna do mjpeg capture */
				fh->map_mode =
				    (fmt->type ==
				     V4L2_BUF_TYPE_VIDEO_CAPTURE) ?
				    ZORAN_MAP_MODE_JPG_REC :
				    ZORAN_MAP_MODE_JPG_PLAY;
			sfmtjpg_unlock_and_return:
				mutex_unlock(&zr->resource_lock);
			} else {
				for (i = 0; i < NUM_FORMATS; i++)
					if (fmt->fmt.pix.pixelformat ==
					    zoran_formats[i].fourcc)
						break;
				if (i == NUM_FORMATS) {
					dprintk(1,
						KERN_ERR
						"%s: VIDIOC_S_FMT - unknown/unsupported format 0x%x (%4.4s)\n",
						ZR_DEVNAME(zr),
						fmt->fmt.pix.pixelformat,
						(char *) &printformat);
					return -EINVAL;
				}
				mutex_lock(&zr->resource_lock);
				if (fh->jpg_buffers.allocated ||
				    (fh->v4l_buffers.allocated &&
				     fh->v4l_buffers.active !=
				     ZORAN_FREE)) {
					dprintk(1,
						KERN_ERR
						"%s: VIDIOC_S_FMT - cannot change capture mode\n",
						ZR_DEVNAME(zr));
					res = -EBUSY;
					goto sfmtv4l_unlock_and_return;
				}
				if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT)
					fmt->fmt.pix.height =
					    BUZ_MAX_HEIGHT;
				if (fmt->fmt.pix.width > BUZ_MAX_WIDTH)
					fmt->fmt.pix.width = BUZ_MAX_WIDTH;

				if ((res =
				     zoran_v4l_set_format(file,
							  fmt->fmt.pix.
							  width,
							  fmt->fmt.pix.
							  height,
							  &zoran_formats
							  [i])))
					goto sfmtv4l_unlock_and_return;

				/* tell the user the
				 * results/missing stuff */
				fmt->fmt.pix.sizeimage =
					fh->v4l_settings.height *
					fh->v4l_settings.bytesperline;
				if (BUZ_MAX_HEIGHT <
				    (fh->v4l_settings.height * 2))
					fmt->fmt.pix.field =
					    V4L2_FIELD_INTERLACED;
				else
					fmt->fmt.pix.field =
					    V4L2_FIELD_TOP;

				fh->map_mode = ZORAN_MAP_MODE_RAW;
			sfmtv4l_unlock_and_return:
				mutex_unlock(&zr->resource_lock);
			}

			break;

		default:
			dprintk(3, "unsupported\n");
			dprintk(1,
				KERN_ERR
				"%s: VIDIOC_S_FMT - unsupported type %d\n",
				ZR_DEVNAME(zr), fmt->type);
			return -EINVAL;
		}

		return res;
	}
		break;

	case VIDIOC_G_FBUF:
	{
		struct v4l2_framebuffer *fb = arg;

		dprintk(3, KERN_DEBUG "%s: VIDIOC_G_FBUF\n", ZR_DEVNAME(zr));

		memset(fb, 0, sizeof(*fb));
		mutex_lock(&zr->resource_lock);
		fb->base = zr->buffer.base;
		fb->fmt.width = zr->buffer.width;
		fb->fmt.height = zr->buffer.height;
		if (zr->overlay_settings.format) {
			fb->fmt.pixelformat =
				fh->overlay_settings.format->fourcc;
		}
		fb->fmt.bytesperline = zr->buffer.bytesperline;
		mutex_unlock(&zr->resource_lock);
		fb->fmt.colorspace = V4L2_COLORSPACE_SRGB;
		fb->fmt.field = V4L2_FIELD_INTERLACED;
		fb->flags = V4L2_FBUF_FLAG_OVERLAY;
		fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;

		return 0;
	}
		break;

	case VIDIOC_S_FBUF:
	{
		int i, res = 0;
		struct v4l2_framebuffer *fb = arg;
		__u32 printformat = __cpu_to_le32(fb->fmt.pixelformat);

		dprintk(3,
			KERN_DEBUG
			"%s: VIDIOC_S_FBUF - base=0x%p, size=%dx%d, bpl=%d, fmt=0x%x (%4.4s)\n",
			ZR_DEVNAME(zr), fb->base, fb->fmt.width, fb->fmt.height,
			fb->fmt.bytesperline, fb->fmt.pixelformat,
			(char *) &printformat);

		for (i = 0; i < NUM_FORMATS; i++)
			if (zoran_formats[i].fourcc == fb->fmt.pixelformat)
				break;
		if (i == NUM_FORMATS) {
			dprintk(1,
				KERN_ERR
				"%s: VIDIOC_S_FBUF - format=0x%x (%4.4s) not allowed\n",
				ZR_DEVNAME(zr), fb->fmt.pixelformat,
				(char *) &printformat);
			return -EINVAL;
		}

		mutex_lock(&zr->resource_lock);
		res =
		    setup_fbuffer(file, fb->base, &zoran_formats[i],
				  fb->fmt.width, fb->fmt.height,
				  fb->fmt.bytesperline);
		mutex_unlock(&zr->resource_lock);

		return res;
	}
		break;

	case VIDIOC_OVERLAY:
	{
		int *on = arg, res;

		dprintk(3, KERN_DEBUG "%s: VIDIOC_PREVIEW - on=%d\n",
			ZR_DEVNAME(zr), *on);

		mutex_lock(&zr->resource_lock);
		res = setup_overlay(file, *on);
		mutex_unlock(&zr->resource_lock);

		return res;
	}
		break;

	case VIDIOC_REQBUFS:
	{
		struct v4l2_requestbuffers *req = arg;
		int res = 0;

		dprintk(3, KERN_DEBUG "%s: VIDIOC_REQBUFS - type=%d\n",
			ZR_DEVNAME(zr), req->type);

		if (req->memory != V4L2_MEMORY_MMAP) {
			dprintk(1,
				KERN_ERR
				"%s: only MEMORY_MMAP capture is supported, not %d\n",
				ZR_DEVNAME(zr), req->memory);
			return -EINVAL;
		}

		mutex_lock(&zr->resource_lock);

		if (fh->v4l_buffers.allocated || fh->jpg_buffers.allocated) {
			dprintk(1,
				KERN_ERR
				"%s: VIDIOC_REQBUFS - buffers allready allocated\n",
				ZR_DEVNAME(zr));
			res = -EBUSY;
			goto v4l2reqbuf_unlock_and_return;
		}

		if (fh->map_mode == ZORAN_MAP_MODE_RAW &&
		    req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {

			/* control user input */
			if (req->count < 2)
				req->count = 2;
			if (req->count > v4l_nbufs)
				req->count = v4l_nbufs;
			fh->v4l_buffers.num_buffers = req->count;

			if (v4l_fbuffer_alloc(file)) {
				res = -ENOMEM;
				goto v4l2reqbuf_unlock_and_return;
			}

			/* The next mmap will map the V4L buffers */
			fh->map_mode = ZORAN_MAP_MODE_RAW;

		} else if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC ||
			   fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) {

			/* we need to calculate size ourselves now */
			if (req->count < 4)
				req->count = 4;
			if (req->count > jpg_nbufs)
				req->count = jpg_nbufs;
			fh->jpg_buffers.num_buffers = req->count;
			fh->jpg_buffers.buffer_size =
			    zoran_v4l2_calc_bufsize(&fh->jpg_settings);

			if (jpg_fbuffer_alloc(file)) {
				res = -ENOMEM;
				goto v4l2reqbuf_unlock_and_return;
			}

			/* The next mmap will map the MJPEG buffers */
			if (req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
				fh->map_mode = ZORAN_MAP_MODE_JPG_REC;
			else
				fh->map_mode = ZORAN_MAP_MODE_JPG_PLAY;

		} else {
			dprintk(1,
				KERN_ERR
				"%s: VIDIOC_REQBUFS - unknown type %d\n",
				ZR_DEVNAME(zr), req->type);
			res = -EINVAL;
			goto v4l2reqbuf_unlock_and_return;
		}
	v4l2reqbuf_unlock_and_return:
		mutex_unlock(&zr->resource_lock);

		return 0;
	}
		break;

	case VIDIOC_QUERYBUF:
	{
		struct v4l2_buffer *buf = arg;
		__u32 type = buf->type;
		int index = buf->index, res;

		dprintk(3,
			KERN_DEBUG
			"%s: VIDIOC_QUERYBUF - index=%d, type=%d\n",
			ZR_DEVNAME(zr), buf->index, buf->type);

		memset(buf, 0, sizeof(*buf));
		buf->type = type;
		buf->index = index;

		mutex_lock(&zr->resource_lock);
		res = zoran_v4l2_buffer_status(file, buf, buf->index);
		mutex_unlock(&zr->resource_lock);

		return res;
	}
		break;

	case VIDIOC_QBUF:
	{
		struct v4l2_buffer *buf = arg;
		int res = 0, codec_mode, buf_type;

		dprintk(3,
			KERN_DEBUG "%s: VIDIOC_QBUF - type=%d, index=%d\n",
			ZR_DEVNAME(zr), buf->type, buf->index);

		mutex_lock(&zr->resource_lock);

		switch (fh->map_mode) {
		case ZORAN_MAP_MODE_RAW:
			if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
				dprintk(1,
					KERN_ERR
					"%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
					ZR_DEVNAME(zr), buf->type, fh->map_mode);
				res = -EINVAL;
				goto qbuf_unlock_and_return;
			}

			res = zoran_v4l_queue_frame(file, buf->index);
			if (res)
				goto qbuf_unlock_and_return;
			if (!zr->v4l_memgrab_active &&
			    fh->v4l_buffers.active == ZORAN_LOCKED)
				zr36057_set_memgrab(zr, 1);
			break;

		case ZORAN_MAP_MODE_JPG_REC:
		case ZORAN_MAP_MODE_JPG_PLAY:
			if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) {
				buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
				codec_mode = BUZ_MODE_MOTION_DECOMPRESS;
			} else {
				buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
				codec_mode = BUZ_MODE_MOTION_COMPRESS;
			}

			if (buf->type != buf_type) {
				dprintk(1,
					KERN_ERR
					"%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
					ZR_DEVNAME(zr), buf->type, fh->map_mode);
				res = -EINVAL;
				goto qbuf_unlock_and_return;
			}

			res =
			    zoran_jpg_queue_frame(file, buf->index,
						  codec_mode);
			if (res != 0)
				goto qbuf_unlock_and_return;
			if (zr->codec_mode == BUZ_MODE_IDLE &&
			    fh->jpg_buffers.active == ZORAN_LOCKED) {
				zr36057_enable_jpg(zr, codec_mode);
			}
			break;

		default:
			dprintk(1,
				KERN_ERR
				"%s: VIDIOC_QBUF - unsupported type %d\n",
				ZR_DEVNAME(zr), buf->type);
			res = -EINVAL;
			goto qbuf_unlock_and_return;
		}
	qbuf_unlock_and_return:
		mutex_unlock(&zr->resource_lock);

		return res;
	}
		break;

	case VIDIOC_DQBUF:
	{
		struct v4l2_buffer *buf = arg;
		int res = 0, buf_type, num = -1;	/* compiler borks here (?) */

		dprintk(3, KERN_DEBUG "%s: VIDIOC_DQBUF - type=%d\n",
			ZR_DEVNAME(zr), buf->type);

		mutex_lock(&zr->resource_lock);

		switch (fh->map_mode) {
		case ZORAN_MAP_MODE_RAW:
			if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
				dprintk(1,
					KERN_ERR
					"%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
					ZR_DEVNAME(zr), buf->type, fh->map_mode);
				res = -EINVAL;
				goto dqbuf_unlock_and_return;
			}

			num = zr->v4l_pend[zr->v4l_sync_tail & V4L_MASK_FRAME];
			if (file->f_flags & O_NONBLOCK &&
			    zr->v4l_buffers.buffer[num].state !=
			    BUZ_STATE_DONE) {
				res = -EAGAIN;
				goto dqbuf_unlock_and_return;
			}
			res = v4l_sync(file, num);
			if (res)
				goto dqbuf_unlock_and_return;
			else
				zr->v4l_sync_tail++;
			res = zoran_v4l2_buffer_status(file, buf, num);
			break;

		case ZORAN_MAP_MODE_JPG_REC:
		case ZORAN_MAP_MODE_JPG_PLAY:
		{
			struct zoran_sync bs;

			if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY)
				buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
			else
				buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

			if (buf->type != buf_type) {
				dprintk(1,
					KERN_ERR
					"%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
					ZR_DEVNAME(zr), buf->type, fh->map_mode);
				res = -EINVAL;
				goto dqbuf_unlock_and_return;
			}

			num =
			    zr->jpg_pend[zr->
					 jpg_que_tail & BUZ_MASK_FRAME];

			if (file->f_flags & O_NONBLOCK &&
			    zr->jpg_buffers.buffer[num].state !=
			    BUZ_STATE_DONE) {
				res = -EAGAIN;
				goto dqbuf_unlock_and_return;
			}
			res = jpg_sync(file, &bs);
			if (res)
				goto dqbuf_unlock_and_return;
			res =
			    zoran_v4l2_buffer_status(file, buf, bs.frame);
			break;
		}

		default:
			dprintk(1,
				KERN_ERR
				"%s: VIDIOC_DQBUF - unsupported type %d\n",
				ZR_DEVNAME(zr), buf->type);
			res = -EINVAL;
			goto dqbuf_unlock_and_return;
		}
	dqbuf_unlock_and_return:
		mutex_unlock(&zr->resource_lock);

		return res;
	}
		break;

	case VIDIOC_STREAMON:
	{
		int res = 0;

		dprintk(3, KERN_DEBUG "%s: VIDIOC_STREAMON\n", ZR_DEVNAME(zr));

		mutex_lock(&zr->resource_lock);

		switch (fh->map_mode) {
		case ZORAN_MAP_MODE_RAW:	/* raw capture */
			if (zr->v4l_buffers.active != ZORAN_ACTIVE ||
			    fh->v4l_buffers.active != ZORAN_ACTIVE) {
				res = -EBUSY;
				goto strmon_unlock_and_return;
			}

			zr->v4l_buffers.active = fh->v4l_buffers.active =
			    ZORAN_LOCKED;
			zr->v4l_settings = fh->v4l_settings;

			zr->v4l_sync_tail = zr->v4l_pend_tail;
			if (!zr->v4l_memgrab_active &&
			    zr->v4l_pend_head != zr->v4l_pend_tail) {
				zr36057_set_memgrab(zr, 1);
			}
			break;

		case ZORAN_MAP_MODE_JPG_REC:
		case ZORAN_MAP_MODE_JPG_PLAY:
			/* what is the codec mode right now? */
			if (zr->jpg_buffers.active != ZORAN_ACTIVE ||
			    fh->jpg_buffers.active != ZORAN_ACTIVE) {
				res = -EBUSY;
				goto strmon_unlock_and_return;
			}

			zr->jpg_buffers.active = fh->jpg_buffers.active =
			    ZORAN_LOCKED;

			if (zr->jpg_que_head != zr->jpg_que_tail) {
				/* Start the jpeg codec when the first frame is queued  */
				jpeg_start(zr);
			}

			break;
		default:
			dprintk(1,
				KERN_ERR
				"%s: VIDIOC_STREAMON - invalid map mode %d\n",
				ZR_DEVNAME(zr), fh->map_mode);
			res = -EINVAL;
			goto strmon_unlock_and_return;
		}
	strmon_unlock_and_return:
		mutex_unlock(&zr->resource_lock);

		return res;
	}
		break;

	case VIDIOC_STREAMOFF:
	{
		int i, res = 0;

		dprintk(3, KERN_DEBUG "%s: VIDIOC_STREAMOFF\n", ZR_DEVNAME(zr));

		mutex_lock(&zr->resource_lock);

		switch (fh->map_mode) {
		case ZORAN_MAP_MODE_RAW:	/* raw capture */
			if (fh->v4l_buffers.active == ZORAN_FREE &&
			    zr->v4l_buffers.active != ZORAN_FREE) {
				res = -EPERM;	/* stay off other's settings! */
				goto strmoff_unlock_and_return;
			}
			if (zr->v4l_buffers.active == ZORAN_FREE)
				goto strmoff_unlock_and_return;

			/* unload capture */
			if (zr->v4l_memgrab_active) {
				unsigned long flags;

				spin_lock_irqsave(&zr->spinlock, flags);
				zr36057_set_memgrab(zr, 0);
				spin_unlock_irqrestore(&zr->spinlock, flags);
			}

			for (i = 0; i < fh->v4l_buffers.num_buffers; i++)
				zr->v4l_buffers.buffer[i].state =
				    BUZ_STATE_USER;
			fh->v4l_buffers = zr->v4l_buffers;

			zr->v4l_buffers.active = fh->v4l_buffers.active =
			    ZORAN_FREE;

			zr->v4l_grab_seq = 0;
			zr->v4l_pend_head = zr->v4l_pend_tail = 0;
			zr->v4l_sync_tail = 0;

			break;

		case ZORAN_MAP_MODE_JPG_REC:
		case ZORAN_MAP_MODE_JPG_PLAY:
			if (fh->jpg_buffers.active == ZORAN_FREE &&
			    zr->jpg_buffers.active != ZORAN_FREE) {
				res = -EPERM;	/* stay off other's settings! */
				goto strmoff_unlock_and_return;
			}
			if (zr->jpg_buffers.active == ZORAN_FREE)
				goto strmoff_unlock_and_return;

			res =
			    jpg_qbuf(file, -1,
				     (fh->map_mode ==
				      ZORAN_MAP_MODE_JPG_REC) ?
				     BUZ_MODE_MOTION_COMPRESS :
				     BUZ_MODE_MOTION_DECOMPRESS);
			if (res)
				goto strmoff_unlock_and_return;
			break;
		default:
			dprintk(1,
				KERN_ERR
				"%s: VIDIOC_STREAMOFF - invalid map mode %d\n",
				ZR_DEVNAME(zr), fh->map_mode);
			res = -EINVAL;
			goto strmoff_unlock_and_return;
		}
	strmoff_unlock_and_return:
		mutex_unlock(&zr->resource_lock);

		return res;
	}
		break;

	case VIDIOC_QUERYCTRL:
	{
		struct v4l2_queryctrl *ctrl = arg;

		dprintk(3, KERN_DEBUG "%s: VIDIOC_QUERYCTRL - id=%d\n",
			ZR_DEVNAME(zr), ctrl->id);

		/* we only support hue/saturation/contrast/brightness */
		if (ctrl->id < V4L2_CID_BRIGHTNESS ||
		    ctrl->id > V4L2_CID_HUE)
			return -EINVAL;
		else {
			int id = ctrl->id;
			memset(ctrl, 0, sizeof(*ctrl));
			ctrl->id = id;
		}

		switch (ctrl->id) {
		case V4L2_CID_BRIGHTNESS:
			strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)-1);
			break;
		case V4L2_CID_CONTRAST:
			strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)-1);
			break;
		case V4L2_CID_SATURATION:
			strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)-1);
			break;
		case V4L2_CID_HUE:
			strncpy(ctrl->name, "Hue", sizeof(ctrl->name)-1);
			break;
		}

		ctrl->minimum = 0;
		ctrl->maximum = 65535;
		ctrl->step = 1;
		ctrl->default_value = 32768;
		ctrl->type = V4L2_CTRL_TYPE_INTEGER;

		return 0;
	}
		break;

	case VIDIOC_G_CTRL:
	{
		struct v4l2_control *ctrl = arg;

		dprintk(3, KERN_DEBUG "%s: VIDIOC_G_CTRL - id=%d\n",
			ZR_DEVNAME(zr), ctrl->id);

		/* we only support hue/saturation/contrast/brightness */
		if (ctrl->id < V4L2_CID_BRIGHTNESS ||
		    ctrl->id > V4L2_CID_HUE)
			return -EINVAL;

		mutex_lock(&zr->resource_lock);
		switch (ctrl->id) {
		case V4L2_CID_BRIGHTNESS:
			ctrl->value = zr->brightness;
			break;
		case V4L2_CID_CONTRAST:
			ctrl->value = zr->contrast;
			break;
		case V4L2_CID_SATURATION:
			ctrl->value = zr->saturation;
			break;
		case V4L2_CID_HUE:
			ctrl->value = zr->hue;
			break;
		}
		mutex_unlock(&zr->resource_lock);

		return 0;
	}
		break;

	case VIDIOC_S_CTRL:
	{
		struct v4l2_control *ctrl = arg;
		struct video_picture pict;

		dprintk(3, KERN_DEBUG "%s: VIDIOC_S_CTRL - id=%d\n",
			ZR_DEVNAME(zr), ctrl->id);

		/* we only support hue/saturation/contrast/brightness */
		if (ctrl->id < V4L2_CID_BRIGHTNESS ||
		    ctrl->id > V4L2_CID_HUE)
			return -EINVAL;

		if (ctrl->value < 0 || ctrl->value > 65535) {
			dprintk(1,
				KERN_ERR
				"%s: VIDIOC_S_CTRL - invalid value %d for id=%d\n",
				ZR_DEVNAME(zr), ctrl->value, ctrl->id);
			return -EINVAL;
		}

		mutex_lock(&zr->resource_lock);
		switch (ctrl->id) {
		case V4L2_CID_BRIGHTNESS:
			zr->brightness = ctrl->value;
			break;
		case V4L2_CID_CONTRAST:
			zr->contrast = ctrl->value;
			break;
		case V4L2_CID_SATURATION:
			zr->saturation = ctrl->value;
			break;
		case V4L2_CID_HUE:
			zr->hue = ctrl->value;
			break;
		}
		pict.brightness = zr->brightness;
		pict.contrast = zr->contrast;
		pict.colour = zr->saturation;
		pict.hue = zr->hue;

		decoder_command(zr, DECODER_SET_PICTURE, &pict);

		mutex_unlock(&zr->resource_lock);

		return 0;
	}
		break;

	case VIDIOC_ENUMSTD:
	{
		struct v4l2_standard *std = arg;

		dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUMSTD - index=%d\n",
			ZR_DEVNAME(zr), std->index);

		if (std->index < 0 || std->index >= (zr->card.norms + 1))
			return -EINVAL;
		else {
			int id = std->index;
			memset(std, 0, sizeof(*std));
			std->index = id;
		}

		if (std->index == zr->card.norms) {
			/* if we have autodetect, ... */
			struct video_decoder_capability caps;
			decoder_command(zr, DECODER_GET_CAPABILITIES,
					&caps);
			if (caps.flags & VIDEO_DECODER_AUTO) {
				std->id = V4L2_STD_ALL;
				strncpy(std->name, "Autodetect", sizeof(std->name)-1);
				return 0;
			} else
				return -EINVAL;
		}
		switch (std->index) {
		case 0:
			std->id = V4L2_STD_PAL;
			strncpy(std->name, "PAL", sizeof(std->name)-1);
			std->frameperiod.numerator = 1;
			std->frameperiod.denominator = 25;
			std->framelines = zr->card.tvn[0]->Ht;
			break;
		case 1:
			std->id = V4L2_STD_NTSC;
			strncpy(std->name, "NTSC", sizeof(std->name)-1);
			std->frameperiod.numerator = 1001;
			std->frameperiod.denominator = 30000;
			std->framelines = zr->card.tvn[1]->Ht;
			break;
		case 2:
			std->id = V4L2_STD_SECAM;
			strncpy(std->name, "SECAM", sizeof(std->name)-1);
			std->frameperiod.numerator = 1;
			std->frameperiod.denominator = 25;
			std->framelines = zr->card.tvn[2]->Ht;
			break;
		}

		return 0;
	}
		break;

	case VIDIOC_G_STD:
	{
		v4l2_std_id *std = arg;
		int norm;

		dprintk(3, KERN_DEBUG "%s: VIDIOC_G_STD\n", ZR_DEVNAME(zr));

		mutex_lock(&zr->resource_lock);
		norm = zr->norm;
		mutex_unlock(&zr->resource_lock);

		switch (norm) {
		case VIDEO_MODE_PAL:
			*std = V4L2_STD_PAL;
			break;
		case VIDEO_MODE_NTSC:
			*std = V4L2_STD_NTSC;
			break;
		case VIDEO_MODE_SECAM:
			*std = V4L2_STD_SECAM;
			break;
		}

		return 0;
	}
		break;

	case VIDIOC_S_STD:
	{
		int norm = -1, res = 0;
		v4l2_std_id *std = arg;

		dprintk(3, KERN_DEBUG "%s: VIDIOC_S_STD - norm=0x%llx\n",
			ZR_DEVNAME(zr), (unsigned long long)*std);

		if ((*std & V4L2_STD_PAL) && !(*std & ~V4L2_STD_PAL))
			norm = VIDEO_MODE_PAL;
		else if ((*std & V4L2_STD_NTSC) && !(*std & ~V4L2_STD_NTSC))
			norm = VIDEO_MODE_NTSC;
		else if ((*std & V4L2_STD_SECAM) && !(*std & ~V4L2_STD_SECAM))
			norm = VIDEO_MODE_SECAM;
		else if (*std == V4L2_STD_ALL)
			norm = VIDEO_MODE_AUTO;
		else {
			dprintk(1,
				KERN_ERR
				"%s: VIDIOC_S_STD - invalid norm 0x%llx\n",
				ZR_DEVNAME(zr), (unsigned long long)*std);
			return -EINVAL;
		}

		mutex_lock(&zr->resource_lock);
		if ((res = zoran_set_norm(zr, norm)))
			goto sstd_unlock_and_return;

		res = wait_grab_pending(zr);
	sstd_unlock_and_return:
		mutex_unlock(&zr->resource_lock);
		return res;
	}
		break;

	case VIDIOC_ENUMINPUT:
	{
		struct v4l2_input *inp = arg;
		int status;

		dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUMINPUT - index=%d\n",
			ZR_DEVNAME(zr), inp->index);

		if (inp->index < 0 || inp->index >= zr->card.inputs)
			return -EINVAL;
		else {
			int id = inp->index;
			memset(inp, 0, sizeof(*inp));
			inp->index = id;
		}

		strncpy(inp->name, zr->card.input[inp->index].name,
			sizeof(inp->name) - 1);
		inp->type = V4L2_INPUT_TYPE_CAMERA;
		inp->std = V4L2_STD_ALL;

		/* Get status of video decoder */
		mutex_lock(&zr->resource_lock);
		decoder_command(zr, DECODER_GET_STATUS, &status);
		mutex_unlock(&zr->resource_lock);

		if (!(status & DECODER_STATUS_GOOD)) {
			inp->status |= V4L2_IN_ST_NO_POWER;
			inp->status |= V4L2_IN_ST_NO_SIGNAL;
		}
		if (!(status & DECODER_STATUS_COLOR))
			inp->status |= V4L2_IN_ST_NO_COLOR;

		return 0;
	}
		break;

	case VIDIOC_G_INPUT:
	{
		int *input = arg;

		dprintk(3, KERN_DEBUG "%s: VIDIOC_G_INPUT\n", ZR_DEVNAME(zr));

		mutex_lock(&zr->resource_lock);
		*input = zr->input;
		mutex_unlock(&zr->resource_lock);

		return 0;
	}
		break;

	case VIDIOC_S_INPUT:
	{
		int *input = arg, res = 0;

		dprintk(3, KERN_DEBUG "%s: VIDIOC_S_INPUT - input=%d\n",
			ZR_DEVNAME(zr), *input);

		mutex_lock(&zr->resource_lock);
		if ((res = zoran_set_input(zr, *input)))
			goto sinput_unlock_and_return;

		/* Make sure the changes come into effect */
		res = wait_grab_pending(zr);
	sinput_unlock_and_return:
		mutex_unlock(&zr->resource_lock);
		return res;
	}
		break;

	case VIDIOC_ENUMOUTPUT:
	{
		struct v4l2_output *outp = arg;

		dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUMOUTPUT - index=%d\n",
			ZR_DEVNAME(zr), outp->index);

		if (outp->index != 0)
			return -EINVAL;

		memset(outp, 0, sizeof(*outp));
		outp->index = 0;
		outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY;
		strncpy(outp->name, "Autodetect", sizeof(outp->name)-1);

		return 0;
	}
		break;

	case VIDIOC_G_OUTPUT:
	{
		int *output = arg;

		dprintk(3, KERN_DEBUG "%s: VIDIOC_G_OUTPUT\n", ZR_DEVNAME(zr));

		*output = 0;

		return 0;
	}
		break;

	case VIDIOC_S_OUTPUT:
	{
		int *output = arg;

		dprintk(3, KERN_DEBUG "%s: VIDIOC_S_OUTPUT - output=%d\n",
			ZR_DEVNAME(zr), *output);

		if (*output != 0)
			return -EINVAL;

		return 0;
	}
		break;

		/* cropping (sub-frame capture) */
	case VIDIOC_CROPCAP:
	{
		struct v4l2_cropcap *cropcap = arg;
		int type = cropcap->type, res = 0;

		dprintk(3, KERN_ERR "%s: VIDIOC_CROPCAP - type=%d\n",
			ZR_DEVNAME(zr), cropcap->type);

		memset(cropcap, 0, sizeof(*cropcap));
		cropcap->type = type;

		mutex_lock(&zr->resource_lock);

		if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
		    (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
		     fh->map_mode == ZORAN_MAP_MODE_RAW)) {
			dprintk(1,
				KERN_ERR
				"%s: VIDIOC_CROPCAP - subcapture only supported for compressed capture\n",
				ZR_DEVNAME(zr));
			res = -EINVAL;
			goto cropcap_unlock_and_return;
		}

		cropcap->bounds.top = cropcap->bounds.left = 0;
		cropcap->bounds.width = BUZ_MAX_WIDTH;
		cropcap->bounds.height = BUZ_MAX_HEIGHT;
		cropcap->defrect.top = cropcap->defrect.left = 0;
		cropcap->defrect.width = BUZ_MIN_WIDTH;
		cropcap->defrect.height = BUZ_MIN_HEIGHT;
	cropcap_unlock_and_return:
		mutex_unlock(&zr->resource_lock);
		return res;
	}
		break;

	case VIDIOC_G_CROP:
	{
		struct v4l2_crop *crop = arg;
		int type = crop->type, res = 0;

		dprintk(3, KERN_ERR "%s: VIDIOC_G_CROP - type=%d\n",
			ZR_DEVNAME(zr), crop->type);

		memset(crop, 0, sizeof(*crop));
		crop->type = type;

		mutex_lock(&zr->resource_lock);

		if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
		    (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
		     fh->map_mode == ZORAN_MAP_MODE_RAW)) {
			dprintk(1,
				KERN_ERR
				"%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n",
				ZR_DEVNAME(zr));
			res = -EINVAL;
			goto gcrop_unlock_and_return;
		}

		crop->c.top = fh->jpg_settings.img_y;
		crop->c.left = fh->jpg_settings.img_x;
		crop->c.width = fh->jpg_settings.img_width;
		crop->c.height = fh->jpg_settings.img_height;

	gcrop_unlock_and_return:
		mutex_unlock(&zr->resource_lock);

		return res;
	}
		break;

	case VIDIOC_S_CROP:
	{
		struct v4l2_crop *crop = arg;
		int res = 0;

		settings = fh->jpg_settings;

		dprintk(3,
			KERN_ERR
			"%s: VIDIOC_S_CROP - type=%d, x=%d,y=%d,w=%d,h=%d\n",
			ZR_DEVNAME(zr), crop->type, crop->c.left, crop->c.top,
			crop->c.width, crop->c.height);

		mutex_lock(&zr->resource_lock);

		if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) {
			dprintk(1,
				KERN_ERR
				"%s: VIDIOC_S_CROP - cannot change settings while active\n",
				ZR_DEVNAME(zr));
			res = -EBUSY;
			goto scrop_unlock_and_return;
		}

		if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
		    (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
		     fh->map_mode == ZORAN_MAP_MODE_RAW)) {
			dprintk(1,
				KERN_ERR
				"%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n",
				ZR_DEVNAME(zr));
			res = -EINVAL;
			goto scrop_unlock_and_return;
		}

		/* move into a form that we understand */
		settings.img_x = crop->c.left;
		settings.img_y = crop->c.top;
		settings.img_width = crop->c.width;
		settings.img_height = crop->c.height;

		/* check validity */
		if ((res = zoran_check_jpg_settings(zr, &settings)))
			goto scrop_unlock_and_return;

		/* accept */
		fh->jpg_settings = settings;

	scrop_unlock_and_return:
		mutex_unlock(&zr->resource_lock);
		return res;
	}
		break;

	case VIDIOC_G_JPEGCOMP:
	{
		struct v4l2_jpegcompression *params = arg;

		dprintk(3, KERN_DEBUG "%s: VIDIOC_G_JPEGCOMP\n",
			ZR_DEVNAME(zr));

		memset(params, 0, sizeof(*params));

		mutex_lock(&zr->resource_lock);

		params->quality = fh->jpg_settings.jpg_comp.quality;
		params->APPn = fh->jpg_settings.jpg_comp.APPn;
		memcpy(params->APP_data,
		       fh->jpg_settings.jpg_comp.APP_data,
		       fh->jpg_settings.jpg_comp.APP_len);
		params->APP_len = fh->jpg_settings.jpg_comp.APP_len;
		memcpy(params->COM_data,
		       fh->jpg_settings.jpg_comp.COM_data,
		       fh->jpg_settings.jpg_comp.COM_len);
		params->COM_len = fh->jpg_settings.jpg_comp.COM_len;
		params->jpeg_markers =
		    fh->jpg_settings.jpg_comp.jpeg_markers;

		mutex_unlock(&zr->resource_lock);

		return 0;
	}
		break;

	case VIDIOC_S_JPEGCOMP:
	{
		struct v4l2_jpegcompression *params = arg;
		int res = 0;

		settings = fh->jpg_settings;

		dprintk(3,
			KERN_DEBUG
			"%s: VIDIOC_S_JPEGCOMP - quality=%d, APPN=%d, APP_len=%d, COM_len=%d\n",
			ZR_DEVNAME(zr), params->quality, params->APPn,
			params->APP_len, params->COM_len);

		settings.jpg_comp = *params;

		mutex_lock(&zr->resource_lock);

		if (fh->v4l_buffers.active != ZORAN_FREE ||
		    fh->jpg_buffers.active != ZORAN_FREE) {
			dprintk(1,
				KERN_WARNING
				"%s: VIDIOC_S_JPEGCOMP called while in playback/capture mode\n",
				ZR_DEVNAME(zr));
			res = -EBUSY;
			goto sjpegc_unlock_and_return;
		}

		if ((res = zoran_check_jpg_settings(zr, &settings)))
			goto sjpegc_unlock_and_return;
		if (!fh->jpg_buffers.allocated)
			fh->jpg_buffers.buffer_size =
			    zoran_v4l2_calc_bufsize(&fh->jpg_settings);
		fh->jpg_settings.jpg_comp = *params = settings.jpg_comp;
	sjpegc_unlock_and_return:
		mutex_unlock(&zr->resource_lock);

		return 0;
	}
		break;

	case VIDIOC_QUERYSTD:	/* why is this useful? */
	{
		v4l2_std_id *std = arg;

		dprintk(3,
			KERN_DEBUG "%s: VIDIOC_QUERY_STD - std=0x%llx\n",
			ZR_DEVNAME(zr), (unsigned long long)*std);

		if (*std == V4L2_STD_ALL || *std == V4L2_STD_NTSC ||
		    *std == V4L2_STD_PAL || (*std == V4L2_STD_SECAM &&
					     zr->card.norms == 3)) {
			return 0;
		}

		return -EINVAL;
	}
		break;

	case VIDIOC_TRY_FMT:
	{
		struct v4l2_format *fmt = arg;
		int res = 0;

		dprintk(3, KERN_DEBUG "%s: VIDIOC_TRY_FMT - type=%d\n",
			ZR_DEVNAME(zr), fmt->type);

		switch (fmt->type) {
		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
			mutex_lock(&zr->resource_lock);

			if (fmt->fmt.win.w.width > BUZ_MAX_WIDTH)
				fmt->fmt.win.w.width = BUZ_MAX_WIDTH;
			if (fmt->fmt.win.w.width < BUZ_MIN_WIDTH)
				fmt->fmt.win.w.width = BUZ_MIN_WIDTH;
			if (fmt->fmt.win.w.height > BUZ_MAX_HEIGHT)
				fmt->fmt.win.w.height = BUZ_MAX_HEIGHT;
			if (fmt->fmt.win.w.height < BUZ_MIN_HEIGHT)
				fmt->fmt.win.w.height = BUZ_MIN_HEIGHT;

			mutex_unlock(&zr->resource_lock);
			break;

		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
		case V4L2_BUF_TYPE_VIDEO_OUTPUT:
			if (fmt->fmt.pix.bytesperline > 0)
				return -EINVAL;

			mutex_lock(&zr->resource_lock);

			if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) {
				settings = fh->jpg_settings;

				/* we actually need to set 'real' parameters now */
				if ((fmt->fmt.pix.height * 2) >
				    BUZ_MAX_HEIGHT)
					settings.TmpDcm = 1;
				else
					settings.TmpDcm = 2;
				settings.decimation = 0;
				if (fmt->fmt.pix.height <=
				    fh->jpg_settings.img_height / 2)
					settings.VerDcm = 2;
				else
					settings.VerDcm = 1;
				if (fmt->fmt.pix.width <=
				    fh->jpg_settings.img_width / 4)
					settings.HorDcm = 4;
				else if (fmt->fmt.pix.width <=
					 fh->jpg_settings.img_width / 2)
					settings.HorDcm = 2;
				else
					settings.HorDcm = 1;
				if (settings.TmpDcm == 1)
					settings.field_per_buff = 2;
				else
					settings.field_per_buff = 1;

				/* check */
				if ((res =
				     zoran_check_jpg_settings(zr,
							      &settings)))
					goto tryfmt_unlock_and_return;

				/* tell the user what we actually did */
				fmt->fmt.pix.width =
				    settings.img_width / settings.HorDcm;
				fmt->fmt.pix.height =
				    settings.img_height * 2 /
				    (settings.TmpDcm * settings.VerDcm);
				if (settings.TmpDcm == 1)
					fmt->fmt.pix.field =
					    (fh->jpg_settings.
					     odd_even ? V4L2_FIELD_SEQ_TB :
					     V4L2_FIELD_SEQ_BT);
				else
					fmt->fmt.pix.field =
					    (fh->jpg_settings.
					     odd_even ? V4L2_FIELD_TOP :
					     V4L2_FIELD_BOTTOM);

				fmt->fmt.pix.sizeimage =
				    zoran_v4l2_calc_bufsize(&settings);
			} else if (fmt->type ==
				   V4L2_BUF_TYPE_VIDEO_CAPTURE) {
				int i;

				for (i = 0; i < NUM_FORMATS; i++)
					if (zoran_formats[i].fourcc ==
					    fmt->fmt.pix.pixelformat)
						break;
				if (i == NUM_FORMATS) {
					res = -EINVAL;
					goto tryfmt_unlock_and_return;
				}

				if (fmt->fmt.pix.width > BUZ_MAX_WIDTH)
					fmt->fmt.pix.width = BUZ_MAX_WIDTH;
				if (fmt->fmt.pix.width < BUZ_MIN_WIDTH)
					fmt->fmt.pix.width = BUZ_MIN_WIDTH;
				if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT)
					fmt->fmt.pix.height =
					    BUZ_MAX_HEIGHT;
				if (fmt->fmt.pix.height < BUZ_MIN_HEIGHT)
					fmt->fmt.pix.height =
					    BUZ_MIN_HEIGHT;
			} else {
				res = -EINVAL;
				goto tryfmt_unlock_and_return;
			}
		tryfmt_unlock_and_return:
			mutex_unlock(&zr->resource_lock);

			return res;
			break;

		default:
			return -EINVAL;
		}

		return 0;
	}
		break;

	default:
		dprintk(1, KERN_DEBUG "%s: UNKNOWN ioctl cmd: 0x%x\n",
			ZR_DEVNAME(zr), cmd);
		return -ENOIOCTLCMD;
		break;

	}
	return 0;
}

Generated by GNU enscript 1.6.4.