Enscript Output

extractedLnx/linux-2.5.5/drivers/usb/ov511.c_ov511_ioctl_internal.c

static int 
ov511_ioctl_internal(struct video_device *vdev, unsigned int cmd, void *arg)
{
	struct usb_ov511 *ov511 = (struct usb_ov511 *)vdev;

	PDEBUG(5, "IOCtl: 0x%X", cmd);

	if (!ov511->dev)
		return -EIO;	

	switch (cmd) {
	case VIDIOCGCAP:
	{
		struct video_capability b;

		PDEBUG(4, "VIDIOCGCAP");

		memset(&b, 0, sizeof(b));
		sprintf(b.name, "%s USB Camera",
			ov511->bridge == BRG_OV511 ? "OV511" :
			ov511->bridge == BRG_OV511PLUS ? "OV511+" :
			ov511->bridge == BRG_OV518 ? "OV518" :
			ov511->bridge == BRG_OV518PLUS ? "OV518+" :
			"unknown");
		b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
		if (ov511->has_tuner)
			b.type |= VID_TYPE_TUNER;
		b.channels = ov511->num_inputs;
		b.audios = ov511->has_audio_proc ? 1:0;
		b.maxwidth = ov511->maxwidth;
		b.maxheight = ov511->maxheight;
		b.minwidth = ov511->minwidth;
		b.minheight = ov511->minheight;

		if (copy_to_user(arg, &b, sizeof(b)))
			return -EFAULT;
				
		return 0;
	}
	case VIDIOCGCHAN:
	{
		struct video_channel v;

		PDEBUG(4, "VIDIOCGCHAN");

		if (copy_from_user(&v, arg, sizeof(v)))
			return -EFAULT;

		if ((unsigned)(v.channel) >= ov511->num_inputs) {
			err("Invalid channel (%d)", v.channel);
			return -EINVAL;
		}

		v.norm = ov511->norm;
		v.type = (ov511->has_tuner) ? VIDEO_TYPE_TV : VIDEO_TYPE_CAMERA;
		v.flags = (ov511->has_tuner) ? VIDEO_VC_TUNER : 0;
		v.flags |= (ov511->has_audio_proc) ? VIDEO_VC_AUDIO : 0;
//		v.flags |= (ov511->has_decoder) ? VIDEO_VC_NORM : 0;
		v.tuners = (ov511->has_tuner) ? 1:0;
		decoder_get_input_name(ov511, v.channel, v.name);

		if (copy_to_user(arg, &v, sizeof(v)))
			return -EFAULT;
				
		return 0;
	}
	case VIDIOCSCHAN:
	{
		struct video_channel v;
		int err;

		PDEBUG(4, "VIDIOCSCHAN");

		if (copy_from_user(&v, arg, sizeof(v)))
			return -EFAULT;

		/* Make sure it's not a camera */
		if (!ov511->has_decoder) {
			if (v.channel == 0)
				return 0;
			else
				return -EINVAL;
		}

		if (v.norm != VIDEO_MODE_PAL &&
		    v.norm != VIDEO_MODE_NTSC &&
		    v.norm != VIDEO_MODE_SECAM &&
		    v.norm != VIDEO_MODE_AUTO) {
			err("Invalid norm (%d)", v.norm);
			return -EINVAL;
		}

		if ((unsigned)(v.channel) >= ov511->num_inputs) {
			err("Invalid channel (%d)", v.channel);
			return -EINVAL;
		}

		err = decoder_set_input(ov511, v.channel);
		if (err)
			return err;

		err = decoder_set_norm(ov511, v.norm);
		if (err)
			return err;

		return 0;
	}
	case VIDIOCGPICT:
	{
		struct video_picture p;

		PDEBUG(4, "VIDIOCGPICT");

		memset(&p, 0, sizeof(p));

		if (sensor_get_picture(ov511, &p))
			return -EIO;

		if (copy_to_user(arg, &p, sizeof(p)))
			return -EFAULT;

		return 0;
	}
	case VIDIOCSPICT:
	{
		struct video_picture p;
		int i;

		PDEBUG(4, "VIDIOCSPICT");

		if (copy_from_user(&p, arg, sizeof(p)))
			return -EFAULT;

		if (!ov511_get_depth(p.palette))
			return -EINVAL;

		if (sensor_set_picture(ov511, &p))
			return -EIO;

		if (force_palette && p.palette != force_palette) {
			info("Palette rejected (%d)", p.palette);
			return -EINVAL;
		}

		// FIXME: Format should be independent of frames
		if (p.palette != ov511->frame[0].format) {
			PDEBUG(4, "Detected format change");

			/* If we're collecting previous frame wait
			   before changing modes */
			interruptible_sleep_on(&ov511->wq);
			if (signal_pending(current)) return -EINTR;

			mode_init_regs(ov511, ov511->frame[0].width,
				ov511->frame[0].height,	p.palette,
				ov511->sub_flag);
		}

		PDEBUG(4, "Setting depth=%d, palette=%d", p.depth, p.palette);
		for (i = 0; i < OV511_NUMFRAMES; i++) {
			ov511->frame[i].depth = p.depth;
			ov511->frame[i].format = p.palette;
		}

		return 0;
	}
	case VIDIOCGCAPTURE:
	{
		int vf;

		PDEBUG(4, "VIDIOCGCAPTURE");

		if (copy_from_user(&vf, arg, sizeof(vf)))
			return -EFAULT;
		ov511->sub_flag = vf;
		return 0;
	}
	case VIDIOCSCAPTURE:
	{
		struct video_capture vc;

		PDEBUG(4, "VIDIOCSCAPTURE");

		if (copy_from_user(&vc, arg, sizeof(vc)))
			return -EFAULT;
		if (vc.flags)
			return -EINVAL;
		if (vc.decimation)
			return -EINVAL;

		vc.x &= ~3L;
		vc.y &= ~1L;
		vc.y &= ~31L;

		if (vc.width == 0)
			vc.width = 32;

		vc.height /= 16;
		vc.height *= 16;
		if (vc.height == 0)
			vc.height = 16;

		ov511->subx = vc.x;
		ov511->suby = vc.y;
		ov511->subw = vc.width;
		ov511->subh = vc.height;

		return 0;
	}
	case VIDIOCSWIN:
	{
		struct video_window vw;
		int i, result;

		if (copy_from_user(&vw, arg, sizeof(vw)))
			return -EFAULT;

		PDEBUG(4, "VIDIOCSWIN: width=%d, height=%d",
			vw.width, vw.height);

#if 0
		if (vw.flags)
			return -EINVAL;
		if (vw.clipcount)
			return -EINVAL;
		if (vw.height != ov511->maxheight)
			return -EINVAL;
		if (vw.width != ov511->maxwidth)
			return -EINVAL;
#endif

		/* If we're collecting previous frame wait
		   before changing modes */
		interruptible_sleep_on(&ov511->wq);
		if (signal_pending(current)) return -EINTR;

		result = mode_init_regs(ov511, vw.width, vw.height,
			ov511->frame[0].format, ov511->sub_flag);
		if (result < 0)
			return result;

		for (i = 0; i < OV511_NUMFRAMES; i++) {
			ov511->frame[i].width = vw.width;
			ov511->frame[i].height = vw.height;
		}

		return 0;
	}
	case VIDIOCGWIN:
	{
		struct video_window vw;

		memset(&vw, 0, sizeof(vw));
		vw.x = 0;		/* FIXME */
		vw.y = 0;
		vw.width = ov511->frame[0].width;
		vw.height = ov511->frame[0].height;
		vw.flags = 30;

		PDEBUG(4, "VIDIOCGWIN: %dx%d", vw.width, vw.height);

		if (copy_to_user(arg, &vw, sizeof(vw)))
			return -EFAULT;

		return 0;
	}
	case VIDIOCGMBUF:
	{
		struct video_mbuf vm;
		int i;

		PDEBUG(4, "VIDIOCGMBUF");

		memset(&vm, 0, sizeof(vm));
		vm.size = OV511_NUMFRAMES
			* MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight);
		vm.frames = OV511_NUMFRAMES;

		vm.offsets[0] = 0;
		for (i = 1; i < OV511_NUMFRAMES; i++) {
			vm.offsets[i] = vm.offsets[i-1]
			   + MAX_DATA_SIZE(ov511->maxwidth, ov511->maxheight);
		}

		if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
			return -EFAULT;

		return 0;
	}
	case VIDIOCMCAPTURE:
	{
		struct video_mmap vm;
		int ret, depth;

		if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
			return -EFAULT;

		PDEBUG(4, "CMCAPTURE");
		PDEBUG(4, "frame: %d, size: %dx%d, format: %d",
			vm.frame, vm.width, vm.height, vm.format);

		depth = ov511_get_depth(vm.format);
		if (!depth) {
			err("VIDIOCMCAPTURE: invalid format (%d)", vm.format);
			return -EINVAL;
		}

		if ((unsigned)vm.frame >= OV511_NUMFRAMES) {
			err("VIDIOCMCAPTURE: invalid frame (%d)", vm.frame);
			return -EINVAL;
		}

		if (vm.width > ov511->maxwidth 
		    || vm.height > ov511->maxheight) {
			err("VIDIOCMCAPTURE: requested dimensions too big");
			return -EINVAL;
		}

		if (ov511->frame[vm.frame].grabstate == FRAME_GRABBING) {
			PDEBUG(4, "VIDIOCMCAPTURE: already grabbing");
			return -EBUSY;
		}

		if (force_palette && vm.format != force_palette) {
			info("palette rejected (%d)", vm.format);
			return -EINVAL;
		}

		if ((ov511->frame[vm.frame].width != vm.width) ||
		    (ov511->frame[vm.frame].height != vm.height) ||
		    (ov511->frame[vm.frame].format != vm.format) ||
		    (ov511->frame[vm.frame].sub_flag != ov511->sub_flag) ||
		    (ov511->frame[vm.frame].depth != depth)) {
			PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters");

			/* If we're collecting previous frame wait
			   before changing modes */
			interruptible_sleep_on(&ov511->wq);
			if (signal_pending(current)) return -EINTR;
			ret = mode_init_regs(ov511, vm.width, vm.height,
				vm.format, ov511->sub_flag);
#if 0
			if (ret < 0) {
				PDEBUG(1, "Got error while initializing regs ");
				return ret;
			}
#endif
			ov511->frame[vm.frame].width = vm.width;
			ov511->frame[vm.frame].height = vm.height;
			ov511->frame[vm.frame].format = vm.format;
			ov511->frame[vm.frame].sub_flag = ov511->sub_flag;
			ov511->frame[vm.frame].depth = depth;
		}

		/* Mark it as ready */
		ov511->frame[vm.frame].grabstate = FRAME_READY;

		PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", vm.frame);

		return ov511_new_frame(ov511, vm.frame);
	}
	case VIDIOCSYNC:
	{
		int fnum, rc;
		struct ov511_frame *frame;

		if (copy_from_user((void *)&fnum, arg, sizeof(int)))
			return -EFAULT;

		if ((unsigned)fnum >= OV511_NUMFRAMES) {
			err("VIDIOCSYNC: invalid frame (%d)", fnum);
			return -EINVAL;
		}

		frame = &ov511->frame[fnum];

		PDEBUG(4, "syncing to frame %d, grabstate = %d", fnum,
		       frame->grabstate);

		switch (frame->grabstate) {
		case FRAME_UNUSED:
			return -EINVAL;
		case FRAME_READY:
		case FRAME_GRABBING:
		case FRAME_ERROR:
redo:
			if (!ov511->dev)
				return -EIO;

			rc = wait_event_interruptible(frame->wq,
			    (frame->grabstate == FRAME_DONE)
			    || (frame->grabstate == FRAME_ERROR));

			if (rc)
				return rc;

			if (frame->grabstate == FRAME_ERROR) {
				int ret;

				if ((ret = ov511_new_frame(ov511, fnum)) < 0)
					return ret;
				goto redo;
			}
			/* Fall through */			
		case FRAME_DONE:
			if (ov511->snap_enabled && !frame->snapshot) {
				int ret;
				if ((ret = ov511_new_frame(ov511, fnum)) < 0)
					return ret;
				goto redo;
			}

			frame->grabstate = FRAME_UNUSED;

			/* Reset the hardware snapshot button */
			/* FIXME - Is this the best place for this? */
			if ((ov511->snap_enabled) && (frame->snapshot)) {
				frame->snapshot = 0;
				ov51x_clear_snapshot(ov511);
			}

			/* Decompression, format conversion, etc... */
			ov511_postprocess(ov511, frame);

			break;
		} /* end switch */

		return 0;
	}
	case VIDIOCGFBUF:
	{
		struct video_buffer vb;

		PDEBUG(4, "VIDIOCSCHAN");

		memset(&vb, 0, sizeof(vb));
		vb.base = NULL;	/* frame buffer not supported, not used */

		if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
			return -EFAULT;

		return 0;
	}
	case VIDIOCGUNIT:
	{
		struct video_unit vu;

		PDEBUG(4, "VIDIOCGUNIT");

		memset(&vu, 0, sizeof(vu));

		vu.video = ov511->vdev.minor;	/* Video minor */
		vu.vbi = VIDEO_NO_UNIT;		/* VBI minor */
		vu.radio = VIDEO_NO_UNIT;	/* Radio minor */
		vu.audio = VIDEO_NO_UNIT;	/* Audio minor */
		vu.teletext = VIDEO_NO_UNIT;	/* Teletext minor */

		if (copy_to_user((void *)arg, (void *)&vu, sizeof(vu)))
			return -EFAULT;

		return 0;
	}
	case VIDIOCGTUNER:
	{
		struct video_tuner v;

		PDEBUG(4, "VIDIOCGTUNER");

		if (copy_from_user(&v, arg, sizeof(v)))
			return -EFAULT;

		if (!ov511->has_tuner || v.tuner)	// Only tuner 0
			return -EINVAL;

		strcpy(v.name, "Television");

		// FIXME: Need a way to get the real values
		v.rangelow = 0;
		v.rangehigh = ~0;

		v.flags = VIDEO_TUNER_PAL | VIDEO_TUNER_NTSC |
		    VIDEO_TUNER_SECAM;
		v.mode = 0; 		/* FIXME:  Not sure what this is yet */
		v.signal = 0xFFFF;	/* unknown */

		call_i2c_clients(ov511, cmd, &v);

		if (copy_to_user(arg, &v, sizeof(v)))
			return -EFAULT;

		return 0;
	}
	case VIDIOCSTUNER:
	{
		struct video_tuner v;
		int err;

		PDEBUG(4, "VIDIOCSTUNER");

		if (copy_from_user(&v, arg, sizeof(v)))
			return -EFAULT;

		/* Only no or one tuner for now */
		if (!ov511->has_tuner || v.tuner)
			return -EINVAL;

		/* and it only has certain valid modes */
		if (v.mode != VIDEO_MODE_PAL &&
		    v.mode != VIDEO_MODE_NTSC &&
		    v.mode != VIDEO_MODE_SECAM) return -EOPNOTSUPP;

		/* Is this right/necessary? */
		err = decoder_set_norm(ov511, v.mode);
		if (err)
			return err;

		call_i2c_clients(ov511, cmd, &v);

		return 0;
	}
	case VIDIOCGFREQ:
	{
		unsigned long v = ov511->freq;

		PDEBUG(4, "VIDIOCGFREQ");

		if (!ov511->has_tuner)
			return -EINVAL;
#if 0
		/* FIXME: this is necessary for testing */
		v = 46*16;
#endif
		if (copy_to_user(arg, &v, sizeof(v)))
			return -EFAULT;

		return 0;
	}
	case VIDIOCSFREQ:
	{
		unsigned long v;

		if (!ov511->has_tuner)
			return -EINVAL;

		if (copy_from_user(&v, arg, sizeof(v)))
			return -EFAULT;

		PDEBUG(4, "VIDIOCSFREQ: %lx", v);

		ov511->freq = v;
		call_i2c_clients(ov511, cmd, &v);

		return 0;
	}
	case VIDIOCGAUDIO:
	case VIDIOCSAUDIO:
	{
		/* FIXME: Implement this... */
		return 0;
	}
	default:
		PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd);
		return -ENOIOCTLCMD;
	} /* end switch */

	return 0;
}

Generated by GNU enscript 1.6.4.