Enscript Output

extractedLnx/linux-2.4.37/drivers/usb/w9968cf.c_w9968cf_v4l_ioctl.c

static int 
w9968cf_v4l_ioctl(struct inode* inode, struct file* filp,
                  unsigned int cmd, void* arg)
{
	struct w9968cf_device* cam;
	const char* v4l1_ioctls[] = {
		"?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", 
		"GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF",
		"SFBUF", "KEY", "GFREQ", "SFREQ", "GAUDIO", "SAUDIO",
		"SYNC", "MCAPTURE", "GMBUF", "GUNIT", "GCAPTURE", "SCAPTURE",
		"SPLAYMODE", "SWRITEMODE", "GPLAYINFO", "SMICROCODE", 
		"GVBIFMT", "SVBIFMT" 
	};

	#define V4L1_IOCTL(cmd) \
	        ((_IOC_NR((cmd)) < sizeof(v4l1_ioctls)/sizeof(char*)) ? \
	        v4l1_ioctls[_IOC_NR((cmd))] : "?")

	cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));

	switch (cmd) {

	case VIDIOCGCAP: /* get video capability */
	{
		struct video_capability cap = {
			.type = VID_TYPE_CAPTURE | VID_TYPE_SCALES,
			.channels = 1,
			.audios = 0,
			.minwidth = cam->minwidth,
			.minheight = cam->minheight,
		};
		sprintf(cap.name, "W996[87]CF USB Camera #%d", 
		        cam->v4ldev->minor);
		cap.maxwidth = (cam->upscaling && w9968cf_vppmod_present)
		               ? W9968CF_MAX_WIDTH : cam->maxwidth;
		cap.maxheight = (cam->upscaling && w9968cf_vppmod_present)
		                ? W9968CF_MAX_HEIGHT : cam->maxheight;

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

		DBG(5, "VIDIOCGCAP successfully called.")
		return 0;
	}

	case VIDIOCGCHAN: /* get video channel informations */
	{
		struct video_channel chan;
		if (copy_from_user(&chan, arg, sizeof(chan)))
			return -EFAULT;

		if (chan.channel != 0)
			return -EINVAL;

		strcpy(chan.name, "Camera");
		chan.tuners = 0;
		chan.flags = 0;
		chan.type = VIDEO_TYPE_CAMERA;
		chan.norm = VIDEO_MODE_AUTO;

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

		DBG(5, "VIDIOCGCHAN successfully called.")
		return 0;
	}

	case VIDIOCSCHAN: /* set active channel */
	{
		struct video_channel chan;

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

		if (chan.channel != 0)
			return -EINVAL;

		DBG(5, "VIDIOCSCHAN successfully called.")
		return 0;
	}

	case VIDIOCGPICT: /* get image properties of the picture */
	{
		if (w9968cf_sensor_get_picture(cam))
			return -EIO;

		if (copy_to_user(arg, &cam->picture, sizeof(cam->picture)))
			return -EFAULT;

		DBG(5, "VIDIOCGPICT successfully called.")
		return 0;
	}

	case VIDIOCSPICT: /* change picture settings */
	{
		struct video_picture pict;
		int err = 0;

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

		if ( (cam->force_palette || !w9968cf_vppmod_present) 
		     && pict.palette != cam->picture.palette ) {
			DBG(4, "Palette %s rejected. Only %s is allowed.",
			    symbolic(v4l1_plist, pict.palette),
			    symbolic(v4l1_plist, cam->picture.palette))
			return -EINVAL;
		}

		if (!w9968cf_valid_palette(pict.palette)) {
			DBG(4, "Palette %s not supported. VIDIOCSPICT failed.",
			    symbolic(v4l1_plist, pict.palette))
			return -EINVAL;
		}

		if (!cam->force_palette) {
		   if (cam->decompression == 0) {
		      if (w9968cf_need_decompression(pict.palette)) {
		         DBG(4, "Decompression disabled: palette %s is not "
		                "allowed. VIDIOCSPICT failed.",
		             symbolic(v4l1_plist, pict.palette))
		         return -EINVAL;
		      }
		   } else if (cam->decompression == 1) {
		      if (!w9968cf_need_decompression(pict.palette)) {
		         DBG(4, "Decompression forced: palette %s is not "
		                "allowed. VIDIOCSPICT failed.",
		             symbolic(v4l1_plist, pict.palette))
		         return -EINVAL;
		      }
		   }
		}

		if (pict.depth != w9968cf_valid_depth(pict.palette)) {
			DBG(4, "Requested depth %d bpp is not valid for %s "
			       "palette: ignored and changed to %d bpp.", 
			    pict.depth, symbolic(v4l1_plist, pict.palette),
			    w9968cf_valid_depth(pict.palette))
			pict.depth = w9968cf_valid_depth(pict.palette);
		}

		if (pict.palette != cam->picture.palette) {
			if(*cam->requested_frame
			   || cam->frame_current->queued) {
				err = wait_event_interruptible
				      ( cam->wait_queue,
				        cam->disconnected ||
				        (!*cam->requested_frame &&
				         !cam->frame_current->queued) );
				if (err)
					return err;
				if (cam->disconnected)
					return -ENODEV;
			}

			if (w9968cf_stop_transfer(cam))
				goto ioctl_fail;

			if (w9968cf_set_picture(cam, pict))
				goto ioctl_fail;

			if (w9968cf_start_transfer(cam))
				goto ioctl_fail;

		} else if (w9968cf_sensor_update_picture(cam, pict))
			return -EIO;


		DBG(5, "VIDIOCSPICT successfully called.")
		return 0;
	}

	case VIDIOCSWIN: /* set capture area */
	{
		struct video_window win;
		int err = 0;

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

		DBG(6, "VIDIOCSWIN called: clipcount=%d, flags=%d, "
		       "x=%d, y=%d, %dx%d", win.clipcount, win.flags,
		    win.x, win.y, win.width, win.height)

		if (win.clipcount != 0 || win.flags != 0)
			return -EINVAL;

		if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width,
		                                      (u16*)&win.height))) {
			DBG(4, "Resolution not supported (%dx%d)."
			       "VIDIOCSWIN failed.", win.width, win.height)
			return err;
		}

		if (win.x != cam->window.x ||
		    win.y != cam->window.y ||
		    win.width != cam->window.width ||
		    win.height != cam->window.height) {
			if(*cam->requested_frame
			   || cam->frame_current->queued) {
				err = wait_event_interruptible
				      ( cam->wait_queue,
				        cam->disconnected ||
				        (!*cam->requested_frame &&
				         !cam->frame_current->queued) );
				if (err)
					return err;
				if (cam->disconnected)
					return -ENODEV;
			}

			if (w9968cf_stop_transfer(cam))
				goto ioctl_fail;

			/* This _must_ be called before set_window() */
			if (w9968cf_set_picture(cam, cam->picture))
				goto ioctl_fail;

			if (w9968cf_set_window(cam, win))
				goto ioctl_fail;

			if (w9968cf_start_transfer(cam))
				goto ioctl_fail;
		}

		DBG(5, "VIDIOCSWIN successfully called. ")
		return 0;
	}

	case VIDIOCGWIN: /* get current window properties */
	{
		if (copy_to_user(arg,&cam->window,sizeof(struct video_window)))
			return -EFAULT;

		DBG(5, "VIDIOCGWIN successfully called.")
		return 0;
	}

	case VIDIOCGMBUF: /* request for memory (mapped) buffer */
	{
		struct video_mbuf mbuf;
		u8 i;

		mbuf.size = cam->nbuffers * w9968cf_get_max_bufsize(cam);
		mbuf.frames = cam->nbuffers;
		for (i = 0; i < cam->nbuffers; i++)
			mbuf.offsets[i] = (unsigned long)cam->frame[i].buffer -
			                  (unsigned long)cam->frame[0].buffer;

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

		DBG(5, "VIDIOCGMBUF successfully called.")
		return 0;
	}

	case VIDIOCMCAPTURE: /* start the capture to a frame */
	{
		struct video_mmap mmap;
		struct w9968cf_frame_t* fr;
		int err = 0;

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

		DBG(6, "VIDIOCMCAPTURE called: frame #%d, format=%s, %dx%d",
		    mmap.frame, symbolic(v4l1_plist, mmap.format), 
		    mmap.width, mmap.height)

		if (mmap.frame >= cam->nbuffers) {
			DBG(4, "Invalid frame number (%d). "
			       "VIDIOCMCAPTURE failed.", mmap.frame)
			return -EINVAL;
		}

		if (mmap.format!=cam->picture.palette && 
		    (cam->force_palette || !w9968cf_vppmod_present)) {
			DBG(4, "Palette %s rejected. Only %s is allowed.",
			    symbolic(v4l1_plist, mmap.format),
			    symbolic(v4l1_plist, cam->picture.palette))
			return -EINVAL;
		}

		if (!w9968cf_valid_palette(mmap.format)) {
			DBG(4, "Palette %s not supported. "
			       "VIDIOCMCAPTURE failed.", 
			    symbolic(v4l1_plist, mmap.format))
			return -EINVAL;
		}

		if (!cam->force_palette) {
		   if (cam->decompression == 0) {
		      if (w9968cf_need_decompression(mmap.format)) {
		         DBG(4, "Decompression disabled: palette %s is not "
		                "allowed. VIDIOCSPICT failed.",
		             symbolic(v4l1_plist, mmap.format))
		         return -EINVAL;
		      }
		   } else if (cam->decompression == 1) {
		      if (!w9968cf_need_decompression(mmap.format)) {
		         DBG(4, "Decompression forced: palette %s is not "
		                "allowed. VIDIOCSPICT failed.",
		             symbolic(v4l1_plist, mmap.format))
		         return -EINVAL;
		      }
		   }
		}

		if ((err = w9968cf_adjust_window_size(cam, (u16*)&mmap.width, 
		                                      (u16*)&mmap.height))) {
			DBG(4, "Resolution not supported (%dx%d). "
			       "VIDIOCMCAPTURE failed.",
			    mmap.width, mmap.height)
			return err;
		}

		fr = &cam->frame[mmap.frame];

		if (mmap.width  != cam->window.width ||
		    mmap.height != cam->window.height ||
		    mmap.format != cam->picture.palette) {

			struct video_window win;
			struct video_picture pict;

			if(*cam->requested_frame
			   || cam->frame_current->queued) {
				DBG(6, "VIDIOCMCAPTURE. Change settings for "
				       "frame #%d: %dx%d, format %s. Wait...",
				    mmap.frame, mmap.width, mmap.height,
			            symbolic(v4l1_plist, mmap.format))
				err = wait_event_interruptible
				      ( cam->wait_queue,
				        cam->disconnected ||
				        (!*cam->requested_frame &&
				         !cam->frame_current->queued) );
				if (err)
					return err;
				if (cam->disconnected)
					return -ENODEV;
			}

			memcpy(&win, &cam->window, sizeof(win));
			memcpy(&pict, &cam->picture, sizeof(pict));
			win.width = mmap.width;
			win.height = mmap.height;
			pict.palette = mmap.format;

			if (w9968cf_stop_transfer(cam))
				goto ioctl_fail;

			/* This before set_window */
			if (w9968cf_set_picture(cam, pict)) 
				goto ioctl_fail;

			if (w9968cf_set_window(cam, win))
				goto ioctl_fail;

			if (w9968cf_start_transfer(cam))
				goto ioctl_fail;

		} else 	if (fr->queued) {

			DBG(6, "Wait until frame #%d is free.", mmap.frame)
			
			err = wait_event_interruptible(cam->wait_queue, 
			                               cam->disconnected ||
			                               (!fr->queued));
			if (err)
				return err;
			if (cam->disconnected)
				return -ENODEV;
		}

		w9968cf_push_frame(cam, mmap.frame);
		DBG(5, "VIDIOCMCAPTURE(%d): successfully called.", mmap.frame)
		return 0;
	}

	case VIDIOCSYNC: /* wait until the capture of a frame is finished */
	{
		unsigned int f_num;
		struct w9968cf_frame_t* fr;
		int err = 0;

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

		if (f_num >= cam->nbuffers) {
			DBG(4, "Invalid frame number (%d). "
			       "VIDIOCMCAPTURE failed.", f_num)
			return -EINVAL;
		}

		DBG(6, "VIDIOCSYNC called for frame #%d", f_num)

		fr = &cam->frame[f_num];

		switch (fr->status) {
		case F_UNUSED:
			if (!fr->queued) {
				DBG(4, "VIDIOSYNC: Frame #%d not requested!",
				    f_num)
				return -EFAULT;
			}
		case F_ERROR:
		case F_GRABBING:
			err = wait_event_interruptible(cam->wait_queue, 
			                               (fr->status == F_READY)
			                               || cam->disconnected);
			if (err)
				return err;
			if (cam->disconnected)
				return -ENODEV;
			break;
		case F_READY:
			break;
		}

		if (w9968cf_vppmod_present)
			w9968cf_postprocess_frame(cam, fr);

		fr->status = F_UNUSED;

		DBG(5, "VIDIOCSYNC(%d) successfully called.", f_num)
		return 0;
	}

	case VIDIOCGUNIT:/* report the unit numbers of the associated devices*/
	{
		struct video_unit unit = {
			.video = cam->v4ldev->minor,
			.vbi = VIDEO_NO_UNIT,
			.radio = VIDEO_NO_UNIT,
			.audio = VIDEO_NO_UNIT,
			.teletext = VIDEO_NO_UNIT,
		};

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

		DBG(5, "VIDIOCGUNIT successfully called.")
		return 0;
	}

	case VIDIOCKEY:
		return 0;

	case VIDIOCGFBUF:
	{
		struct video_buffer* buffer = (struct video_buffer*)arg;

		if (clear_user(buffer, sizeof(struct video_buffer)))
			return -EFAULT;

		DBG(5, "VIDIOCGFBUF successfully called.")
		return 0;
	}

	case VIDIOCGTUNER:
	{
		struct video_tuner tuner;
		if (copy_from_user(&tuner, arg, sizeof(tuner)))
			return -EFAULT;

		if (tuner.tuner != 0)
			return -EINVAL;

		strcpy(tuner.name, "no_tuner");
		tuner.rangelow = 0;
		tuner.rangehigh = 0;
		tuner.flags = VIDEO_TUNER_NORM;
		tuner.mode = VIDEO_MODE_AUTO;
		tuner.signal = 0xffff;

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

		DBG(5, "VIDIOCGTUNER successfully called.")
		return 0;
	}

	case VIDIOCSTUNER:
	{
		struct video_tuner tuner;
		if (copy_from_user(&tuner, arg, sizeof(tuner)))
			return -EFAULT;

		if (tuner.tuner != 0)
			return -EINVAL;

		if (tuner.mode != VIDEO_MODE_AUTO)
			return -EINVAL;

		DBG(5, "VIDIOCSTUNER successfully called.")
		return 0;
	}

	case VIDIOCSFBUF:
	case VIDIOCCAPTURE:
	case VIDIOCGFREQ:
	case VIDIOCSFREQ:
	case VIDIOCGAUDIO:
	case VIDIOCSAUDIO:
	case VIDIOCSPLAYMODE:
	case VIDIOCSWRITEMODE:
	case VIDIOCGPLAYINFO:
	case VIDIOCSMICROCODE:
	case VIDIOCGVBIFMT:
	case VIDIOCSVBIFMT:
		DBG(4, "Unsupported V4L1 IOCtl: VIDIOC%s "
		       "(type 0x%01X, "
		       "n. 0x%01X, "
		       "dir. 0x%01X, " 
		       "size 0x%02X).",
		    V4L1_IOCTL(cmd),
		    _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd))

		return -EINVAL;

	default:
		DBG(4, "Invalid V4L1 IOCtl: VIDIOC%s "
		       "type 0x%01X, "
		       "n. 0x%01X, "
		       "dir. 0x%01X, "
		       "size 0x%02X.",
		    V4L1_IOCTL(cmd),
		    _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd))

		return -ENOIOCTLCMD;

	} /* end of switch */

ioctl_fail:
	cam->misconfigured = 1;
	DBG(1, "VIDIOC%s failed because of hardware problems. "
	       "To use the camera, close and open it again.", V4L1_IOCTL(cmd))
	return -EFAULT;
}

Generated by GNU enscript 1.6.4.