media: i2c: adv7842: export InfoFrames to debugfs

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>
This commit is contained in:
Hans Verkuil
2024-08-28 16:24:11 +02:00
committed by Mauro Carvalho Chehab
parent 60bdc2ffe5
commit 42765902bd

View File

@@ -114,6 +114,9 @@ struct adv7842_state {
bool restart_stdi_once;
bool hdmi_port_a;
struct dentry *debugfs_dir;
struct v4l2_debugfs_if *infoframes;
/* i2c clients */
struct i2c_client *i2c_sdp_io;
struct i2c_client *i2c_sdp;
@@ -2565,58 +2568,65 @@ struct adv7842_cfg_read_infoframe {
u8 payload_addr;
};
static void log_infoframe(struct v4l2_subdev *sd, const struct adv7842_cfg_read_infoframe *cri)
static const struct adv7842_cfg_read_infoframe adv7842_cri[] = {
{ "AVI", 0x01, 0xe0, 0x00 },
{ "Audio", 0x02, 0xe3, 0x1c },
{ "SDP", 0x04, 0xe6, 0x2a },
{ "Vendor", 0x10, 0xec, 0x54 }
};
static int adv7842_read_infoframe_buf(struct v4l2_subdev *sd, int index,
u8 buf[V4L2_DEBUGFS_IF_MAX_LEN])
{
int i;
u8 buffer[32];
union hdmi_infoframe frame;
u8 len;
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct device *dev = &client->dev;
const struct adv7842_cfg_read_infoframe *cri = &adv7842_cri[index];
int len, i;
if (!(io_read(sd, 0x60) & cri->present_mask)) {
v4l2_info(sd, "%s infoframe not received\n", cri->desc);
return;
v4l2_dbg(1, debug, sd,
"%s infoframe not received\n", cri->desc);
return -ENOENT;
}
for (i = 0; i < 3; i++)
buffer[i] = infoframe_read(sd, cri->head_addr + i);
buf[i] = infoframe_read(sd, cri->head_addr + i);
len = buffer[2] + 1;
len = buf[2] + 1;
if (len + 3 > sizeof(buffer)) {
v4l2_err(sd, "%s: invalid %s infoframe length %d\n", __func__, cri->desc, len);
return;
if (len + 3 > V4L2_DEBUGFS_IF_MAX_LEN) {
v4l2_err(sd, "%s: invalid %s infoframe length %d\n",
__func__, cri->desc, len);
return -ENOENT;
}
for (i = 0; i < len; i++)
buffer[i + 3] = infoframe_read(sd, cri->payload_addr + i);
if (hdmi_infoframe_unpack(&frame, buffer, len + 3) < 0) {
v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
return;
}
hdmi_infoframe_log(KERN_INFO, dev, &frame);
buf[i + 3] = infoframe_read(sd, cri->payload_addr + i);
return len + 3;
}
static void adv7842_log_infoframes(struct v4l2_subdev *sd)
{
int i;
static const struct adv7842_cfg_read_infoframe cri[] = {
{ "AVI", 0x01, 0xe0, 0x00 },
{ "Audio", 0x02, 0xe3, 0x1c },
{ "SDP", 0x04, 0xe6, 0x2a },
{ "Vendor", 0x10, 0xec, 0x54 }
};
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct device *dev = &client->dev;
union hdmi_infoframe frame;
u8 buffer[V4L2_DEBUGFS_IF_MAX_LEN] = {};
int len, i;
if (!(hdmi_read(sd, 0x05) & 0x80)) {
v4l2_info(sd, "receive DVI-D signal, no infoframes\n");
return;
}
for (i = 0; i < ARRAY_SIZE(cri); i++)
log_infoframe(sd, &cri[i]);
for (i = 0; i < ARRAY_SIZE(adv7842_cri); i++) {
len = adv7842_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__, adv7842_cri[i].desc);
else
hdmi_infoframe_log(KERN_INFO, dev, &frame);
}
}
#if 0
@@ -3263,6 +3273,41 @@ static int adv7842_subscribe_event(struct v4l2_subdev *sd,
}
}
static ssize_t
adv7842_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 = adv7842_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 adv7842_registered(struct v4l2_subdev *sd)
{
struct adv7842_state *state = to_state(sd);
@@ -3270,8 +3315,15 @@ static int adv7842_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);
} else {
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,
adv7842_debugfs_if_read);
}
return err;
}
@@ -3280,6 +3332,10 @@ static void adv7842_unregistered(struct v4l2_subdev *sd)
struct adv7842_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;
}
/* ----------------------------------------------------------------------- */