Commit afa38521 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab
Browse files

[media] pwc: convert to video_ioctl2



Tested with a Logitech QuickCam Pro 4000.

Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent b577f962
Loading
Loading
Loading
Loading
+2 −20
Original line number Diff line number Diff line
@@ -151,8 +151,6 @@ static int pwc_video_close(struct file *file);
static ssize_t pwc_video_read(struct file *file, char __user *buf,
			  size_t count, loff_t *ppos);
static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
static long  pwc_video_ioctl(struct file *file,
			    unsigned int ioctlnr, unsigned long arg);
static int  pwc_video_mmap(struct file *file, struct vm_area_struct *vma);

static const struct v4l2_file_operations pwc_fops = {
@@ -162,7 +160,7 @@ static const struct v4l2_file_operations pwc_fops = {
	.read =		pwc_video_read,
	.poll =		pwc_video_poll,
	.mmap =		pwc_video_mmap,
	.unlocked_ioctl = pwc_video_ioctl,
	.unlocked_ioctl = video_ioctl2,
};
static struct video_device pwc_template = {
	.name =		"Philips Webcam",	/* Filled in later */
@@ -1378,23 +1376,6 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
	return 0;
}

static long pwc_video_ioctl(struct file *file,
			   unsigned int cmd, unsigned long arg)
{
	struct video_device *vdev = file->private_data;
	struct pwc_device *pdev;
	long r = -ENODEV;

	if (!vdev)
		goto out;
	pdev = video_get_drvdata(vdev);

	if (!pdev->unplugged)
		r = video_usercopy(file, cmd, arg, pwc_video_do_ioctl);
out:
	return r;
}

static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
{
	struct video_device *vdev = file->private_data;
@@ -1744,6 +1725,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
	memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
	pdev->vdev->parent = &intf->dev;
	pdev->vdev->lock = &pdev->modlock;
	pdev->vdev->ioctl_ops = &pwc_ioctl_ops;
	strcpy(pdev->vdev->name, name);
	video_set_drvdata(pdev->vdev, pdev);

+491 −543
Original line number Diff line number Diff line
@@ -341,34 +341,11 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)

}

long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
{
	struct video_device *vdev = video_devdata(file);
	struct pwc_device *pdev;
	DECLARE_WAITQUEUE(wait, current);

	if (vdev == NULL)
		return -EFAULT;
	pdev = video_get_drvdata(vdev);
	if (pdev == NULL)
		return -EFAULT;

#ifdef CONFIG_USB_PWC_DEBUG
	if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace) {
		v4l_printk_ioctl(cmd);
		printk("\n");
	}
#endif

	struct pwc_device *pdev = video_drvdata(file);

	switch (cmd) {
		/* V4L2 Layer */
		case VIDIOC_QUERYCAP:
		{
		    struct v4l2_capability *cap = arg;

		    PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCAP) This application "\
				       "try to use the v4l2 layer\n");
	strcpy(cap->driver, PWC_NAME);
	strlcpy(cap->card, vdev->name, sizeof(cap->card));
	usb_make_path(pdev->udev, cap->bus_info, sizeof(cap->bus_info));
@@ -380,43 +357,30 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
	return 0;
}

		case VIDIOC_ENUMINPUT:
static int pwc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
{
		    struct v4l2_input *i = arg;

	if (i->index)	/* Only one INPUT is supported */
		return -EINVAL;

		    memset(i, 0, sizeof(struct v4l2_input));
	strcpy(i->name, "usb");
	return 0;
}

		case VIDIOC_G_INPUT:
static int pwc_g_input(struct file *file, void *fh, unsigned int *i)
{
		    int *i = arg;
		    *i = 0;	/* Only one INPUT is supported */
	*i = 0;
	return 0;
}
		case VIDIOC_S_INPUT:
		{
			int *i = arg;

			if ( *i ) {	/* Only one INPUT is supported */
				PWC_DEBUG_IOCTL("Only one input source is"\
					" supported with this webcam.\n");
				return -EINVAL;
			}
			return 0;
static int pwc_s_input(struct file *file, void *fh, unsigned int i)
{
	return i ? -EINVAL : 0;
}

		/* TODO: */
		case VIDIOC_QUERYCTRL:
static int pwc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c)
{
			struct v4l2_queryctrl *c = arg;
	int i;

			PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) query id=%d\n", c->id);
	for (i = 0; i < sizeof(pwc_controls) / sizeof(struct v4l2_queryctrl); i++) {
		if (pwc_controls[i].id == c->id) {
			PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
@@ -424,17 +388,15 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
			return 0;
		}
	}
			PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) not found\n");

	return -EINVAL;
}
		case VIDIOC_G_CTRL:

