]> Pileus Git - ~andy/linux/blobdiff - drivers/media/v4l2-core/v4l2-ioctl.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-nmw
[~andy/linux] / drivers / media / v4l2-core / v4l2-ioctl.c
index aa6e7c788db2b00ed0493c9babae92924a65b6a5..f81bda1a48ec33ce603a1f741466bac726298e21 100644 (file)
@@ -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);