]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
media: i2c: adv7604: export InfoFrames to debugfs
authorHans Verkuil <hverkuil-cisco@xs4all.nl>
Wed, 28 Aug 2024 14:24:10 +0000 (16:24 +0200)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Sat, 12 Oct 2024 08:44:05 +0000 (10:44 +0200)
Export InfoFrames to debugfs.

Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Tested-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
drivers/media/i2c/adv7604.c

index 48230d5109f054d302fc75992183a9dbb4a2bf5a..3184a2fa15322caa2a8eb415bea14312690b839c 100644 (file)
@@ -193,6 +193,9 @@ struct adv76xx_state {
        struct delayed_work delayed_work_enable_hotplug;
        bool restart_stdi_once;
 
+       struct dentry *debugfs_dir;
+       struct v4l2_debugfs_if *infoframes;
+
        /* CEC */
        struct cec_adapter *cec_adap;
        u8   cec_addr[ADV76XX_MAX_ADDRS];
@@ -2458,10 +2461,9 @@ static const struct adv76xx_cfg_read_infoframe adv76xx_cri[] = {
        { "Vendor", 0x10, 0xec, 0x54 }
 };
 
-static int adv76xx_read_infoframe(struct v4l2_subdev *sd, int index,
-                                 union hdmi_infoframe *frame)
+static int adv76xx_read_infoframe_buf(struct v4l2_subdev *sd, int index,
+                                     u8 buf[V4L2_DEBUGFS_IF_MAX_LEN])
 {
-       uint8_t buffer[32];
        u8 len;
        int i;
 
@@ -2472,27 +2474,20 @@ static int adv76xx_read_infoframe(struct v4l2_subdev *sd, int index,
        }
 
        for (i = 0; i < 3; i++)
-               buffer[i] = infoframe_read(sd,
-                                          adv76xx_cri[index].head_addr + i);
+               buf[i] = infoframe_read(sd, adv76xx_cri[index].head_addr + i);
 
-       len = buffer[2] + 1;
+       len = buf[2] + 1;
 
-       if (len + 3 > sizeof(buffer)) {
+       if (len + 3 > V4L2_DEBUGFS_IF_MAX_LEN) {
                v4l2_err(sd, "%s: invalid %s infoframe length %d\n", __func__,
                         adv76xx_cri[index].desc, len);
                return -ENOENT;
        }
 
        for (i = 0; i < len; i++)
-               buffer[i + 3] = infoframe_read(sd,
-                                      adv76xx_cri[index].payload_addr + i);
-
-       if (hdmi_infoframe_unpack(frame, buffer, len + 3) < 0) {
-               v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__,
-                        adv76xx_cri[index].desc);
-               return -ENOENT;
-       }
-       return 0;
+               buf[i + 3] = infoframe_read(sd,
+                                           adv76xx_cri[index].payload_addr + i);
+       return len + 3;
 }
 
 static void adv76xx_log_infoframes(struct v4l2_subdev *sd)
@@ -2505,10 +2500,19 @@ static void adv76xx_log_infoframes(struct v4l2_subdev *sd)
        }
 
        for (i = 0; i < ARRAY_SIZE(adv76xx_cri); i++) {
-               union hdmi_infoframe frame;
                struct i2c_client *client = v4l2_get_subdevdata(sd);
+               u8 buffer[V4L2_DEBUGFS_IF_MAX_LEN] = {};
+               union hdmi_infoframe frame;
+               int len;
 
-               if (!adv76xx_read_infoframe(sd, i, &frame))
+               len = adv76xx_read_infoframe_buf(sd, i, buffer);
+               if (len < 0)
+                       continue;
+
+               if (hdmi_infoframe_unpack(&frame, buffer, len) < 0)
+                       v4l2_err(sd, "%s: unpack of %s infoframe failed\n",
+                                __func__, adv76xx_cri[i].desc);
+               else
                        hdmi_infoframe_log(KERN_INFO, &client->dev, &frame);
        }
 }
@@ -2686,6 +2690,41 @@ static int adv76xx_subscribe_event(struct v4l2_subdev *sd,
        }
 }
 
+static ssize_t
+adv76xx_debugfs_if_read(u32 type, void *priv, struct file *filp,
+                       char __user *ubuf, size_t count, loff_t *ppos)
+{
+       u8 buf[V4L2_DEBUGFS_IF_MAX_LEN] = {};
+       struct v4l2_subdev *sd = priv;
+       int index;
+       int len;
+
+       if (!is_hdmi(sd))
+               return 0;
+
+       switch (type) {
+       case V4L2_DEBUGFS_IF_AVI:
+               index = 0;
+               break;
+       case V4L2_DEBUGFS_IF_AUDIO:
+               index = 1;
+               break;
+       case V4L2_DEBUGFS_IF_SPD:
+               index = 2;
+               break;
+       case V4L2_DEBUGFS_IF_HDMI:
+               index = 3;
+               break;
+       default:
+               return 0;
+       }
+
+       len = adv76xx_read_infoframe_buf(sd, index, buf);
+       if (len > 0)
+               len = simple_read_from_buffer(ubuf, count, ppos, buf, len);
+       return len < 0 ? 0 : len;
+}
+
 static int adv76xx_registered(struct v4l2_subdev *sd)
 {
        struct adv76xx_state *state = to_state(sd);
@@ -2693,9 +2732,16 @@ static int adv76xx_registered(struct v4l2_subdev *sd)
        int err;
 
        err = cec_register_adapter(state->cec_adap, &client->dev);
-       if (err)
+       if (err) {
                cec_delete_adapter(state->cec_adap);
-       return err;
+               return err;
+       }
+       state->debugfs_dir = debugfs_create_dir(sd->name, v4l2_debugfs_root());
+       state->infoframes = v4l2_debugfs_if_alloc(state->debugfs_dir,
+               V4L2_DEBUGFS_IF_AVI | V4L2_DEBUGFS_IF_AUDIO |
+               V4L2_DEBUGFS_IF_SPD | V4L2_DEBUGFS_IF_HDMI, sd,
+               adv76xx_debugfs_if_read);
+       return 0;
 }
 
 static void adv76xx_unregistered(struct v4l2_subdev *sd)
@@ -2703,6 +2749,10 @@ static void adv76xx_unregistered(struct v4l2_subdev *sd)
        struct adv76xx_state *state = to_state(sd);
 
        cec_unregister_adapter(state->cec_adap);
+       v4l2_debugfs_if_free(state->infoframes);
+       state->infoframes = NULL;
+       debugfs_remove_recursive(state->debugfs_dir);
+       state->debugfs_dir = NULL;
 }
 
 /* ----------------------------------------------------------------------- */