]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
media: v4l2-core: add v4l2_debugfs_if_alloc/free()
authorHans Verkuil <hverkuil-cisco@xs4all.nl>
Wed, 28 Aug 2024 14:24:08 +0000 (16:24 +0200)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Sat, 12 Oct 2024 08:44:05 +0000 (10:44 +0200)
Add new helpers to export received or transmitted HDMI InfoFrames to
debugfs.

This complements similar code in drm where the transmitted HDMI infoframes
are exported to debugfs.

The same names have been used as in drm, so this is consistent.

The exported infoframes can be parsed with the edid-decode utility.

Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
drivers/media/v4l2-core/v4l2-dv-timings.c
include/media/v4l2-dv-timings.h

index 942d0005c55e82047bcb9589ad6ac0f8502b5fd2..39b5fc1807c409a4cc7421edc6b7ed2b5c1452e1 100644 (file)
@@ -1154,3 +1154,70 @@ int v4l2_phys_addr_validate(u16 phys_addr, u16 *parent, u16 *port)
        return 0;
 }
 EXPORT_SYMBOL_GPL(v4l2_phys_addr_validate);
+
+#ifdef CONFIG_DEBUG_FS
+
+#define DEBUGFS_FOPS(type, flag)                                       \
+static ssize_t                                                         \
+infoframe_read_##type(struct file *filp,                               \
+                     char __user *ubuf, size_t count, loff_t *ppos)    \
+{                                                                      \
+       struct v4l2_debugfs_if *infoframes = filp->private_data;        \
+                                                                       \
+       return infoframes->if_read((flag), infoframes->priv, filp,      \
+                                  ubuf, count, ppos);                  \
+}                                                                      \
+                                                                       \
+static const struct file_operations infoframe_##type##_fops = {                \
+       .owner   = THIS_MODULE,                                         \
+       .open    = simple_open,                                         \
+       .read    = infoframe_read_##type,                               \
+}
+
+DEBUGFS_FOPS(avi, V4L2_DEBUGFS_IF_AVI);
+DEBUGFS_FOPS(audio, V4L2_DEBUGFS_IF_AUDIO);
+DEBUGFS_FOPS(spd, V4L2_DEBUGFS_IF_SPD);
+DEBUGFS_FOPS(hdmi, V4L2_DEBUGFS_IF_HDMI);
+
+struct v4l2_debugfs_if *v4l2_debugfs_if_alloc(struct dentry *root, u32 if_types,
+                                             void *priv,
+                                             v4l2_debugfs_if_read_t if_read)
+{
+       struct v4l2_debugfs_if *infoframes;
+
+       if (IS_ERR_OR_NULL(root) || !if_types || !if_read)
+               return NULL;
+
+       infoframes = kzalloc(sizeof(*infoframes), GFP_KERNEL);
+       if (!infoframes)
+               return NULL;
+
+       infoframes->if_dir = debugfs_create_dir("infoframes", root);
+       infoframes->priv = priv;
+       infoframes->if_read = if_read;
+       if (if_types & V4L2_DEBUGFS_IF_AVI)
+               debugfs_create_file("avi", 0400, infoframes->if_dir,
+                                   infoframes, &infoframe_avi_fops);
+       if (if_types & V4L2_DEBUGFS_IF_AUDIO)
+               debugfs_create_file("audio", 0400, infoframes->if_dir,
+                                   infoframes, &infoframe_audio_fops);
+       if (if_types & V4L2_DEBUGFS_IF_SPD)
+               debugfs_create_file("spd", 0400, infoframes->if_dir,
+                                   infoframes, &infoframe_spd_fops);
+       if (if_types & V4L2_DEBUGFS_IF_HDMI)
+               debugfs_create_file("hdmi", 0400, infoframes->if_dir,
+                                   infoframes, &infoframe_hdmi_fops);
+       return infoframes;
+}
+EXPORT_SYMBOL_GPL(v4l2_debugfs_if_alloc);
+
+void v4l2_debugfs_if_free(struct v4l2_debugfs_if *infoframes)
+{
+       if (infoframes) {
+               debugfs_remove_recursive(infoframes->if_dir);
+               kfree(infoframes);
+       }
+}
+EXPORT_SYMBOL_GPL(v4l2_debugfs_if_free);
+
+#endif
index 8fa963326bf6a2d05146672e34d5def354efc678..13830411bd6c486e863b01a2ae3ebf91235c5f67 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef __V4L2_DV_TIMINGS_H
 #define __V4L2_DV_TIMINGS_H
 
+#include <linux/debugfs.h>
 #include <linux/videodev2.h>
 
 /**
@@ -251,4 +252,51 @@ void v4l2_set_edid_phys_addr(u8 *edid, unsigned int size, u16 phys_addr);
 u16 v4l2_phys_addr_for_input(u16 phys_addr, u8 input);
 int v4l2_phys_addr_validate(u16 phys_addr, u16 *parent, u16 *port);
 
+/* Add support for exporting InfoFrames to debugfs */
+
+/*
+ * HDMI InfoFrames start with a 3 byte header, then a checksum,
+ * followed by the actual IF payload.
+ *
+ * The payload length is limited to 30 bytes according to the HDMI spec,
+ * but since the length is encoded in 5 bits, it can be 31 bytes theoretically.
+ * So set the max length as 31 + 3 (header) + 1 (checksum) = 35.
+ */
+#define V4L2_DEBUGFS_IF_MAX_LEN (35)
+
+#define V4L2_DEBUGFS_IF_AVI    BIT(0)
+#define V4L2_DEBUGFS_IF_AUDIO  BIT(1)
+#define V4L2_DEBUGFS_IF_SPD    BIT(2)
+#define V4L2_DEBUGFS_IF_HDMI   BIT(3)
+
+typedef ssize_t (*v4l2_debugfs_if_read_t)(u32 type, void *priv,
+                                         struct file *filp, char __user *ubuf,
+                                         size_t count, loff_t *ppos);
+
+struct v4l2_debugfs_if {
+       struct dentry *if_dir;
+       void *priv;
+
+       v4l2_debugfs_if_read_t if_read;
+};
+
+#ifdef CONFIG_DEBUG_FS
+struct v4l2_debugfs_if *v4l2_debugfs_if_alloc(struct dentry *root, u32 if_types,
+                                             void *priv,
+                                             v4l2_debugfs_if_read_t if_read);
+void v4l2_debugfs_if_free(struct v4l2_debugfs_if *infoframes);
+#else
+static inline
+struct v4l2_debugfs_if *v4l2_debugfs_if_alloc(struct dentry *root, u32 if_types,
+                                             void *priv,
+                                             v4l2_debugfs_if_read_t if_read)
+{
+       return NULL;
+}
+
+static inline void v4l2_debugfs_if_free(struct v4l2_debugfs_if *infoframes)
+{
+}
+#endif
+
 #endif