media: v4l2-core: add v4l2_debugfs_if_alloc/free()

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>
This commit is contained in:
Hans Verkuil 2024-08-28 16:24:08 +02:00 committed by Mauro Carvalho Chehab
parent ccb32f2357
commit 01c76fc995
2 changed files with 115 additions and 0 deletions

View 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

View 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