static int pwc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
{
			struct v4l2_control *c = arg;
	struct pwc_device *pdev = video_drvdata(file);
	int ret;

			switch (c->id)
			{
	switch (c->id) {
	case V4L2_CID_BRIGHTNESS:
		c->value = pwc_get_brightness(pdev);
		if (c->value < 0)
@@ -531,13 +493,13 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
	}
	return -EINVAL;
}
		case VIDIOC_S_CTRL:

static int pwc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
{
			struct v4l2_control *c = arg;
	struct pwc_device *pdev = video_drvdata(file);
	int ret;

			switch (c->id)
			{
	switch (c->id) {
	case V4L2_CID_BRIGHTNESS:
		c->value <<= 9;
		ret = pwc_set_brightness(pdev, c->value);
@@ -647,21 +609,12 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
	return -EINVAL;
}

		case VIDIOC_ENUM_FMT:
static int pwc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
{
			struct v4l2_fmtdesc *f = arg;
			int index;

			if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
			      return -EINVAL;
	struct pwc_device *pdev = video_drvdata(file);

	/* We only support two format: the raw format, and YUV */
			index = f->index;
			memset(f,0,sizeof(struct v4l2_fmtdesc));
			f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
			f->index = index;
			switch(index)
			{
	switch (f->index) {
	case 0:
		/* RAW format */
		f->pixelformat = pdev->type <= 646 ? V4L2_PIX_FMT_PWC1 : V4L2_PIX_FMT_PWC2;
@@ -678,53 +631,32 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
	return 0;
}

		case VIDIOC_G_FMT:
static int pwc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
{
			struct v4l2_format *f = arg;

			PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",pdev->image.x,pdev->image.y);
			if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
			      return -EINVAL;
	struct pwc_device *pdev = video_drvdata(file);

	PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",
			pdev->image.x, pdev->image.y);
	pwc_vidioc_fill_fmt(pdev, f);

	return 0;
}

		case VIDIOC_TRY_FMT:
			return pwc_vidioc_try_fmt(pdev, arg);

		case VIDIOC_S_FMT:
			return pwc_vidioc_set_fmt(pdev, arg);

		case VIDIOC_G_STD:
static int pwc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
{
			v4l2_std_id *std = arg;
			*std = V4L2_STD_UNKNOWN;
			return 0;
		}
	struct pwc_device *pdev = video_drvdata(file);

		case VIDIOC_S_STD:
		{
			v4l2_std_id *std = arg;
			if (*std != V4L2_STD_UNKNOWN)
				return -EINVAL;
			return 0;
	return pwc_vidioc_try_fmt(pdev, f);
}

		case VIDIOC_ENUMSTD:
static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
{
			struct v4l2_standard *std = arg;
			if (std->index != 0)
				return -EINVAL;
			std->id = V4L2_STD_UNKNOWN;
			strlcpy(std->name, "webcam", sizeof(std->name));
			return 0;
	struct pwc_device *pdev = video_drvdata(file);

	return pwc_vidioc_set_fmt(pdev, f);
}

		case VIDIOC_REQBUFS:
static int pwc_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb)
{
			struct v4l2_requestbuffers *rb = arg;
	int nbuffers;

	PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n", rb->count);
@@ -743,9 +675,9 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
	return 0;
}

		case VIDIOC_QUERYBUF:
static int pwc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
{
			struct v4l2_buffer *buf = arg;
	struct pwc_device *pdev = video_drvdata(file);
	int index;

	PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n", buf->index);
@@ -753,19 +685,12 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
		PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n");
		return -EINVAL;
	}
			if (buf->memory != V4L2_MEMORY_MMAP) {
				PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad memory type\n");
				return -EINVAL;
			}
	index = buf->index;
	if (index < 0 || index >= pwc_mbufs) {
		PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index);
		return -EINVAL;
	}

			memset(buf, 0, sizeof(struct v4l2_buffer));
			buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
			buf->index = index;
	buf->m.offset = index * pdev->len_per_image;
	if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
		buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
@@ -773,7 +698,7 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
		buf->bytesused = pdev->view.size;
	buf->field = V4L2_FIELD_NONE;
	buf->memory = V4L2_MEMORY_MMAP;
			//buf->flags = V4L2_BUF_FLAG_MAPPED;
	/*buf->flags = V4L2_BUF_FLAG_MAPPED;*/
	buf->length = pdev->len_per_image;

	PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n", buf->index);
@@ -783,10 +708,8 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
	return 0;
}

		case VIDIOC_QBUF:
static int pwc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
{
			struct v4l2_buffer *buf = arg;

	PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n", buf->index);
	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return -EINVAL;
@@ -801,9 +724,10 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
	return 0;
}

		case VIDIOC_DQBUF:
static int pwc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
{
			struct v4l2_buffer *buf = arg;
	DECLARE_WAITQUEUE(wait, current);
	struct pwc_device *pdev = video_drvdata(file);
	int ret;

	PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
@@ -811,12 +735,6 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return -EINVAL;

			/* Add ourselves to the frame wait-queue.

			   FIXME: needs auditing for safety.
			   QUESTION: In what respect? I think that using the
				     frameq is safe now.
			 */
	add_wait_queue(&pdev->frameq, &wait);
	while (pdev->full_frames == NULL) {
		if (pdev->error_status) {
@@ -868,20 +786,25 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)

}

		case VIDIOC_STREAMON:
static int pwc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
{
	struct pwc_device *pdev = video_drvdata(file);

	return pwc_isoc_init(pdev);
}

		case VIDIOC_STREAMOFF:
static int pwc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
{
	struct pwc_device *pdev = video_drvdata(file);

	pwc_isoc_cleanup(pdev);
	return 0;
}

		case VIDIOC_ENUM_FRAMESIZES:
static int pwc_enum_framesizes(struct file *file, void *fh,
					 struct v4l2_frmsizeenum *fsize)
{
			struct v4l2_frmsizeenum *fsize = arg;
	struct pwc_device *pdev = video_drvdata(file);
	unsigned int i = 0, index = fsize->index;

	if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) {
@@ -907,9 +830,10 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
	return -EINVAL;
}

		case VIDIOC_ENUM_FRAMEINTERVALS:
static int pwc_enum_frameintervals(struct file *file, void *fh,
					   struct v4l2_frmivalenum *fival)
{
			struct v4l2_frmivalenum *fival = arg;
	struct pwc_device *pdev = video_drvdata(file);
	int size = -1;
	unsigned int i;

@@ -922,9 +846,8 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
	}

	/* TODO: Support raw format */
			if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420) {
	if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420)
		return -EINVAL;
			}

	i = pwc_get_fps(pdev, fival->index, size);
	if (!i)
