Enscript Output

extractedLnx/linux-2.6.23/drivers/media/video/saa7134/saa7134-video.c_video_do_ioctl.c

static int video_do_ioctl(struct inode *inode, struct file *file,
			  unsigned int cmd, void *arg)
{
	struct saa7134_fh *fh = file->private_data;
	struct saa7134_dev *dev = fh->dev;
	unsigned long flags;
	int err;

	if (video_debug > 1)
		v4l_print_ioctl(dev->name,cmd);

	switch (cmd) {
	case VIDIOC_S_CTRL:
	case VIDIOC_S_STD:
	case VIDIOC_S_INPUT:
	case VIDIOC_S_TUNER:
	case VIDIOC_S_FREQUENCY:
		err = v4l2_prio_check(&dev->prio,&fh->prio);
		if (0 != err)
			return err;
	}

	switch (cmd) {
	case VIDIOC_QUERYCAP:
	{
		struct v4l2_capability *cap = arg;
		unsigned int tuner_type = dev->tuner_type;

		memset(cap,0,sizeof(*cap));
		strcpy(cap->driver, "saa7134");
		strlcpy(cap->card, saa7134_boards[dev->board].name,
			sizeof(cap->card));
		sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
		cap->version = SAA7134_VERSION_CODE;
		cap->capabilities =
			V4L2_CAP_VIDEO_CAPTURE |
			V4L2_CAP_VBI_CAPTURE |
			V4L2_CAP_READWRITE |
			V4L2_CAP_STREAMING |
			V4L2_CAP_TUNER;
		if (saa7134_no_overlay <= 0) {
			cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
		}

		if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET))
			cap->capabilities &= ~V4L2_CAP_TUNER;

		return 0;
	}

	/* --- tv standards ------------------------------------------ */
	case VIDIOC_ENUMSTD:
	{
		struct v4l2_standard *e = arg;
		unsigned int i;

		i = e->index;
		if (i >= TVNORMS)
			return -EINVAL;
		err = v4l2_video_std_construct(e, tvnorms[e->index].id,
					       tvnorms[e->index].name);
		e->index = i;
		if (err < 0)
			return err;
		return 0;
	}
	case VIDIOC_G_STD:
	{
		v4l2_std_id *id = arg;

		*id = dev->tvnorm->id;
		return 0;
	}
	case VIDIOC_S_STD:
	{
		v4l2_std_id *id = arg;
		unsigned int i;
		v4l2_std_id fixup;

		for (i = 0; i < TVNORMS; i++)
			if (*id == tvnorms[i].id)
				break;
		if (i == TVNORMS)
			for (i = 0; i < TVNORMS; i++)
				if (*id & tvnorms[i].id)
					break;
		if (i == TVNORMS)
			return -EINVAL;
		if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) {
			if (secam[0] == 'L' || secam[0] == 'l') {
				if (secam[1] == 'C' || secam[1] == 'c')
					fixup = V4L2_STD_SECAM_LC;
				else
					fixup = V4L2_STD_SECAM_L;
			} else {
				if (secam[0] == 'D' || secam[0] == 'd')
					fixup = V4L2_STD_SECAM_DK;
				else
					fixup = V4L2_STD_SECAM;
			}
			for (i = 0; i < TVNORMS; i++)
				if (fixup == tvnorms[i].id)
					break;
		}
		mutex_lock(&dev->lock);
		if (res_check(fh, RESOURCE_OVERLAY)) {
			spin_lock_irqsave(&dev->slock,flags);
			stop_preview(dev,fh);
			set_tvnorm(dev,&tvnorms[i]);
			start_preview(dev,fh);
			spin_unlock_irqrestore(&dev->slock,flags);
		} else
			set_tvnorm(dev,&tvnorms[i]);
		saa7134_tvaudio_do_scan(dev);
		mutex_unlock(&dev->lock);
		return 0;
	}

	case VIDIOC_CROPCAP:
	{
		struct v4l2_cropcap *cap = arg;

		if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
		    cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
			return -EINVAL;
		cap->bounds  = dev->crop_bounds;
		cap->defrect = dev->crop_defrect;
		cap->pixelaspect.numerator   = 1;
		cap->pixelaspect.denominator = 1;
		if (dev->tvnorm->id & V4L2_STD_525_60) {
			cap->pixelaspect.numerator   = 11;
			cap->pixelaspect.denominator = 10;
		}
		if (dev->tvnorm->id & V4L2_STD_625_50) {
			cap->pixelaspect.numerator   = 54;
			cap->pixelaspect.denominator = 59;
		}
		return 0;
	}

	case VIDIOC_G_CROP:
	{
		struct v4l2_crop * crop = arg;

		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
		    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
			return -EINVAL;
		crop->c = dev->crop_current;
		return 0;
	}
	case VIDIOC_S_CROP:
	{
		struct v4l2_crop *crop = arg;
		struct v4l2_rect *b = &dev->crop_bounds;

		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
		    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
			return -EINVAL;
		if (crop->c.height < 0)
			return -EINVAL;
		if (crop->c.width < 0)
			return -EINVAL;

		if (res_locked(fh->dev,RESOURCE_OVERLAY))
			return -EBUSY;
		if (res_locked(fh->dev,RESOURCE_VIDEO))
			return -EBUSY;

		if (crop->c.top < b->top)
			crop->c.top = b->top;
		if (crop->c.top > b->top + b->height)
			crop->c.top = b->top + b->height;
		if (crop->c.height > b->top - crop->c.top + b->height)
			crop->c.height = b->top - crop->c.top + b->height;

		if (crop->c.left < b->left)
			crop->c.left = b->left;
		if (crop->c.left > b->left + b->width)
			crop->c.left = b->left + b->width;
		if (crop->c.width > b->left - crop->c.left + b->width)
			crop->c.width = b->left - crop->c.left + b->width;

		dev->crop_current = crop->c;
		return 0;
	}

	/* --- tuner ioctls ------------------------------------------ */
	case VIDIOC_G_TUNER:
	{
		struct v4l2_tuner *t = arg;
		int n;

		if (0 != t->index)
			return -EINVAL;
		memset(t,0,sizeof(*t));
		for (n = 0; n < SAA7134_INPUT_MAX; n++)
			if (card_in(dev,n).tv)
				break;
		if (NULL != card_in(dev,n).name) {
			strcpy(t->name, "Television");
			t->type = V4L2_TUNER_ANALOG_TV;
			t->capability = V4L2_TUNER_CAP_NORM |
				V4L2_TUNER_CAP_STEREO |
				V4L2_TUNER_CAP_LANG1 |
				V4L2_TUNER_CAP_LANG2;
			t->rangehigh = 0xffffffffUL;
			t->rxsubchans = saa7134_tvaudio_getstereo(dev);
			t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans);
		}
		if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03))
			t->signal = 0xffff;
		return 0;
	}
	case VIDIOC_S_TUNER:
	{
		struct v4l2_tuner *t = arg;
		int rx,mode;

		mode = dev->thread.mode;
		if (UNSET == mode) {
			rx   = saa7134_tvaudio_getstereo(dev);
			mode = saa7134_tvaudio_rx2mode(t->rxsubchans);
		}
		if (mode != t->audmode) {
			dev->thread.mode = t->audmode;
		}
		return 0;
	}
	case VIDIOC_G_FREQUENCY:
	{
		struct v4l2_frequency *f = arg;

		memset(f,0,sizeof(*f));
		f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
		f->frequency = dev->ctl_freq;
		return 0;
	}
	case VIDIOC_S_FREQUENCY:
	{
		struct v4l2_frequency *f = arg;

		if (0 != f->tuner)
			return -EINVAL;
		if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type)
			return -EINVAL;
		if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
			return -EINVAL;
		mutex_lock(&dev->lock);
		dev->ctl_freq = f->frequency;

		saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,f);

		saa7134_tvaudio_do_scan(dev);
		mutex_unlock(&dev->lock);
		return 0;
	}

	/* --- control ioctls ---------------------------------------- */
	case VIDIOC_ENUMINPUT:
	case VIDIOC_G_INPUT:
	case VIDIOC_S_INPUT:
	case VIDIOC_QUERYCTRL:
	case VIDIOC_G_CTRL:
	case VIDIOC_S_CTRL:
		return saa7134_common_ioctl(dev, cmd, arg);

	case VIDIOC_G_AUDIO:
	{
		struct v4l2_audio *a = arg;

		memset(a,0,sizeof(*a));
		strcpy(a->name,"audio");
		return 0;
	}
	case VIDIOC_S_AUDIO:
		return 0;
	case VIDIOC_G_PARM:
	{
		struct v4l2_captureparm *parm = arg;
		memset(parm,0,sizeof(*parm));
		return 0;
	}

	case VIDIOC_G_PRIORITY:
	{
		enum v4l2_priority *p = arg;

		*p = v4l2_prio_max(&dev->prio);
		return 0;
	}
	case VIDIOC_S_PRIORITY:
	{
		enum v4l2_priority *prio = arg;

		return v4l2_prio_change(&dev->prio, &fh->prio, *prio);
	}

	/* --- preview ioctls ---------------------------------------- */
	case VIDIOC_ENUM_FMT:
	{
		struct v4l2_fmtdesc *f = arg;
		enum v4l2_buf_type type;
		unsigned int index;

		index = f->index;
		type  = f->type;
		switch (type) {
		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
			if (saa7134_no_overlay > 0) {
				printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
				return -EINVAL;
			}
			if (index >= FORMATS)
				return -EINVAL;
			if (f->type == V4L2_BUF_TYPE_VIDEO_OVERLAY &&
			    formats[index].planar)
				return -EINVAL;
			memset(f,0,sizeof(*f));
			f->index = index;
			f->type  = type;
			strlcpy(f->description,formats[index].name,sizeof(f->description));
			f->pixelformat = formats[index].fourcc;
			break;
		case V4L2_BUF_TYPE_VBI_CAPTURE:
			if (0 != index)
				return -EINVAL;
			memset(f,0,sizeof(*f));
			f->index = index;
			f->type  = type;
			f->pixelformat = V4L2_PIX_FMT_GREY;
			strcpy(f->description,"vbi data");
			break;
		default:
			return -EINVAL;
		}
		return 0;
	}
	case VIDIOC_G_FBUF:
	{
		struct v4l2_framebuffer *fb = arg;

		*fb = dev->ovbuf;
		fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
		return 0;
	}
	case VIDIOC_S_FBUF:
	{
		struct v4l2_framebuffer *fb = arg;
		struct saa7134_format *fmt;

		if(!capable(CAP_SYS_ADMIN) &&
		   !capable(CAP_SYS_RAWIO))
			return -EPERM;

		/* check args */
		fmt = format_by_fourcc(fb->fmt.pixelformat);
		if (NULL == fmt)
			return -EINVAL;

		/* ok, accept it */
		dev->ovbuf = *fb;
		dev->ovfmt = fmt;
		if (0 == dev->ovbuf.fmt.bytesperline)
			dev->ovbuf.fmt.bytesperline =
				dev->ovbuf.fmt.width*fmt->depth/8;
		return 0;
	}
	case VIDIOC_OVERLAY:
	{
		int *on = arg;

		if (*on) {
			if (saa7134_no_overlay > 0) {
				printk ("no_overlay\n");
				return -EINVAL;
			}

			if (!res_get(dev,fh,RESOURCE_OVERLAY))
				return -EBUSY;
			spin_lock_irqsave(&dev->slock,flags);
			start_preview(dev,fh);
			spin_unlock_irqrestore(&dev->slock,flags);
		}
		if (!*on) {
			if (!res_check(fh, RESOURCE_OVERLAY))
				return -EINVAL;
			spin_lock_irqsave(&dev->slock,flags);
			stop_preview(dev,fh);
			spin_unlock_irqrestore(&dev->slock,flags);
			res_free(dev,fh,RESOURCE_OVERLAY);
		}
		return 0;
	}

	/* --- capture ioctls ---------------------------------------- */
	case VIDIOC_G_FMT:
	{
		struct v4l2_format *f = arg;
		return saa7134_g_fmt(dev,fh,f);
	}
	case VIDIOC_S_FMT:
	{
		struct v4l2_format *f = arg;
		return saa7134_s_fmt(dev,fh,f);
	}
	case VIDIOC_TRY_FMT:
	{
		struct v4l2_format *f = arg;
		return saa7134_try_fmt(dev,fh,f);
	}
