diff options
Diffstat (limited to 'drivers/media/v4l2-core/v4l2-ioctl.c')
| -rw-r--r-- | drivers/media/v4l2-core/v4l2-ioctl.c | 219 | 
1 files changed, 141 insertions, 78 deletions
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index aa6e7c788db..f81bda1a48e 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -35,6 +35,8 @@  	memset((u8 *)(p) + offsetof(typeof(*(p)), field) + sizeof((p)->field), \  	0, sizeof(*(p)) - offsetof(typeof(*(p)), field) - sizeof((p)->field)) +#define is_valid_ioctl(vfd, cmd) test_bit(_IOC_NR(cmd), (vfd)->valid_ioctls) +  struct std_descr {  	v4l2_std_id std;  	const char *descr; @@ -167,9 +169,11 @@ static void v4l_print_querycap(const void *arg, bool write_only)  {  	const struct v4l2_capability *p = arg; -	pr_cont("driver=%s, card=%s, bus=%s, version=0x%08x, " +	pr_cont("driver=%.*s, card=%.*s, bus=%.*s, version=0x%08x, "  		"capabilities=0x%08x, device_caps=0x%08x\n", -		p->driver, p->card, p->bus_info, +		(int)sizeof(p->driver), p->driver, +		(int)sizeof(p->card), p->card, +		(int)sizeof(p->bus_info), p->bus_info,  		p->version, p->capabilities, p->device_caps);  } @@ -177,20 +181,21 @@ static void v4l_print_enuminput(const void *arg, bool write_only)  {  	const struct v4l2_input *p = arg; -	pr_cont("index=%u, name=%s, type=%u, audioset=0x%x, tuner=%u, " +	pr_cont("index=%u, name=%.*s, type=%u, audioset=0x%x, tuner=%u, "  		"std=0x%08Lx, status=0x%x, capabilities=0x%x\n", -		p->index, p->name, p->type, p->audioset, p->tuner, -		(unsigned long long)p->std, p->status, p->capabilities); +		p->index, (int)sizeof(p->name), p->name, p->type, p->audioset, +		p->tuner, (unsigned long long)p->std, p->status, +		p->capabilities);  }  static void v4l_print_enumoutput(const void *arg, bool write_only)  {  	const struct v4l2_output *p = arg; -	pr_cont("index=%u, name=%s, type=%u, audioset=0x%x, " +	pr_cont("index=%u, name=%.*s, type=%u, audioset=0x%x, "  		"modulator=%u, std=0x%08Lx, capabilities=0x%x\n", -		p->index, p->name, p->type, p->audioset, p->modulator, -		(unsigned long long)p->std, p->capabilities); +		p->index, (int)sizeof(p->name), p->name, p->type, p->audioset, +		p->modulator, (unsigned long long)p->std, p->capabilities);  }  static void v4l_print_audio(const void *arg, bool write_only) @@ -200,8 +205,9 @@ static void v4l_print_audio(const void *arg, bool write_only)  	if (write_only)  		pr_cont("index=%u, mode=0x%x\n", p->index, p->mode);  	else -		pr_cont("index=%u, name=%s, capability=0x%x, mode=0x%x\n", -			p->index, p->name, p->capability, p->mode); +		pr_cont("index=%u, name=%.*s, capability=0x%x, mode=0x%x\n", +			p->index, (int)sizeof(p->name), p->name, +			p->capability, p->mode);  }  static void v4l_print_audioout(const void *arg, bool write_only) @@ -211,21 +217,22 @@ static void v4l_print_audioout(const void *arg, bool write_only)  	if (write_only)  		pr_cont("index=%u\n", p->index);  	else -		pr_cont("index=%u, name=%s, capability=0x%x, mode=0x%x\n", -			p->index, p->name, p->capability, p->mode); +		pr_cont("index=%u, name=%.*s, capability=0x%x, mode=0x%x\n", +			p->index, (int)sizeof(p->name), p->name, +			p->capability, p->mode);  }  static void v4l_print_fmtdesc(const void *arg, bool write_only)  {  	const struct v4l2_fmtdesc *p = arg; -	pr_cont("index=%u, type=%s, flags=0x%x, pixelformat=%c%c%c%c, description='%s'\n", +	pr_cont("index=%u, type=%s, flags=0x%x, pixelformat=%c%c%c%c, description='%.*s'\n",  		p->index, prt_names(p->type, v4l2_type_names),  		p->flags, (p->pixelformat & 0xff),  		(p->pixelformat >>  8) & 0xff,  		(p->pixelformat >> 16) & 0xff,  		(p->pixelformat >> 24) & 0xff, -		p->description); +		(int)sizeof(p->description), p->description);  }  static void v4l_print_format(const void *arg, bool write_only) @@ -348,9 +355,9 @@ static void v4l_print_modulator(const void *arg, bool write_only)  	if (write_only)  		pr_cont("index=%u, txsubchans=0x%x", p->index, p->txsubchans);  	else -		pr_cont("index=%u, name=%s, capability=0x%x, " +		pr_cont("index=%u, name=%.*s, capability=0x%x, "  			"rangelow=%u, rangehigh=%u, txsubchans=0x%x\n", -			p->index, p->name, p->capability, +			p->index, (int)sizeof(p->name), p->name, p->capability,  			p->rangelow, p->rangehigh, p->txsubchans);  } @@ -361,10 +368,10 @@ static void v4l_print_tuner(const void *arg, bool write_only)  	if (write_only)  		pr_cont("index=%u, audmode=%u\n", p->index, p->audmode);  	else -		pr_cont("index=%u, name=%s, type=%u, capability=0x%x, " +		pr_cont("index=%u, name=%.*s, type=%u, capability=0x%x, "  			"rangelow=%u, rangehigh=%u, signal=%u, afc=%d, "  			"rxsubchans=0x%x, audmode=%u\n", -			p->index, p->name, p->type, +			p->index, (int)sizeof(p->name), p->name, p->type,  			p->capability, p->rangelow,  			p->rangehigh, p->signal, p->afc,  			p->rxsubchans, p->audmode); @@ -382,9 +389,9 @@ static void v4l_print_standard(const void *arg, bool write_only)  {  	const struct v4l2_standard *p = arg; -	pr_cont("index=%u, id=0x%Lx, name=%s, fps=%u/%u, " +	pr_cont("index=%u, id=0x%Lx, name=%.*s, fps=%u/%u, "  		"framelines=%u\n", p->index, -		(unsigned long long)p->id, p->name, +		(unsigned long long)p->id, (int)sizeof(p->name), p->name,  		p->frameperiod.numerator,  		p->frameperiod.denominator,  		p->framelines); @@ -504,9 +511,9 @@ static void v4l_print_queryctrl(const void *arg, bool write_only)  {  	const struct v4l2_queryctrl *p = arg; -	pr_cont("id=0x%x, type=%d, name=%s, min/max=%d/%d, " +	pr_cont("id=0x%x, type=%d, name=%.*s, min/max=%d/%d, "  		"step=%d, default=%d, flags=0x%08x\n", -			p->id, p->type, p->name, +			p->id, p->type, (int)sizeof(p->name), p->name,  			p->minimum, p->maximum,  			p->step, p->default_value, p->flags);  } @@ -623,39 +630,39 @@ static void v4l_print_dbg_chip_ident(const void *arg, bool write_only)  	pr_cont("type=%u, ", p->match.type);  	if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER) -		pr_cont("name=%s, ", p->match.name); +		pr_cont("name=%.*s, ", +				(int)sizeof(p->match.name), p->match.name);  	else  		pr_cont("addr=%u, ", p->match.addr);  	pr_cont("chip_ident=%u, revision=0x%x\n",  			p->ident, p->revision);  } -static void v4l_print_dbg_register(const void *arg, bool write_only) +static void v4l_print_dbg_chip_info(const void *arg, bool write_only)  { -	const struct v4l2_dbg_register *p = arg; +	const struct v4l2_dbg_chip_info *p = arg;  	pr_cont("type=%u, ", p->match.type);  	if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER) -		pr_cont("name=%s, ", p->match.name); +		pr_cont("name=%.*s, ", +				(int)sizeof(p->match.name), p->match.name);  	else  		pr_cont("addr=%u, ", p->match.addr); -	pr_cont("reg=0x%llx, val=0x%llx\n", -			p->reg, p->val); +	pr_cont("name=%.*s\n", (int)sizeof(p->name), p->name);  } -static void v4l_print_dv_enum_presets(const void *arg, bool write_only) -{ -	const struct v4l2_dv_enum_preset *p = arg; - -	pr_cont("index=%u, preset=%u, name=%s, width=%u, height=%u\n", -			p->index, p->preset, p->name, p->width, p->height); -} - -static void v4l_print_dv_preset(const void *arg, bool write_only) +static void v4l_print_dbg_register(const void *arg, bool write_only)  { -	const struct v4l2_dv_preset *p = arg; +	const struct v4l2_dbg_register *p = arg; -	pr_cont("preset=%u\n", p->preset); +	pr_cont("type=%u, ", p->match.type); +	if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER) +		pr_cont("name=%.*s, ", +				(int)sizeof(p->match.name), p->match.name); +	else +		pr_cont("addr=%u, ", p->match.addr); +	pr_cont("reg=0x%llx, val=0x%llx\n", +			p->reg, p->val);  }  static void v4l_print_dv_timings(const void *arg, bool write_only) @@ -997,20 +1004,17 @@ static int v4l_s_priority(const struct v4l2_ioctl_ops *ops,  static int v4l_enuminput(const struct v4l2_ioctl_ops *ops,  				struct file *file, void *fh, void *arg)  { +	struct video_device *vfd = video_devdata(file);  	struct v4l2_input *p = arg;  	/* -	 * We set the flags for CAP_PRESETS, CAP_DV_TIMINGS & +	 * We set the flags for CAP_DV_TIMINGS &  	 * CAP_STD here based on ioctl handler provided by the  	 * driver. If the driver doesn't support these  	 * for a specific input, it must override these flags.  	 */ -	if (ops->vidioc_s_std) +	if (is_valid_ioctl(vfd, VIDIOC_S_STD))  		p->capabilities |= V4L2_IN_CAP_STD; -	if (ops->vidioc_s_dv_preset) -		p->capabilities |= V4L2_IN_CAP_PRESETS; -	if (ops->vidioc_s_dv_timings) -		p->capabilities |= V4L2_IN_CAP_DV_TIMINGS;  	return ops->vidioc_enum_input(file, fh, p);  } @@ -1018,20 +1022,17 @@ static int v4l_enuminput(const struct v4l2_ioctl_ops *ops,  static int v4l_enumoutput(const struct v4l2_ioctl_ops *ops,  				struct file *file, void *fh, void *arg)  { +	struct video_device *vfd = video_devdata(file);  	struct v4l2_output *p = arg;  	/* -	 * We set the flags for CAP_PRESETS, CAP_DV_TIMINGS & +	 * We set the flags for CAP_DV_TIMINGS &  	 * CAP_STD here based on ioctl handler provided by the  	 * driver. If the driver doesn't support these  	 * for a specific output, it must override these flags.  	 */ -	if (ops->vidioc_s_std) +	if (is_valid_ioctl(vfd, VIDIOC_S_STD))  		p->capabilities |= V4L2_OUT_CAP_STD; -	if (ops->vidioc_s_dv_preset) -		p->capabilities |= V4L2_OUT_CAP_PRESETS; -	if (ops->vidioc_s_dv_timings) -		p->capabilities |= V4L2_OUT_CAP_DV_TIMINGS;  	return ops->vidioc_enum_output(file, fh, p);  } @@ -1316,7 +1317,7 @@ static int v4l_s_frequency(const struct v4l2_ioctl_ops *ops,  				struct file *file, void *fh, void *arg)  {  	struct video_device *vfd = video_devdata(file); -	struct v4l2_frequency *p = arg; +	const struct v4l2_frequency *p = arg;  	enum v4l2_tuner_type type;  	type = (vfd->vfl_type == VFL_TYPE_RADIO) ? @@ -1383,15 +1384,15 @@ static int v4l_s_std(const struct v4l2_ioctl_ops *ops,  				struct file *file, void *fh, void *arg)  {  	struct video_device *vfd = video_devdata(file); -	v4l2_std_id *id = arg, norm; +	v4l2_std_id id = *(v4l2_std_id *)arg, norm;  	int ret; -	norm = (*id) & vfd->tvnorms; +	norm = id & vfd->tvnorms;  	if (vfd->tvnorms && !norm)	/* Check if std is supported */  		return -EINVAL;  	/* Calls the specific handler */ -	ret = ops->vidioc_s_std(file, fh, &norm); +	ret = ops->vidioc_s_std(file, fh, norm);  	/* Updates standard information */  	if (ret >= 0) @@ -1513,7 +1514,7 @@ static int v4l_g_parm(const struct v4l2_ioctl_ops *ops,  	    p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)  		return -EINVAL;  	p->parm.capture.readbuffers = 2; -	if (ops->vidioc_g_std) +	if (is_valid_ioctl(vfd, VIDIOC_G_STD) && ops->vidioc_g_std)  		ret = ops->vidioc_g_std(file, fh, &std);  	if (ret == 0)  		v4l2_video_std_frame_period(std, @@ -1792,10 +1793,23 @@ static int v4l_dbg_g_register(const struct v4l2_ioctl_ops *ops,  {  #ifdef CONFIG_VIDEO_ADV_DEBUG  	struct v4l2_dbg_register *p = arg; +	struct video_device *vfd = video_devdata(file); +	struct v4l2_subdev *sd; +	int idx = 0;  	if (!capable(CAP_SYS_ADMIN))  		return -EPERM; -	return ops->vidioc_g_register(file, fh, p); +	if (p->match.type == V4L2_CHIP_MATCH_SUBDEV) { +		if (vfd->v4l2_dev == NULL) +			return -EINVAL; +		v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) +			if (p->match.addr == idx++) +				return v4l2_subdev_call(sd, core, g_register, p); +		return -EINVAL; +	} +	if (ops->vidioc_g_register) +		return ops->vidioc_g_register(file, fh, p); +	return -EINVAL;  #else  	return -ENOTTY;  #endif @@ -1805,11 +1819,24 @@ static int v4l_dbg_s_register(const struct v4l2_ioctl_ops *ops,  				struct file *file, void *fh, void *arg)  {  #ifdef CONFIG_VIDEO_ADV_DEBUG -	struct v4l2_dbg_register *p = arg; +	const struct v4l2_dbg_register *p = arg; +	struct video_device *vfd = video_devdata(file); +	struct v4l2_subdev *sd; +	int idx = 0;  	if (!capable(CAP_SYS_ADMIN))  		return -EPERM; -	return ops->vidioc_s_register(file, fh, p); +	if (p->match.type == V4L2_CHIP_MATCH_SUBDEV) { +		if (vfd->v4l2_dev == NULL) +			return -EINVAL; +		v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) +			if (p->match.addr == idx++) +				return v4l2_subdev_call(sd, core, s_register, p); +		return -EINVAL; +	} +	if (ops->vidioc_s_register) +		return ops->vidioc_s_register(file, fh, p); +	return -EINVAL;  #else  	return -ENOTTY;  #endif @@ -1822,9 +1849,59 @@ static int v4l_dbg_g_chip_ident(const struct v4l2_ioctl_ops *ops,  	p->ident = V4L2_IDENT_NONE;  	p->revision = 0; +	if (p->match.type == V4L2_CHIP_MATCH_SUBDEV) +		return -EINVAL;  	return ops->vidioc_g_chip_ident(file, fh, p);  } +static int v4l_dbg_g_chip_info(const struct v4l2_ioctl_ops *ops, +				struct file *file, void *fh, void *arg) +{ +#ifdef CONFIG_VIDEO_ADV_DEBUG +	struct video_device *vfd = video_devdata(file); +	struct v4l2_dbg_chip_info *p = arg; +	struct v4l2_subdev *sd; +	int idx = 0; + +	switch (p->match.type) { +	case V4L2_CHIP_MATCH_BRIDGE: +		if (ops->vidioc_s_register) +			p->flags |= V4L2_CHIP_FL_WRITABLE; +		if (ops->vidioc_g_register) +			p->flags |= V4L2_CHIP_FL_READABLE; +		if (vfd->v4l2_dev) +			strlcpy(p->name, vfd->v4l2_dev->name, sizeof(p->name)); +		else if (vfd->parent) +			strlcpy(p->name, vfd->parent->driver->name, sizeof(p->name)); +		else +			strlcpy(p->name, "bridge", sizeof(p->name)); +		if (ops->vidioc_g_chip_info) +			return ops->vidioc_g_chip_info(file, fh, arg); +		if (p->match.addr) +			return -EINVAL; +		return 0; + +	case V4L2_CHIP_MATCH_SUBDEV: +		if (vfd->v4l2_dev == NULL) +			break; +		v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) { +			if (p->match.addr != idx++) +				continue; +			if (sd->ops->core && sd->ops->core->s_register) +				p->flags |= V4L2_CHIP_FL_WRITABLE; +			if (sd->ops->core && sd->ops->core->g_register) +				p->flags |= V4L2_CHIP_FL_READABLE; +			strlcpy(p->name, sd->name, sizeof(p->name)); +			return 0; +		} +		break; +	} +	return -EINVAL; +#else +	return -ENOTTY; +#endif +} +  static int v4l_dqevent(const struct v4l2_ioctl_ops *ops,  				struct file *file, void *fh, void *arg)  { @@ -1873,7 +1950,7 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops,  		return -EINVAL;  	if (ops->vidioc_enum_freq_bands)  		return ops->vidioc_enum_freq_bands(file, fh, p); -	if (ops->vidioc_g_tuner) { +	if (is_valid_ioctl(vfd, VIDIOC_G_TUNER)) {  		struct v4l2_tuner t = {  			.index = p->tuner,  			.type = type, @@ -1891,7 +1968,7 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops,  			V4L2_BAND_MODULATION_FM : V4L2_BAND_MODULATION_VSB;  		return 0;  	} -	if (ops->vidioc_g_modulator) { +	if (is_valid_ioctl(vfd, VIDIOC_G_MODULATOR)) {  		struct v4l2_modulator m = {  			.index = p->tuner,  		}; @@ -2028,10 +2105,6 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = {  	IOCTL_INFO_FNC(VIDIOC_DBG_G_REGISTER, v4l_dbg_g_register, v4l_print_dbg_register, 0),  	IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_IDENT, v4l_dbg_g_chip_ident, v4l_print_dbg_chip_ident, 0),  	IOCTL_INFO_FNC(VIDIOC_S_HW_FREQ_SEEK, v4l_s_hw_freq_seek, v4l_print_hw_freq_seek, INFO_FL_PRIO), -	IOCTL_INFO_STD(VIDIOC_ENUM_DV_PRESETS, vidioc_enum_dv_presets, v4l_print_dv_enum_presets, 0), -	IOCTL_INFO_STD(VIDIOC_S_DV_PRESET, vidioc_s_dv_preset, v4l_print_dv_preset, INFO_FL_PRIO), -	IOCTL_INFO_STD(VIDIOC_G_DV_PRESET, vidioc_g_dv_preset, v4l_print_dv_preset, 0), -	IOCTL_INFO_STD(VIDIOC_QUERY_DV_PRESET, vidioc_query_dv_preset, v4l_print_dv_preset, 0),  	IOCTL_INFO_STD(VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings, v4l_print_dv_timings, INFO_FL_PRIO),  	IOCTL_INFO_STD(VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings, v4l_print_dv_timings, 0),  	IOCTL_INFO_FNC(VIDIOC_DQEVENT, v4l_dqevent, v4l_print_event, 0), @@ -2043,6 +2116,7 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = {  	IOCTL_INFO_STD(VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings, v4l_print_dv_timings, 0),  	IOCTL_INFO_STD(VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap, v4l_print_dv_timings_cap, INFO_FL_CLEAR(v4l2_dv_timings_cap, type)),  	IOCTL_INFO_FNC(VIDIOC_ENUM_FREQ_BANDS, v4l_enum_freq_bands, v4l_print_freq_band, 0), +	IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_INFO, v4l_dbg_g_chip_info, v4l_print_dbg_chip_info, INFO_FL_CLEAR(v4l2_dbg_chip_info, match)),  };  #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) @@ -2147,11 +2221,6 @@ static long __video_do_ioctl(struct file *file,  	}  	write_only = _IOC_DIR(cmd) == _IOC_WRITE; -	if (write_only && debug > V4L2_DEBUG_IOCTL) { -		v4l_printk_ioctl(video_device_node_name(vfd), cmd); -		pr_cont(": "); -		info->debug(arg, write_only); -	}  	if (info->flags & INFO_FL_STD) {  		typedef int (*vidioc_op)(struct file *file, void *fh, void *p);  		const void *p = vfd->ioctl_ops; @@ -2170,16 +2239,10 @@ static long __video_do_ioctl(struct file *file,  done:  	if (debug) { -		if (write_only && debug > V4L2_DEBUG_IOCTL) { -			if (ret < 0) -				printk(KERN_DEBUG "%s: error %ld\n", -					video_device_node_name(vfd), ret); -			return ret; -		}  		v4l_printk_ioctl(video_device_node_name(vfd), cmd);  		if (ret < 0) -			pr_cont(": error %ld\n", ret); -		else if (debug == V4L2_DEBUG_IOCTL) +			pr_cont(": error %ld", ret); +		if (debug == V4L2_DEBUG_IOCTL)  			pr_cont("\n");  		else if (_IOC_DIR(cmd) == _IOC_NONE)  			info->debug(arg, write_only);  |