]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
media: i2c: adv7511-v4l2: export InfoFrames to debugfs
authorHans Verkuil <hverkuil-cisco@xs4all.nl>
Wed, 28 Aug 2024 14:24:09 +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/adv7511-v4l2.c

index e9406d552699f8e347ec32692cbda3eed0e3b3aa..4036972af3a6628b72de0c770b13ba829742ff2f 100644 (file)
@@ -116,6 +116,9 @@ struct adv7511_state {
        unsigned edid_detect_counter;
        struct workqueue_struct *work_queue;
        struct delayed_work edid_handler; /* work entry */
+
+       struct dentry *debugfs_dir;
+       struct v4l2_debugfs_if *infoframes;
 };
 
 static void adv7511_check_monitor_present_status(struct v4l2_subdev *sd);
@@ -483,27 +486,25 @@ static u8 hdmi_infoframe_checksum(u8 *ptr, size_t size)
        return 256 - csum;
 }
 
-static void log_infoframe(struct v4l2_subdev *sd, const struct adv7511_cfg_read_infoframe *cri)
+static int read_infoframe(struct v4l2_subdev *sd,
+                         const struct adv7511_cfg_read_infoframe *cri,
+                         u8 *buffer)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct device *dev = &client->dev;
-       union hdmi_infoframe frame;
-       u8 buffer[32];
        u8 len;
        int i;
 
        if (!(adv7511_rd(sd, cri->present_reg) & cri->present_mask)) {
                v4l2_info(sd, "%s infoframe not transmitted\n", cri->desc);
-               return;
+               return 0;
        }
 
        memcpy(buffer, cri->header, sizeof(cri->header));
 
        len = buffer[2];
 
-       if (len + 4 > sizeof(buffer)) {
+       if (len + 4 > V4L2_DEBUGFS_IF_MAX_LEN) {
                v4l2_err(sd, "%s: invalid %s infoframe length %d\n", __func__, cri->desc, len);
-               return;
+               return 0;
        }
 
        if (cri->payload_addr >= 0x100) {
@@ -516,21 +517,38 @@ static void log_infoframe(struct v4l2_subdev *sd, const struct adv7511_cfg_read_
        buffer[3] = 0;
        buffer[3] = hdmi_infoframe_checksum(buffer, len + 4);
 
-       if (hdmi_infoframe_unpack(&frame, buffer, len + 4) < 0) {
-               v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
+       return len + 4;
+}
+
+static void log_infoframe(struct v4l2_subdev *sd,
+                         const struct adv7511_cfg_read_infoframe *cri)
+{
+       union hdmi_infoframe frame;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct device *dev = &client->dev;
+       u8 buffer[V4L2_DEBUGFS_IF_MAX_LEN] = {};
+       int len = read_infoframe(sd, cri, buffer);
+
+       if (len <= 0)
+               return;
+
+       if (hdmi_infoframe_unpack(&frame, buffer, len) < 0) {
+               v4l2_err(sd, "%s: unpack of %s infoframe failed\n",
+                        __func__, cri->desc);
                return;
        }
 
        hdmi_infoframe_log(KERN_INFO, dev, &frame);
 }
 
+static const struct adv7511_cfg_read_infoframe cri[] = {
+       { "AVI", 0x44, 0x10, { 0x82, 2, 13 }, 0x55 },
+       { "Audio", 0x44, 0x08, { 0x84, 1, 10 }, 0x73 },
+       { "SDP", 0x40, 0x40, { 0x83, 1, 25 }, 0x103 },
+};
+
 static void adv7511_log_infoframes(struct v4l2_subdev *sd)
 {
-       static const struct adv7511_cfg_read_infoframe cri[] = {
-               { "AVI", 0x44, 0x10, { 0x82, 2, 13 }, 0x55 },
-               { "Audio", 0x44, 0x08, { 0x84, 1, 10 }, 0x73 },
-               { "SDP", 0x40, 0x40, { 0x83, 1, 25 }, 0x103 },
-       };
        int i;
 
        for (i = 0; i < ARRAY_SIZE(cri); i++)
@@ -1693,6 +1711,34 @@ static bool adv7511_check_edid_status(struct v4l2_subdev *sd)
        return false;
 }
 
+static ssize_t
+adv7511_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;
+
+       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;
+       default:
+               return 0;
+       }
+       len = read_infoframe(sd, &cri[index], buf);
+       if (len > 0)
+               len = simple_read_from_buffer(ubuf, count, ppos, buf, len);
+       return len < 0 ? 0 : len;
+}
+
 static int adv7511_registered(struct v4l2_subdev *sd)
 {
        struct adv7511_state *state = get_adv7511_state(sd);
@@ -1700,9 +1746,16 @@ static int adv7511_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, sd, adv7511_debugfs_if_read);
+       return 0;
 }
 
 static void adv7511_unregistered(struct v4l2_subdev *sd)
@@ -1710,6 +1763,10 @@ static void adv7511_unregistered(struct v4l2_subdev *sd)
        struct adv7511_state *state = get_adv7511_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;
 }
 
 static const struct v4l2_subdev_internal_ops adv7511_int_ops = {