From 79b0c6400517456935f84f8d46c8bb0cf73f1813 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 18 Mar 2013 12:16:34 -0300 Subject: [media] v4l2: add new VIDIOC_DBG_G_CHIP_NAME ioctl Simplify the debugging ioctls by creating the VIDIOC_DBG_G_CHIP_NAME ioctl. This will eventually replace VIDIOC_DBG_G_CHIP_IDENT. Chip matching is done by the name or index of subdevices or an index to a bridge chip. Most of this can all be done automatically, so most drivers just need to provide get/set register ops. In particular, it is now possible to get/set subdev registers without requiring assistance of the bridge driver. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-common.c | 5 +- drivers/media/v4l2-core/v4l2-dev.c | 5 +- drivers/media/v4l2-core/v4l2-ioctl.c | 115 ++++++++++++++++++++++++++++++++-- 3 files changed, 118 insertions(+), 7 deletions(-) (limited to 'drivers/media/v4l2-core') diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index a9e7703560ad..f8fac9cefc3c 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -230,7 +230,7 @@ EXPORT_SYMBOL(v4l2_ctrl_next); int v4l2_chip_match_host(const struct v4l2_dbg_match *match) { switch (match->type) { - case V4L2_CHIP_MATCH_HOST: + case V4L2_CHIP_MATCH_BRIDGE: return match->addr == 0; default: return 0; @@ -254,6 +254,9 @@ int v4l2_chip_match_i2c_client(struct i2c_client *c, const struct v4l2_dbg_match return len && !strncmp(c->driver->driver.name, match->name, len); case V4L2_CHIP_MATCH_I2C_ADDR: return c->addr == match->addr; + case V4L2_CHIP_MATCH_SUBDEV_IDX: + case V4L2_CHIP_MATCH_SUBDEV_NAME: + return 1; default: return 0; } diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 1fbd95755e75..670b9ca8ecbe 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -591,9 +591,10 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_G_FREQUENCY, vidioc_g_frequency); SET_VALID_IOCTL(ops, VIDIOC_S_FREQUENCY, vidioc_s_frequency); SET_VALID_IOCTL(ops, VIDIOC_LOG_STATUS, vidioc_log_status); + set_bit(_IOC_NR(VIDIOC_DBG_G_CHIP_NAME), valid_ioctls); #ifdef CONFIG_VIDEO_ADV_DEBUG - SET_VALID_IOCTL(ops, VIDIOC_DBG_G_REGISTER, vidioc_g_register); - SET_VALID_IOCTL(ops, VIDIOC_DBG_S_REGISTER, vidioc_s_register); + set_bit(_IOC_NR(VIDIOC_DBG_G_REGISTER), valid_ioctls); + set_bit(_IOC_NR(VIDIOC_DBG_S_REGISTER), valid_ioctls); #endif SET_VALID_IOCTL(ops, VIDIOC_DBG_G_CHIP_IDENT, vidioc_g_chip_ident); /* yes, really vidioc_subscribe_event */ diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 83aa39dfe07c..336ed2dd607c 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -629,7 +629,8 @@ static void v4l_print_dbg_chip_ident(const void *arg, bool write_only) const struct v4l2_dbg_chip_ident *p = arg; pr_cont("type=%u, ", p->match.type); - if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER) + if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER || + p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) pr_cont("name=%.*s, ", (int)sizeof(p->match.name), p->match.name); else @@ -638,12 +639,27 @@ static void v4l_print_dbg_chip_ident(const void *arg, bool write_only) p->ident, p->revision); } +static void v4l_print_dbg_chip_name(const void *arg, bool write_only) +{ + const struct v4l2_dbg_chip_name *p = arg; + + pr_cont("type=%u, ", p->match.type); + if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER || + p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) + pr_cont("name=%.*s, ", + (int)sizeof(p->match.name), p->match.name); + else + pr_cont("addr=%u, ", p->match.addr); + pr_cont("name=%.*s\n", (int)sizeof(p->name), p->name); +} + static void v4l_print_dbg_register(const void *arg, bool write_only) { const struct v4l2_dbg_register *p = arg; pr_cont("type=%u, ", p->match.type); - if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER) + if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER || + p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) pr_cont("name=%.*s, ", (int)sizeof(p->match.name), p->match.name); else @@ -1775,15 +1791,38 @@ static int v4l_log_status(const struct v4l2_ioctl_ops *ops, return ret; } +static bool v4l_dbg_found_match(const struct v4l2_dbg_match *match, + struct v4l2_subdev *sd, int idx) +{ + if (match->type == V4L2_CHIP_MATCH_SUBDEV_IDX) + return match->addr == idx; + return !strcmp(match->name, sd->name); +} + static int v4l_dbg_g_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; + 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_IDX || + p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) { + if (vfd->v4l2_dev == NULL) + return -EINVAL; + v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) { + if (v4l_dbg_found_match(&p->match, sd, 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 @@ -1794,10 +1833,25 @@ static int v4l_dbg_s_register(const struct v4l2_ioctl_ops *ops, { #ifdef CONFIG_VIDEO_ADV_DEBUG 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_IDX || + p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) { + if (vfd->v4l2_dev == NULL) + return -EINVAL; + v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) { + if (v4l_dbg_found_match(&p->match, sd, 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 @@ -1810,9 +1864,61 @@ 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_NAME || + p->match.type == V4L2_CHIP_MATCH_SUBDEV_IDX) + return -EINVAL; return ops->vidioc_g_chip_ident(file, fh, p); } +static int v4l_dbg_g_chip_name(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + struct v4l2_dbg_chip_name *p = arg; + struct v4l2_subdev *sd; + int idx = 0; + + switch (p->match.type) { + case V4L2_CHIP_MATCH_BRIDGE: +#ifdef CONFIG_VIDEO_ADV_DEBUG + if (ops->vidioc_s_register) + p->flags |= V4L2_CHIP_FL_WRITABLE; + if (ops->vidioc_g_register) + p->flags |= V4L2_CHIP_FL_READABLE; +#endif + if (ops->vidioc_g_chip_name) + return ops->vidioc_g_chip_name(file, fh, arg); + if (p->match.addr) + return -EINVAL; + 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)); + return 0; + + case V4L2_CHIP_MATCH_SUBDEV_IDX: + case V4L2_CHIP_MATCH_SUBDEV_NAME: + if (vfd->v4l2_dev == NULL) + break; + v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) { + if (v4l_dbg_found_match(&p->match, sd, idx++)) { +#ifdef CONFIG_VIDEO_ADV_DEBUG + 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; +#endif + strlcpy(p->name, sd->name, sizeof(p->name)); + return 0; + } + } + break; + } + return -EINVAL; +} + static int v4l_dqevent(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { @@ -2027,6 +2133,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_NAME, v4l_dbg_g_chip_name, v4l_print_dbg_chip_name, INFO_FL_CLEAR(v4l2_dbg_chip_name, match)), }; #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) -- cgit v1.2.3