#ifdef CONFIG_VIDEO_V4L1_COMPAT
	case VIDIOCGMBUF:
	{
		struct video_mbuf *mbuf = arg;
		struct videobuf_queue *q;
		struct v4l2_requestbuffers req;
		unsigned int i;

		q = saa7134_queue(fh);
		memset(&req,0,sizeof(req));
		req.type   = q->type;
		req.count  = gbuffers;
		req.memory = V4L2_MEMORY_MMAP;
		err = videobuf_reqbufs(q,&req);
		if (err < 0)
			return err;
		memset(mbuf,0,sizeof(*mbuf));
		mbuf->frames = req.count;
		mbuf->size   = 0;
		for (i = 0; i < mbuf->frames; i++) {
			mbuf->offsets[i]  = q->bufs[i]->boff;
			mbuf->size       += q->bufs[i]->bsize;
		}
		return 0;
	}
#endif
	case VIDIOC_REQBUFS:
		return videobuf_reqbufs(saa7134_queue(fh),arg);

	case VIDIOC_QUERYBUF:
		return videobuf_querybuf(saa7134_queue(fh),arg);

	case VIDIOC_QBUF:
		return videobuf_qbuf(saa7134_queue(fh),arg);

	case VIDIOC_DQBUF:
		return videobuf_dqbuf(saa7134_queue(fh),arg,
				      file->f_flags & O_NONBLOCK);

	case VIDIOC_STREAMON:
	{
		int res = saa7134_resource(fh);

		if (!res_get(dev,fh,res))
			return -EBUSY;
		return videobuf_streamon(saa7134_queue(fh));
	}
	case VIDIOC_STREAMOFF:
	{
		int res = saa7134_resource(fh);

		err = videobuf_streamoff(saa7134_queue(fh));
		if (err < 0)
			return err;
		res_free(dev,fh,res);
		return 0;
	}

	default:
		return v4l_compat_translate_ioctl(inode,file,cmd,arg,
						  video_do_ioctl);
	}
	return 0;
}

Generated by GNU enscript 1.6.4.