diff options
Diffstat (limited to 'drivers/media/video/pwc/pwc-v4l.c')
| -rw-r--r-- | drivers/media/video/pwc/pwc-v4l.c | 1015 | 
1 files changed, 483 insertions, 532 deletions
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c index 8ca4d22b438..aa87e462a95 100644 --- a/drivers/media/video/pwc/pwc-v4l.c +++ b/drivers/media/video/pwc/pwc-v4l.c @@ -341,604 +341,555 @@ 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; +	struct pwc_device *pdev = video_drvdata(file); -#ifdef CONFIG_USB_PWC_DEBUG -	if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace) { -		v4l_printk_ioctl(cmd); -		printk("\n"); -	} -#endif - - -	switch (cmd) { -		/* V4L2 Layer */ -		case VIDIOC_QUERYCAP: -		{ -		    struct v4l2_capability *cap = arg; +	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)); +	cap->version = PWC_VERSION_CODE; +	cap->capabilities = +		V4L2_CAP_VIDEO_CAPTURE	| +		V4L2_CAP_STREAMING	| +		V4L2_CAP_READWRITE; +	return 0; +} -		    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)); -		    cap->version = PWC_VERSION_CODE; -		    cap->capabilities = -			V4L2_CAP_VIDEO_CAPTURE	| -			V4L2_CAP_STREAMING	| -			V4L2_CAP_READWRITE; -		    return 0; -		} +static int pwc_enum_input(struct file *file, void *fh, struct v4l2_input *i) +{ +	if (i->index)	/* Only one INPUT is supported */ +		return -EINVAL; -		case VIDIOC_ENUMINPUT: -		{ -		    struct v4l2_input *i = arg; +	strcpy(i->name, "usb"); +	return 0; +} -		    if ( i->index )	/* Only one INPUT is supported */ -			  return -EINVAL; +static int pwc_g_input(struct file *file, void *fh, unsigned int *i) +{ +	*i = 0; +	return 0; +} -		    memset(i, 0, sizeof(struct v4l2_input)); -		    strcpy(i->name, "usb"); -		    return 0; -		} +static int pwc_s_input(struct file *file, void *fh, unsigned int i) +{ +	return i ? -EINVAL : 0; +} -		case VIDIOC_G_INPUT: -		{ -		    int *i = arg; -		    *i = 0;	/* Only one INPUT is supported */ -		    return 0; -		} -		case VIDIOC_S_INPUT: -		{ -			int *i = arg; +static int pwc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c) +{ +	int i; -			if ( *i ) {	/* Only one INPUT is supported */ -				PWC_DEBUG_IOCTL("Only one input source is"\ -					" supported with this webcam.\n"); -				return -EINVAL; -			} +	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"); +			memcpy(c, &pwc_controls[i], sizeof(struct v4l2_queryctrl));  			return 0;  		} +	} +	return -EINVAL; +} -		/* TODO: */ -		case VIDIOC_QUERYCTRL: -		{ -			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"); -					memcpy(c,&pwc_controls[i],sizeof(struct v4l2_queryctrl)); -					return 0; -				} -			} -			PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) not found\n"); +static int pwc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) +{ +	struct pwc_device *pdev = video_drvdata(file); +	int ret; +	switch (c->id) { +	case V4L2_CID_BRIGHTNESS: +		c->value = pwc_get_brightness(pdev); +		if (c->value < 0)  			return -EINVAL; -		} -		case VIDIOC_G_CTRL: -		{ -			struct v4l2_control *c = arg; -			int ret; - -			switch (c->id) -			{ -				case V4L2_CID_BRIGHTNESS: -					c->value = pwc_get_brightness(pdev); -					if (c->value<0) -						return -EINVAL; -					return 0; -				case V4L2_CID_CONTRAST: -					c->value = pwc_get_contrast(pdev); -					if (c->value<0) -						return -EINVAL; -					return 0; -				case V4L2_CID_SATURATION: -					ret = pwc_get_saturation(pdev, &c->value); -					if (ret<0) -						return -EINVAL; -					return 0; -				case V4L2_CID_GAMMA: -					c->value = pwc_get_gamma(pdev); -					if (c->value<0) -						return -EINVAL; -					return 0; -				case V4L2_CID_RED_BALANCE: -					ret = pwc_get_red_gain(pdev, &c->value); -					if (ret<0) -						return -EINVAL; -					c->value >>= 8; -					return 0; -				case V4L2_CID_BLUE_BALANCE: -					ret = pwc_get_blue_gain(pdev, &c->value); -					if (ret<0) -						return -EINVAL; -					c->value >>= 8; -					return 0; -				case V4L2_CID_AUTO_WHITE_BALANCE: -					ret = pwc_get_awb(pdev); -					if (ret<0) -						return -EINVAL; -					c->value = (ret == PWC_WB_MANUAL)?0:1; -					return 0; -				case V4L2_CID_GAIN: -					ret = pwc_get_agc(pdev, &c->value); -					if (ret<0) -						return -EINVAL; -					c->value >>= 8; -					return 0; -				case V4L2_CID_AUTOGAIN: -					ret = pwc_get_agc(pdev, &c->value); -					if (ret<0) -						return -EINVAL; -					c->value = (c->value < 0)?1:0; -					return 0; -				case V4L2_CID_EXPOSURE: -					ret = pwc_get_shutter_speed(pdev, &c->value); -					if (ret<0) -						return -EINVAL; -					return 0; -				case V4L2_CID_PRIVATE_COLOUR_MODE: -					ret = pwc_get_colour_mode(pdev, &c->value); -					if (ret < 0) -						return -EINVAL; -					return 0; -				case V4L2_CID_PRIVATE_AUTOCONTOUR: -					ret = pwc_get_contour(pdev, &c->value); -					if (ret < 0) -						return -EINVAL; -					c->value=(c->value == -1?1:0); -					return 0; -				case V4L2_CID_PRIVATE_CONTOUR: -					ret = pwc_get_contour(pdev, &c->value); -					if (ret < 0) -						return -EINVAL; -					c->value >>= 10; -					return 0; -				case V4L2_CID_PRIVATE_BACKLIGHT: -					ret = pwc_get_backlight(pdev, &c->value); -					if (ret < 0) -						return -EINVAL; -					return 0; -				case V4L2_CID_PRIVATE_FLICKERLESS: -					ret = pwc_get_flicker(pdev, &c->value); -					if (ret < 0) -						return -EINVAL; -					c->value=(c->value?1:0); -					return 0; -				case V4L2_CID_PRIVATE_NOISE_REDUCTION: -					ret = pwc_get_dynamic_noise(pdev, &c->value); -					if (ret < 0) -						return -EINVAL; -					return 0; - -				case V4L2_CID_PRIVATE_SAVE_USER: -				case V4L2_CID_PRIVATE_RESTORE_USER: -				case V4L2_CID_PRIVATE_RESTORE_FACTORY: -					return -EINVAL; -			} +		return 0; +	case V4L2_CID_CONTRAST: +		c->value = pwc_get_contrast(pdev); +		if (c->value < 0)  			return -EINVAL; -		} -		case VIDIOC_S_CTRL: -		{ -			struct v4l2_control *c = arg; -			int ret; - -			switch (c->id) -			{ -				case V4L2_CID_BRIGHTNESS: -					c->value <<= 9; -					ret = pwc_set_brightness(pdev, c->value); -					if (ret<0) -						return -EINVAL; -					return 0; -				case V4L2_CID_CONTRAST: -					c->value <<= 10; -					ret = pwc_set_contrast(pdev, c->value); -					if (ret<0) -						return -EINVAL; -					return 0; -				case V4L2_CID_SATURATION: -					ret = pwc_set_saturation(pdev, c->value); -					if (ret<0) -					  return -EINVAL; -					return 0; -				case V4L2_CID_GAMMA: -					c->value <<= 11; -					ret = pwc_set_gamma(pdev, c->value); -					if (ret<0) -						return -EINVAL; -					return 0; -				case V4L2_CID_RED_BALANCE: -					c->value <<= 8; -					ret = pwc_set_red_gain(pdev, c->value); -					if (ret<0) -						return -EINVAL; -					return 0; -				case V4L2_CID_BLUE_BALANCE: -					c->value <<= 8; -					ret = pwc_set_blue_gain(pdev, c->value); -					if (ret<0) -						return -EINVAL; -					return 0; -				case V4L2_CID_AUTO_WHITE_BALANCE: -					c->value = (c->value == 0)?PWC_WB_MANUAL:PWC_WB_AUTO; -					ret = pwc_set_awb(pdev, c->value); -					if (ret<0) -						return -EINVAL; -					return 0; -				case V4L2_CID_EXPOSURE: -					c->value <<= 8; -					ret = pwc_set_shutter_speed(pdev, c->value?0:1, c->value); -					if (ret<0) -						return -EINVAL; -					return 0; -				case V4L2_CID_AUTOGAIN: -					/* autogain off means nothing without a gain */ -					if (c->value == 0) -						return 0; -					ret = pwc_set_agc(pdev, c->value, 0); -					if (ret<0) -						return -EINVAL; -					return 0; -				case V4L2_CID_GAIN: -					c->value <<= 8; -					ret = pwc_set_agc(pdev, 0, c->value); -					if (ret<0) -						return -EINVAL; -					return 0; -				case V4L2_CID_PRIVATE_SAVE_USER: -					if (pwc_save_user(pdev)) -						return -EINVAL; -					return 0; -				case V4L2_CID_PRIVATE_RESTORE_USER: -					if (pwc_restore_user(pdev)) -						return -EINVAL; -					return 0; -				case V4L2_CID_PRIVATE_RESTORE_FACTORY: -					if (pwc_restore_factory(pdev)) -						return -EINVAL; -					return 0; -				case V4L2_CID_PRIVATE_COLOUR_MODE: -					ret = pwc_set_colour_mode(pdev, c->value); -					if (ret < 0) -					  return -EINVAL; -					return 0; -				case V4L2_CID_PRIVATE_AUTOCONTOUR: -				  c->value=(c->value == 1)?-1:0; -				  ret = pwc_set_contour(pdev, c->value); -				  if (ret < 0) -				    return -EINVAL; -				  return 0; -				case V4L2_CID_PRIVATE_CONTOUR: -				  c->value <<= 10; -				  ret = pwc_set_contour(pdev, c->value); -				  if (ret < 0) -				    return -EINVAL; -				  return 0; -				case V4L2_CID_PRIVATE_BACKLIGHT: -				  ret = pwc_set_backlight(pdev, c->value); -				  if (ret < 0) -				    return -EINVAL; -				  return 0; -				case V4L2_CID_PRIVATE_FLICKERLESS: -				  ret = pwc_set_flicker(pdev, c->value); -				  if (ret < 0) -				    return -EINVAL; -				case V4L2_CID_PRIVATE_NOISE_REDUCTION: -				  ret = pwc_set_dynamic_noise(pdev, c->value); -				  if (ret < 0) -				    return -EINVAL; -				  return 0; - -			} +		return 0; +	case V4L2_CID_SATURATION: +		ret = pwc_get_saturation(pdev, &c->value); +		if (ret < 0)  			return -EINVAL; -		} +		return 0; +	case V4L2_CID_GAMMA: +		c->value = pwc_get_gamma(pdev); +		if (c->value < 0) +			return -EINVAL; +		return 0; +	case V4L2_CID_RED_BALANCE: +		ret = pwc_get_red_gain(pdev, &c->value); +		if (ret < 0) +			return -EINVAL; +		c->value >>= 8; +		return 0; +	case V4L2_CID_BLUE_BALANCE: +		ret = pwc_get_blue_gain(pdev, &c->value); +		if (ret < 0) +			return -EINVAL; +		c->value >>= 8; +		return 0; +	case V4L2_CID_AUTO_WHITE_BALANCE: +		ret = pwc_get_awb(pdev); +		if (ret < 0) +			return -EINVAL; +		c->value = (ret == PWC_WB_MANUAL) ? 0 : 1; +		return 0; +	case V4L2_CID_GAIN: +		ret = pwc_get_agc(pdev, &c->value); +		if (ret < 0) +			return -EINVAL; +		c->value >>= 8; +		return 0; +	case V4L2_CID_AUTOGAIN: +		ret = pwc_get_agc(pdev, &c->value); +		if (ret < 0) +			return -EINVAL; +		c->value = (c->value < 0) ? 1 : 0; +		return 0; +	case V4L2_CID_EXPOSURE: +		ret = pwc_get_shutter_speed(pdev, &c->value); +		if (ret < 0) +			return -EINVAL; +		return 0; +	case V4L2_CID_PRIVATE_COLOUR_MODE: +		ret = pwc_get_colour_mode(pdev, &c->value); +		if (ret < 0) +			return -EINVAL; +		return 0; +	case V4L2_CID_PRIVATE_AUTOCONTOUR: +		ret = pwc_get_contour(pdev, &c->value); +		if (ret < 0) +			return -EINVAL; +		c->value = (c->value == -1 ? 1 : 0); +		return 0; +	case V4L2_CID_PRIVATE_CONTOUR: +		ret = pwc_get_contour(pdev, &c->value); +		if (ret < 0) +			return -EINVAL; +		c->value >>= 10; +		return 0; +	case V4L2_CID_PRIVATE_BACKLIGHT: +		ret = pwc_get_backlight(pdev, &c->value); +		if (ret < 0) +			return -EINVAL; +		return 0; +	case V4L2_CID_PRIVATE_FLICKERLESS: +		ret = pwc_get_flicker(pdev, &c->value); +		if (ret < 0) +			return -EINVAL; +		c->value = (c->value ? 1 : 0); +		return 0; +	case V4L2_CID_PRIVATE_NOISE_REDUCTION: +		ret = pwc_get_dynamic_noise(pdev, &c->value); +		if (ret < 0) +			return -EINVAL; +		return 0; -		case VIDIOC_ENUM_FMT: -		{ -			struct v4l2_fmtdesc *f = arg; -			int index; +	case V4L2_CID_PRIVATE_SAVE_USER: +	case V4L2_CID_PRIVATE_RESTORE_USER: +	case V4L2_CID_PRIVATE_RESTORE_FACTORY: +		return -EINVAL; +	} +	return -EINVAL; +} -			if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) -			      return -EINVAL; +static int pwc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) +{ +	struct pwc_device *pdev = video_drvdata(file); +	int ret; -			/* 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) -			{ -				case 0: -					/* RAW format */ -					f->pixelformat = pdev->type<=646?V4L2_PIX_FMT_PWC1:V4L2_PIX_FMT_PWC2; -					f->flags = V4L2_FMT_FLAG_COMPRESSED; -					strlcpy(f->description,"Raw Philips Webcam",sizeof(f->description)); -					break; -				case 1: -					f->pixelformat = V4L2_PIX_FMT_YUV420; -					strlcpy(f->description,"4:2:0, planar, Y-Cb-Cr",sizeof(f->description)); -					break; -				default: -					return -EINVAL; -			} +	switch (c->id) { +	case V4L2_CID_BRIGHTNESS: +		c->value <<= 9; +		ret = pwc_set_brightness(pdev, c->value); +		if (ret < 0) +			return -EINVAL; +		return 0; +	case V4L2_CID_CONTRAST: +		c->value <<= 10; +		ret = pwc_set_contrast(pdev, c->value); +		if (ret < 0) +			return -EINVAL; +		return 0; +	case V4L2_CID_SATURATION: +		ret = pwc_set_saturation(pdev, c->value); +		if (ret < 0) +			return -EINVAL; +		return 0; +	case V4L2_CID_GAMMA: +		c->value <<= 11; +		ret = pwc_set_gamma(pdev, c->value); +		if (ret < 0) +			return -EINVAL; +		return 0; +	case V4L2_CID_RED_BALANCE: +		c->value <<= 8; +		ret = pwc_set_red_gain(pdev, c->value); +		if (ret < 0) +			return -EINVAL; +		return 0; +	case V4L2_CID_BLUE_BALANCE: +		c->value <<= 8; +		ret = pwc_set_blue_gain(pdev, c->value); +		if (ret < 0) +			return -EINVAL; +		return 0; +	case V4L2_CID_AUTO_WHITE_BALANCE: +		c->value = (c->value == 0) ? PWC_WB_MANUAL : PWC_WB_AUTO; +		ret = pwc_set_awb(pdev, c->value); +		if (ret < 0) +			return -EINVAL; +		return 0; +	case V4L2_CID_EXPOSURE: +		c->value <<= 8; +		ret = pwc_set_shutter_speed(pdev, c->value ? 0 : 1, c->value); +		if (ret < 0) +			return -EINVAL; +		return 0; +	case V4L2_CID_AUTOGAIN: +		/* autogain off means nothing without a gain */ +		if (c->value == 0)  			return 0; -		} - -		case VIDIOC_G_FMT: -		{ -			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; +		ret = pwc_set_agc(pdev, c->value, 0); +		if (ret < 0) +			return -EINVAL; +		return 0; +	case V4L2_CID_GAIN: +		c->value <<= 8; +		ret = pwc_set_agc(pdev, 0, c->value); +		if (ret < 0) +			return -EINVAL; +		return 0; +	case V4L2_CID_PRIVATE_SAVE_USER: +		if (pwc_save_user(pdev)) +			return -EINVAL; +		return 0; +	case V4L2_CID_PRIVATE_RESTORE_USER: +		if (pwc_restore_user(pdev)) +			return -EINVAL; +		return 0; +	case V4L2_CID_PRIVATE_RESTORE_FACTORY: +		if (pwc_restore_factory(pdev)) +			return -EINVAL; +		return 0; +	case V4L2_CID_PRIVATE_COLOUR_MODE: +		ret = pwc_set_colour_mode(pdev, c->value); +		if (ret < 0) +			return -EINVAL; +		return 0; +	case V4L2_CID_PRIVATE_AUTOCONTOUR: +		c->value = (c->value == 1) ? -1 : 0; +		ret = pwc_set_contour(pdev, c->value); +		if (ret < 0) +			return -EINVAL; +		return 0; +	case V4L2_CID_PRIVATE_CONTOUR: +		c->value <<= 10; +		ret = pwc_set_contour(pdev, c->value); +		if (ret < 0) +			return -EINVAL; +		return 0; +	case V4L2_CID_PRIVATE_BACKLIGHT: +		ret = pwc_set_backlight(pdev, c->value); +		if (ret < 0) +			return -EINVAL; +		return 0; +	case V4L2_CID_PRIVATE_FLICKERLESS: +		ret = pwc_set_flicker(pdev, c->value); +		if (ret < 0) +			return -EINVAL; +	case V4L2_CID_PRIVATE_NOISE_REDUCTION: +		ret = pwc_set_dynamic_noise(pdev, c->value); +		if (ret < 0) +			return -EINVAL; +		return 0; -			pwc_vidioc_fill_fmt(pdev, f); +	} +	return -EINVAL; +} -			return 0; -		} +static int pwc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ +	struct pwc_device *pdev = video_drvdata(file); -		case VIDIOC_TRY_FMT: -			return pwc_vidioc_try_fmt(pdev, arg); +	/* We only support two format: the raw format, and YUV */ +	switch (f->index) { +	case 0: +		/* RAW format */ +		f->pixelformat = pdev->type <= 646 ? V4L2_PIX_FMT_PWC1 : V4L2_PIX_FMT_PWC2; +		f->flags = V4L2_FMT_FLAG_COMPRESSED; +		strlcpy(f->description, "Raw Philips Webcam", sizeof(f->description)); +		break; +	case 1: +		f->pixelformat = V4L2_PIX_FMT_YUV420; +		strlcpy(f->description, "4:2:0, planar, Y-Cb-Cr", sizeof(f->description)); +		break; +	default: +		return -EINVAL; +	} +	return 0; +} -		case VIDIOC_S_FMT: -			return pwc_vidioc_set_fmt(pdev, arg); +static int pwc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) +{ +	struct pwc_device *pdev = video_drvdata(file); -		case VIDIOC_G_STD: -		{ -			v4l2_std_id *std = arg; -			*std = V4L2_STD_UNKNOWN; -			return 0; -		} +	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_S_STD: -		{ -			v4l2_std_id *std = arg; -			if (*std != V4L2_STD_UNKNOWN) -				return -EINVAL; -			return 0; -		} +static int pwc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) +{ +	struct pwc_device *pdev = video_drvdata(file); -		case VIDIOC_ENUMSTD: -		{ -			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; -		} +	return pwc_vidioc_try_fmt(pdev, f); +} -		case VIDIOC_REQBUFS: -		{ -			struct v4l2_requestbuffers *rb = arg; -			int nbuffers; +static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) +{ +	struct pwc_device *pdev = video_drvdata(file); -			PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n",rb->count); -			if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) -				return -EINVAL; -			if (rb->memory != V4L2_MEMORY_MMAP) -				return -EINVAL; +	return pwc_vidioc_set_fmt(pdev, f); +} -			nbuffers = rb->count; -			if (nbuffers < 2) -				nbuffers = 2; -			else if (nbuffers > pwc_mbufs) -				nbuffers = pwc_mbufs; -			/* Force to use our # of buffers */ -			rb->count = pwc_mbufs; -			return 0; -		} +static int pwc_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb) +{ +	int nbuffers; -		case VIDIOC_QUERYBUF: -		{ -			struct v4l2_buffer *buf = arg; -			int index; +	PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n", rb->count); +	if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) +		return -EINVAL; +	if (rb->memory != V4L2_MEMORY_MMAP) +		return -EINVAL; -			PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n",buf->index); -			if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { -				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; -			} +	nbuffers = rb->count; +	if (nbuffers < 2) +		nbuffers = 2; +	else if (nbuffers > pwc_mbufs) +		nbuffers = pwc_mbufs; +	/* Force to use our # of buffers */ +	rb->count = pwc_mbufs; +	return 0; +} -			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); -			else -				buf->bytesused = pdev->view.size; -			buf->field = V4L2_FIELD_NONE; -			buf->memory = V4L2_MEMORY_MMAP; -			//buf->flags = V4L2_BUF_FLAG_MAPPED; -			buf->length = pdev->len_per_image; +static int pwc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) +{ +	struct pwc_device *pdev = video_drvdata(file); +	int index; -			PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n",buf->index); -			PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n",buf->m.offset); -			PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n",buf->bytesused); +	PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n", buf->index); +	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { +		PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad 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; +	} -			return 0; -		} +	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); +	else +		buf->bytesused = pdev->view.size; +	buf->field = V4L2_FIELD_NONE; +	buf->memory = V4L2_MEMORY_MMAP; +	/*buf->flags = V4L2_BUF_FLAG_MAPPED;*/ +	buf->length = pdev->len_per_image; -		case VIDIOC_QBUF: -		{ -			struct v4l2_buffer *buf = arg; +	PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n", buf->index); +	PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n", buf->m.offset); +	PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n", buf->bytesused); -			PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n",buf->index); -			if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) -				return -EINVAL; -			if (buf->memory != V4L2_MEMORY_MMAP) -				return -EINVAL; -			if (buf->index >= pwc_mbufs) -				return -EINVAL; +	return 0; +} -			buf->flags |= V4L2_BUF_FLAG_QUEUED; -			buf->flags &= ~V4L2_BUF_FLAG_DONE; +static int pwc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) +{ +	PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n", buf->index); +	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) +		return -EINVAL; +	if (buf->memory != V4L2_MEMORY_MMAP) +		return -EINVAL; +	if (buf->index >= pwc_mbufs) +		return -EINVAL; -			return 0; -		} +	buf->flags |= V4L2_BUF_FLAG_QUEUED; +	buf->flags &= ~V4L2_BUF_FLAG_DONE; -		case VIDIOC_DQBUF: -		{ -			struct v4l2_buffer *buf = arg; -			int ret; +	return 0; +} -			PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n"); +static int pwc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) +{ +	DECLARE_WAITQUEUE(wait, current); +	struct pwc_device *pdev = video_drvdata(file); +	int ret; -			if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) -				return -EINVAL; +	PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n"); -			/* Add ourselves to the frame wait-queue. +	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) +		return -EINVAL; -			   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) { -					remove_wait_queue(&pdev->frameq, &wait); -					set_current_state(TASK_RUNNING); -					return -pdev->error_status; -				} +	add_wait_queue(&pdev->frameq, &wait); +	while (pdev->full_frames == NULL) { +		if (pdev->error_status) { +			remove_wait_queue(&pdev->frameq, &wait); +			set_current_state(TASK_RUNNING); +			return -pdev->error_status; +		} -				if (signal_pending(current)) { -					remove_wait_queue(&pdev->frameq, &wait); -					set_current_state(TASK_RUNNING); -					return -ERESTARTSYS; -				} -				schedule(); -				set_current_state(TASK_INTERRUPTIBLE); -			} +		if (signal_pending(current)) {  			remove_wait_queue(&pdev->frameq, &wait);  			set_current_state(TASK_RUNNING); +			return -ERESTARTSYS; +		} +		mutex_unlock(&pdev->modlock); +		schedule(); +		set_current_state(TASK_INTERRUPTIBLE); +		mutex_lock(&pdev->modlock); +	} +	remove_wait_queue(&pdev->frameq, &wait); +	set_current_state(TASK_RUNNING); -			PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n"); -			/* Decompress data in pdev->images[pdev->fill_image] */ -			ret = pwc_handle_frame(pdev); -			if (ret) -				return -EFAULT; -			PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n"); +	PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n"); +	/* Decompress data in pdev->images[pdev->fill_image] */ +	ret = pwc_handle_frame(pdev); +	if (ret) +		return -EFAULT; +	PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n"); -			buf->index = pdev->fill_image; -			if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) -				buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame); -			else -				buf->bytesused = pdev->view.size; -			buf->flags = V4L2_BUF_FLAG_MAPPED; -			buf->field = V4L2_FIELD_NONE; -			do_gettimeofday(&buf->timestamp); -			buf->sequence = 0; -			buf->memory = V4L2_MEMORY_MMAP; -			buf->m.offset = pdev->fill_image * pdev->len_per_image; -			buf->length = pdev->len_per_image; -			pwc_next_image(pdev); +	buf->index = pdev->fill_image; +	if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) +		buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame); +	else +		buf->bytesused = pdev->view.size; +	buf->flags = V4L2_BUF_FLAG_MAPPED; +	buf->field = V4L2_FIELD_NONE; +	do_gettimeofday(&buf->timestamp); +	buf->sequence = 0; +	buf->memory = V4L2_MEMORY_MMAP; +	buf->m.offset = pdev->fill_image * pdev->len_per_image; +	buf->length = pdev->len_per_image; +	pwc_next_image(pdev); -			PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index); -			PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n",buf->length); -			PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n",buf->m.offset); -			PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n",buf->bytesused); -			PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n"); -			return 0; +	PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n", buf->index); +	PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n", buf->length); +	PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n", buf->m.offset); +	PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n", buf->bytesused); +	PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n"); +	return 0; -		} +} -		case VIDIOC_STREAMON: -		{ -			return pwc_isoc_init(pdev); -		} +static int pwc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) +{ +	struct pwc_device *pdev = video_drvdata(file); -		case VIDIOC_STREAMOFF: -		{ -			pwc_isoc_cleanup(pdev); -			return 0; -		} +	return pwc_isoc_init(pdev); +} -		case VIDIOC_ENUM_FRAMESIZES: -		{ -			struct v4l2_frmsizeenum *fsize = arg; -			unsigned int i = 0, index = fsize->index; +static int pwc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) +{ +	struct pwc_device *pdev = video_drvdata(file); -			if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) { -				for (i = 0; i < PSZ_MAX; i++) { -					if (pdev->image_mask & (1UL << i)) { -						if (!index--) { -							fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; -							fsize->discrete.width = pwc_image_sizes[i].x; -							fsize->discrete.height = pwc_image_sizes[i].y; -							return 0; -						} -					} -				} -			} else if (fsize->index == 0 && -				   ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) || -				    (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) { +	pwc_isoc_cleanup(pdev); +	return 0; +} -				fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; -				fsize->discrete.width = pdev->abs_max.x; -				fsize->discrete.height = pdev->abs_max.y; -				return 0; +static int pwc_enum_framesizes(struct file *file, void *fh, +					 struct v4l2_frmsizeenum *fsize) +{ +	struct pwc_device *pdev = video_drvdata(file); +	unsigned int i = 0, index = fsize->index; + +	if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) { +		for (i = 0; i < PSZ_MAX; i++) { +			if (pdev->image_mask & (1UL << i)) { +				if (!index--) { +					fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; +					fsize->discrete.width = pwc_image_sizes[i].x; +					fsize->discrete.height = pwc_image_sizes[i].y; +					return 0; +				}  			} -			return -EINVAL;  		} +	} else if (fsize->index == 0 && +			((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) || +			 (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) { -		case VIDIOC_ENUM_FRAMEINTERVALS: -		{ -			struct v4l2_frmivalenum *fival = arg; -			int size = -1; -			unsigned int i; +		fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; +		fsize->discrete.width = pdev->abs_max.x; +		fsize->discrete.height = pdev->abs_max.y; +		return 0; +	} +	return -EINVAL; +} -			for (i = 0; i < PSZ_MAX; i++) { -				if (pwc_image_sizes[i].x == fival->width && -				    pwc_image_sizes[i].y == fival->height) { -					size = i; -					break; -				} -			} +static int pwc_enum_frameintervals(struct file *file, void *fh, +					   struct v4l2_frmivalenum *fival) +{ +	struct pwc_device *pdev = video_drvdata(file); +	int size = -1; +	unsigned int i; -			/* TODO: Support raw format */ -			if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420) { -				return -EINVAL; -			} +	for (i = 0; i < PSZ_MAX; i++) { +		if (pwc_image_sizes[i].x == fival->width && +				pwc_image_sizes[i].y == fival->height) { +			size = i; +			break; +		} +	} -			i = pwc_get_fps(pdev, fival->index, size); -			if (!i) -				return -EINVAL; +	/* TODO: Support raw format */ +	if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420) +		return -EINVAL; -			fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; -			fival->discrete.numerator = 1; -			fival->discrete.denominator = i; +	i = pwc_get_fps(pdev, fival->index, size); +	if (!i) +		return -EINVAL; -			return 0; -		} +	fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; +	fival->discrete.numerator = 1; +	fival->discrete.denominator = i; -		default: -			return pwc_ioctl(pdev, cmd, arg); -	} /* ..switch */  	return 0;  } +static long pwc_default(struct file *file, void *fh, bool valid_prio, +			int cmd, void *arg) +{ +	struct pwc_device *pdev = video_drvdata(file); + +	return pwc_ioctl(pdev, cmd, arg); +} + +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: */  |