Export InfoFrames to debugfs. Signed-off-by: Hans Verkuil <hverkuil-cisco@xxxxxxxxx> Tested-by: Hans Verkuil <hverkuil-cisco@xxxxxxxxx> --- drivers/media/i2c/adv7842.c | 120 ++++++++++++++++++++++++++---------- 1 file changed, 88 insertions(+), 32 deletions(-) diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 014fc913225c..e445699da85b 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -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; } /* ----------------------------------------------------------------------- */ -- 2.43.0