diff options
Diffstat (limited to 'drivers/media/v4l2-core/v4l2-ioctl.c')
| -rw-r--r-- | drivers/media/v4l2-core/v4l2-ioctl.c | 112 | 
1 files changed, 92 insertions, 20 deletions
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 68e6b5e912f..16bffd851bf 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -28,6 +28,9 @@  #include <media/v4l2-device.h>  #include <media/videobuf2-core.h> +#define CREATE_TRACE_POINTS +#include <trace/events/v4l2.h> +  /* Zero out the end of the struct pointed to by p.  Everything after, but   * not including, the specified field is cleared. */  #define CLEAR_AFTER_FIELD(p, field) \ @@ -149,6 +152,7 @@ const char *v4l2_type_names[] = {  	[V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "vid-out-overlay",  	[V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE] = "vid-cap-mplane",  	[V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE] = "vid-out-mplane", +	[V4L2_BUF_TYPE_SDR_CAPTURE]        = "sdr-cap",  };  EXPORT_SYMBOL(v4l2_type_names); @@ -242,6 +246,7 @@ static void v4l_print_format(const void *arg, bool write_only)  	const struct v4l2_vbi_format *vbi;  	const struct v4l2_sliced_vbi_format *sliced;  	const struct v4l2_window *win; +	const struct v4l2_sdr_format *sdr;  	unsigned i;  	pr_cont("type=%s", prt_names(p->type, v4l2_type_names)); @@ -315,6 +320,14 @@ static void v4l_print_format(const void *arg, bool write_only)  				sliced->service_lines[0][i],  				sliced->service_lines[1][i]);  		break; +	case V4L2_BUF_TYPE_SDR_CAPTURE: +		sdr = &p->fmt.sdr; +		pr_cont(", pixelformat=%c%c%c%c\n", +			(sdr->pixelformat >>  0) & 0xff, +			(sdr->pixelformat >>  8) & 0xff, +			(sdr->pixelformat >> 16) & 0xff, +			(sdr->pixelformat >> 24) & 0xff); +		break;  	}  } @@ -549,7 +562,7 @@ static void v4l_print_cropcap(const void *arg, bool write_only)  	const struct v4l2_cropcap *p = arg;  	pr_cont("type=%s, bounds wxh=%dx%d, x,y=%d,%d, " -		"defrect wxh=%dx%d, x,y=%d,%d\n, " +		"defrect wxh=%dx%d, x,y=%d,%d, "  		"pixelaspect %d/%d\n",  		prt_names(p->type, v4l2_type_names),  		p->bounds.width, p->bounds.height, @@ -831,6 +844,14 @@ static void v4l_print_freq_band(const void *arg, bool write_only)  			p->rangehigh, p->modulation);  } +static void v4l_print_edid(const void *arg, bool write_only) +{ +	const struct v4l2_edid *p = arg; + +	pr_cont("pad=%u, start_block=%u, blocks=%u\n", +		p->pad, p->start_block, p->blocks); +} +  static void v4l_print_u32(const void *arg, bool write_only)  {  	pr_cont("value=%u\n", *(const u32 *)arg); @@ -878,6 +899,7 @@ static int check_fmt(struct file *file, enum v4l2_buf_type type)  	const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;  	bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER;  	bool is_vbi = vfd->vfl_type == VFL_TYPE_VBI; +	bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;  	bool is_rx = vfd->vfl_dir != VFL_DIR_TX;  	bool is_tx = vfd->vfl_dir != VFL_DIR_RX; @@ -927,6 +949,10 @@ static int check_fmt(struct file *file, enum v4l2_buf_type type)  		if (is_vbi && is_tx && ops->vidioc_g_fmt_sliced_vbi_out)  			return 0;  		break; +	case V4L2_BUF_TYPE_SDR_CAPTURE: +		if (is_sdr && is_rx && ops->vidioc_g_fmt_sdr_cap) +			return 0; +		break;  	default:  		break;  	} @@ -1046,6 +1072,10 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops,  		if (unlikely(!is_tx || !ops->vidioc_enum_fmt_vid_out_mplane))  			break;  		return ops->vidioc_enum_fmt_vid_out_mplane(file, fh, arg); +	case V4L2_BUF_TYPE_SDR_CAPTURE: +		if (unlikely(!is_rx || !ops->vidioc_enum_fmt_sdr_cap)) +			break; +		return ops->vidioc_enum_fmt_sdr_cap(file, fh, arg);  	}  	return -EINVAL;  } @@ -1056,6 +1086,7 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,  	struct v4l2_format *p = arg;  	struct video_device *vfd = video_devdata(file);  	bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER; +	bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;  	bool is_rx = vfd->vfl_dir != VFL_DIR_TX;  	bool is_tx = vfd->vfl_dir != VFL_DIR_RX; @@ -1100,6 +1131,10 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,  		if (unlikely(!is_tx || is_vid || !ops->vidioc_g_fmt_sliced_vbi_out))  			break;  		return ops->vidioc_g_fmt_sliced_vbi_out(file, fh, arg); +	case V4L2_BUF_TYPE_SDR_CAPTURE: +		if (unlikely(!is_rx || !is_sdr || !ops->vidioc_g_fmt_sdr_cap)) +			break; +		return ops->vidioc_g_fmt_sdr_cap(file, fh, arg);  	}  	return -EINVAL;  } @@ -1110,6 +1145,7 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,  	struct v4l2_format *p = arg;  	struct video_device *vfd = video_devdata(file);  	bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER; +	bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;  	bool is_rx = vfd->vfl_dir != VFL_DIR_TX;  	bool is_tx = vfd->vfl_dir != VFL_DIR_RX; @@ -1164,6 +1200,11 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,  			break;  		CLEAR_AFTER_FIELD(p, fmt.sliced);  		return ops->vidioc_s_fmt_sliced_vbi_out(file, fh, arg); +	case V4L2_BUF_TYPE_SDR_CAPTURE: +		if (unlikely(!is_rx || !is_sdr || !ops->vidioc_s_fmt_sdr_cap)) +			break; +		CLEAR_AFTER_FIELD(p, fmt.sdr); +		return ops->vidioc_s_fmt_sdr_cap(file, fh, arg);  	}  	return -EINVAL;  } @@ -1174,6 +1215,7 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops,  	struct v4l2_format *p = arg;  	struct video_device *vfd = video_devdata(file);  	bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER; +	bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;  	bool is_rx = vfd->vfl_dir != VFL_DIR_TX;  	bool is_tx = vfd->vfl_dir != VFL_DIR_RX; @@ -1228,6 +1270,11 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops,  			break;  		CLEAR_AFTER_FIELD(p, fmt.sliced);  		return ops->vidioc_try_fmt_sliced_vbi_out(file, fh, arg); +	case V4L2_BUF_TYPE_SDR_CAPTURE: +		if (unlikely(!is_rx || !is_sdr || !ops->vidioc_try_fmt_sdr_cap)) +			break; +		CLEAR_AFTER_FIELD(p, fmt.sdr); +		return ops->vidioc_try_fmt_sdr_cap(file, fh, arg);  	}  	return -EINVAL;  } @@ -1288,8 +1335,11 @@ static int v4l_g_frequency(const struct v4l2_ioctl_ops *ops,  	struct video_device *vfd = video_devdata(file);  	struct v4l2_frequency *p = arg; -	p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ? -			V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; +	if (vfd->vfl_type == VFL_TYPE_SDR) +		p->type = V4L2_TUNER_ADC; +	else +		p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ? +				V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;  	return ops->vidioc_g_frequency(file, fh, p);  } @@ -1300,10 +1350,15 @@ static int v4l_s_frequency(const struct v4l2_ioctl_ops *ops,  	const struct v4l2_frequency *p = arg;  	enum v4l2_tuner_type type; -	type = (vfd->vfl_type == VFL_TYPE_RADIO) ? -			V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; -	if (p->type != type) -		return -EINVAL; +	if (vfd->vfl_type == VFL_TYPE_SDR) { +		if (p->type != V4L2_TUNER_ADC && p->type != V4L2_TUNER_RF) +			return -EINVAL; +	} else { +		type = (vfd->vfl_type == VFL_TYPE_RADIO) ? +				V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; +		if (type != p->type) +			return -EINVAL; +	}  	return ops->vidioc_s_frequency(file, fh, p);  } @@ -1383,6 +1438,10 @@ static int v4l_s_hw_freq_seek(const struct v4l2_ioctl_ops *ops,  	struct v4l2_hw_freq_seek *p = arg;  	enum v4l2_tuner_type type; +	/* s_hw_freq_seek is not supported for SDR for now */ +	if (vfd->vfl_type == VFL_TYPE_SDR) +		return -EINVAL; +  	type = (vfd->vfl_type == VFL_TYPE_RADIO) ?  		V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;  	if (p->type != type) @@ -1882,11 +1941,16 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops,  	enum v4l2_tuner_type type;  	int err; -	type = (vfd->vfl_type == VFL_TYPE_RADIO) ? -			V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - -	if (type != p->type) -		return -EINVAL; +	if (vfd->vfl_type == VFL_TYPE_SDR) { +		if (p->type != V4L2_TUNER_ADC && p->type != V4L2_TUNER_RF) +			return -EINVAL; +		type = p->type; +	} else { +		type = (vfd->vfl_type == VFL_TYPE_RADIO) ? +				V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; +		if (type != p->type) +			return -EINVAL; +	}  	if (ops->vidioc_enum_freq_bands)  		return ops->vidioc_enum_freq_bands(file, fh, p);  	if (is_valid_ioctl(vfd, VIDIOC_G_TUNER)) { @@ -2006,6 +2070,8 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = {  	IOCTL_INFO_FNC(VIDIOC_QUERYMENU, v4l_querymenu, v4l_print_querymenu, INFO_FL_CTRL | INFO_FL_CLEAR(v4l2_querymenu, index)),  	IOCTL_INFO_STD(VIDIOC_G_INPUT, vidioc_g_input, v4l_print_u32, 0),  	IOCTL_INFO_FNC(VIDIOC_S_INPUT, v4l_s_input, v4l_print_u32, INFO_FL_PRIO), +	IOCTL_INFO_STD(VIDIOC_G_EDID, vidioc_g_edid, v4l_print_edid, INFO_FL_CLEAR(v4l2_edid, edid)), +	IOCTL_INFO_STD(VIDIOC_S_EDID, vidioc_s_edid, v4l_print_edid, INFO_FL_PRIO | INFO_FL_CLEAR(v4l2_edid, edid)),  	IOCTL_INFO_STD(VIDIOC_G_OUTPUT, vidioc_g_output, v4l_print_u32, 0),  	IOCTL_INFO_FNC(VIDIOC_S_OUTPUT, v4l_s_output, v4l_print_u32, INFO_FL_PRIO),  	IOCTL_INFO_FNC(VIDIOC_ENUMOUTPUT, v4l_enumoutput, v4l_print_enumoutput, INFO_FL_CLEAR(v4l2_output, index)), @@ -2194,7 +2260,7 @@ done:  }  static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, -			    void * __user *user_ptr, void ***kernel_ptr) +			    void __user **user_ptr, void ***kernel_ptr)  {  	int ret = 0; @@ -2211,16 +2277,16 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,  				break;  			}  			*user_ptr = (void __user *)buf->m.planes; -			*kernel_ptr = (void *)&buf->m.planes; +			*kernel_ptr = (void **)&buf->m.planes;  			*array_size = sizeof(struct v4l2_plane) * buf->length;  			ret = 1;  		}  		break;  	} -	case VIDIOC_SUBDEV_G_EDID: -	case VIDIOC_SUBDEV_S_EDID: { -		struct v4l2_subdev_edid *edid = parg; +	case VIDIOC_G_EDID: +	case VIDIOC_S_EDID: { +		struct v4l2_edid *edid = parg;  		if (edid->blocks) {  			if (edid->blocks > 256) { @@ -2228,7 +2294,7 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,  				break;  			}  			*user_ptr = (void __user *)edid->edid; -			*kernel_ptr = (void *)&edid->edid; +			*kernel_ptr = (void **)&edid->edid;  			*array_size = edid->blocks * 128;  			ret = 1;  		} @@ -2246,7 +2312,7 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,  				break;  			}  			*user_ptr = (void __user *)ctrls->controls; -			*kernel_ptr = (void *)&ctrls->controls; +			*kernel_ptr = (void **)&ctrls->controls;  			*array_size = sizeof(struct v4l2_ext_control)  				    * ctrls->count;  			ret = 1; @@ -2338,9 +2404,15 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,  	err = func(file, cmd, parg);  	if (err == -ENOIOCTLCMD)  		err = -ENOTTY; +	if (err == 0) { +		if (cmd == VIDIOC_DQBUF) +			trace_v4l2_dqbuf(video_devdata(file)->minor, parg); +		else if (cmd == VIDIOC_QBUF) +			trace_v4l2_qbuf(video_devdata(file)->minor, parg); +	}  	if (has_array_args) { -		*kernel_ptr = user_ptr; +		*kernel_ptr = (void __force *)user_ptr;  		if (copy_to_user(user_ptr, mbuf, array_size))  			err = -EFAULT;  		goto out_array_args;  | 