@@ -937,10 +860,35 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
	return 0;
}

		default:
static long pwc_default(struct file *file, void *fh, int cmd, void *arg)
{
	struct pwc_device *pdev = video_drvdata(file);

	return pwc_ioctl(pdev, cmd, arg);
	} /* ..switch */
	return 0;
}

const struct v4l2_ioctl_ops pwc_ioctl_ops = {
	.vidioc_querycap		    = pwc_querycap,
	.vidioc_enum_input		    = pwc_enum_input,
	.vidioc_g_input			    = pwc_g_input,
	.vidioc_s_input			    = pwc_s_input,
	.vidioc_enum_fmt_vid_cap	    = pwc_enum_fmt_vid_cap,
	.vidioc_g_fmt_vid_cap		    = pwc_g_fmt_vid_cap,
	.vidioc_s_fmt_vid_cap		    = pwc_s_fmt_vid_cap,
	.vidioc_try_fmt_vid_cap		    = pwc_try_fmt_vid_cap,
	.vidioc_queryctrl		    = pwc_queryctrl,
	.vidioc_g_ctrl			    = pwc_g_ctrl,
	.vidioc_s_ctrl			    = pwc_s_ctrl,
	.vidioc_reqbufs			    = pwc_reqbufs,
	.vidioc_querybuf		    = pwc_querybuf,
	.vidioc_qbuf			    = pwc_qbuf,
	.vidioc_dqbuf			    = pwc_dqbuf,
	.vidioc_streamon		    = pwc_streamon,
	.vidioc_streamoff		    = pwc_streamoff,
	.vidioc_enum_framesizes		    = pwc_enum_framesizes,
	.vidioc_enum_frameintervals	    = pwc_enum_frameintervals,
	.vidioc_default		    = pwc_default,
};


/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
+1 −2
Original line number Diff line number Diff line
@@ -339,8 +339,7 @@ extern int pwc_camera_power(struct pwc_device *pdev, int power);
/* Private ioctl()s; see pwc-ioctl.h */
extern long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg);

/** Functions in pwc-v4l.c */
extern long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg);
extern const struct v4l2_ioctl_ops pwc_ioctl_ops;

/** pwc-uncompress.c */
/* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */