From 04dd17822334871b23ea2862f7798fb0e0007777 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Sat, 11 May 2024 08:53:19 +0000 Subject: [PATCH] change otg to host mode --- kernel/drivers/media/v4l2-core/v4l2-mc.c | 260 ++++++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 224 insertions(+), 36 deletions(-) diff --git a/kernel/drivers/media/v4l2-core/v4l2-mc.c b/kernel/drivers/media/v4l2-core/v4l2-mc.c index 0fc185a..ba2f2b8 100644 --- a/kernel/drivers/media/v4l2-core/v4l2-mc.c +++ b/kernel/drivers/media/v4l2-core/v4l2-mc.c @@ -28,7 +28,7 @@ struct media_entity *io_v4l = NULL, *io_vbi = NULL, *io_swradio = NULL; bool is_webcam = false; u32 flags; - int ret; + int ret, pad_sink, pad_source; if (!mdev) return 0; @@ -63,8 +63,10 @@ } /* It should have at least one I/O entity */ - if (!io_v4l && !io_vbi && !io_swradio) + if (!io_v4l && !io_vbi && !io_swradio) { + dev_warn(mdev->dev, "Didn't find any I/O entity\n"); return -EINVAL; + } /* * Here, webcams are modelled on a very simple way: the sensor is @@ -74,8 +76,10 @@ * PC-consumer's hardware. */ if (is_webcam) { - if (!io_v4l) + if (!io_v4l) { + dev_warn(mdev->dev, "Didn't find a MEDIA_ENT_F_IO_V4L\n"); return -EINVAL; + } media_device_for_each_entity(entity, mdev) { if (entity->function != MEDIA_ENT_F_CAM_SENSOR) @@ -83,46 +87,91 @@ ret = media_create_pad_link(entity, 0, io_v4l, 0, MEDIA_LNK_FL_ENABLED); - if (ret) + if (ret) { + dev_warn(mdev->dev, "Failed to create a sensor link\n"); return ret; + } } if (!decoder) return 0; } /* The device isn't a webcam. So, it should have a decoder */ - if (!decoder) + if (!decoder) { + dev_warn(mdev->dev, "Decoder not found\n"); return -EINVAL; + } /* Link the tuner and IF video output pads */ if (tuner) { if (if_vid) { - ret = media_create_pad_link(tuner, TUNER_PAD_OUTPUT, - if_vid, - IF_VID_DEC_PAD_IF_INPUT, + pad_source = media_get_pad_index(tuner, false, + PAD_SIGNAL_ANALOG); + pad_sink = media_get_pad_index(if_vid, true, + PAD_SIGNAL_ANALOG); + if (pad_source < 0 || pad_sink < 0) { + dev_warn(mdev->dev, "Couldn't get tuner and/or PLL pad(s): (%d, %d)\n", + pad_source, pad_sink); + return -EINVAL; + } + ret = media_create_pad_link(tuner, pad_source, + if_vid, pad_sink, MEDIA_LNK_FL_ENABLED); - if (ret) + if (ret) { + dev_warn(mdev->dev, "Couldn't create tuner->PLL link)\n"); return ret; - ret = media_create_pad_link(if_vid, IF_VID_DEC_PAD_OUT, - decoder, DEMOD_PAD_IF_INPUT, - MEDIA_LNK_FL_ENABLED); - if (ret) + } + + pad_source = media_get_pad_index(if_vid, false, + PAD_SIGNAL_ANALOG); + pad_sink = media_get_pad_index(decoder, true, + PAD_SIGNAL_ANALOG); + if (pad_source < 0 || pad_sink < 0) { + dev_warn(mdev->dev, "get decoder and/or PLL pad(s): (%d, %d)\n", + pad_source, pad_sink); + return -EINVAL; + } + ret = media_create_pad_link(if_vid, pad_source, + decoder, pad_sink, + MEDIA_LNK_FL_ENABLED); + if (ret) { + dev_warn(mdev->dev, "couldn't link PLL to decoder\n"); return ret; + } } else { - ret = media_create_pad_link(tuner, TUNER_PAD_OUTPUT, - decoder, DEMOD_PAD_IF_INPUT, - MEDIA_LNK_FL_ENABLED); + pad_source = media_get_pad_index(tuner, false, + PAD_SIGNAL_ANALOG); + pad_sink = media_get_pad_index(decoder, true, + PAD_SIGNAL_ANALOG); + if (pad_source < 0 || pad_sink < 0) { + dev_warn(mdev->dev, "couldn't get tuner and/or decoder pad(s): (%d, %d)\n", + pad_source, pad_sink); + return -EINVAL; + } + ret = media_create_pad_link(tuner, pad_source, + decoder, pad_sink, + MEDIA_LNK_FL_ENABLED); if (ret) return ret; } if (if_aud) { - ret = media_create_pad_link(tuner, TUNER_PAD_AUD_OUT, - if_aud, - IF_AUD_DEC_PAD_IF_INPUT, + pad_source = media_get_pad_index(tuner, false, + PAD_SIGNAL_AUDIO); + pad_sink = media_get_pad_index(if_aud, true, + PAD_SIGNAL_AUDIO); + if (pad_source < 0 || pad_sink < 0) { + dev_warn(mdev->dev, "couldn't get tuner and/or decoder pad(s) for audio: (%d, %d)\n", + pad_source, pad_sink); + return -EINVAL; + } + ret = media_create_pad_link(tuner, pad_source, + if_aud, pad_sink, MEDIA_LNK_FL_ENABLED); - if (ret) + if (ret) { + dev_warn(mdev->dev, "couldn't link tuner->audio PLL\n"); return ret; + } } else { if_aud = tuner; } @@ -131,27 +180,48 @@ /* Create demod to V4L, VBI and SDR radio links */ if (io_v4l) { - ret = media_create_pad_link(decoder, DEMOD_PAD_VID_OUT, - io_v4l, 0, - MEDIA_LNK_FL_ENABLED); - if (ret) + pad_source = media_get_pad_index(decoder, false, PAD_SIGNAL_DV); + if (pad_source < 0) { + dev_warn(mdev->dev, "couldn't get decoder output pad for V4L I/O\n"); + return -EINVAL; + } + ret = media_create_pad_link(decoder, pad_source, + io_v4l, 0, + MEDIA_LNK_FL_ENABLED); + if (ret) { + dev_warn(mdev->dev, "couldn't link decoder output to V4L I/O\n"); return ret; + } } if (io_swradio) { - ret = media_create_pad_link(decoder, DEMOD_PAD_VID_OUT, - io_swradio, 0, - MEDIA_LNK_FL_ENABLED); - if (ret) + pad_source = media_get_pad_index(decoder, false, PAD_SIGNAL_DV); + if (pad_source < 0) { + dev_warn(mdev->dev, "couldn't get decoder output pad for SDR\n"); + return -EINVAL; + } + ret = media_create_pad_link(decoder, pad_source, + io_swradio, 0, + MEDIA_LNK_FL_ENABLED); + if (ret) { + dev_warn(mdev->dev, "couldn't link decoder output to SDR\n"); return ret; + } } if (io_vbi) { - ret = media_create_pad_link(decoder, DEMOD_PAD_VBI_OUT, + pad_source = media_get_pad_index(decoder, false, PAD_SIGNAL_DV); + if (pad_source < 0) { + dev_warn(mdev->dev, "couldn't get decoder output pad for VBI\n"); + return -EINVAL; + } + ret = media_create_pad_link(decoder, pad_source, io_vbi, 0, MEDIA_LNK_FL_ENABLED); - if (ret) + if (ret) { + dev_warn(mdev->dev, "couldn't link decoder output to VBI\n"); return ret; + } } /* Create links for the media connectors */ @@ -161,15 +231,26 @@ case MEDIA_ENT_F_CONN_RF: if (!tuner) continue; - + pad_sink = media_get_pad_index(tuner, true, + PAD_SIGNAL_ANALOG); + if (pad_sink < 0) { + dev_warn(mdev->dev, "couldn't get tuner analog pad sink\n"); + return -EINVAL; + } ret = media_create_pad_link(entity, 0, tuner, - TUNER_PAD_RF_INPUT, + pad_sink, flags); break; case MEDIA_ENT_F_CONN_SVIDEO: case MEDIA_ENT_F_CONN_COMPOSITE: + pad_sink = media_get_pad_index(decoder, true, + PAD_SIGNAL_ANALOG); + if (pad_sink < 0) { + dev_warn(mdev->dev, "couldn't get tuner analog pad sink\n"); + return -EINVAL; + } ret = media_create_pad_link(entity, 0, decoder, - DEMOD_PAD_IF_INPUT, + pad_sink, flags); break; default: @@ -228,6 +309,101 @@ } EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source); +int v4l2_create_fwnode_links_to_pad(struct v4l2_subdev *src_sd, + struct media_pad *sink) +{ + struct fwnode_handle *endpoint; + struct v4l2_subdev *sink_sd; + + if (!(sink->flags & MEDIA_PAD_FL_SINK) || + !is_media_entity_v4l2_subdev(sink->entity)) + return -EINVAL; + + sink_sd = media_entity_to_v4l2_subdev(sink->entity); + + fwnode_graph_for_each_endpoint(dev_fwnode(src_sd->dev), endpoint) { + struct fwnode_handle *remote_ep; + int src_idx, sink_idx, ret; + struct media_pad *src; + + src_idx = media_entity_get_fwnode_pad(&src_sd->entity, + endpoint, + MEDIA_PAD_FL_SOURCE); + if (src_idx < 0) + continue; + + remote_ep = fwnode_graph_get_remote_endpoint(endpoint); + if (!remote_ep) + continue; + + /* + * ask the sink to verify it owns the remote endpoint, + * and translate to a sink pad. + */ + sink_idx = media_entity_get_fwnode_pad(&sink_sd->entity, + remote_ep, + MEDIA_PAD_FL_SINK); + fwnode_handle_put(remote_ep); + + if (sink_idx < 0 || sink_idx != sink->index) + continue; + + /* + * the source endpoint corresponds to one of its source pads, + * the source endpoint connects to an endpoint at the sink + * entity, and the sink endpoint corresponds to the sink + * pad requested, so we have found an endpoint connection + * that works, create the media link for it. + */ + + src = &src_sd->entity.pads[src_idx]; + + /* skip if link already exists */ + if (media_entity_find_link(src, sink)) + continue; + + dev_dbg(sink_sd->dev, "creating link %s:%d -> %s:%d\n", + src_sd->entity.name, src_idx, + sink_sd->entity.name, sink_idx); + + ret = media_create_pad_link(&src_sd->entity, src_idx, + &sink_sd->entity, sink_idx, 0); + if (ret) { + dev_err(sink_sd->dev, + "link %s:%d -> %s:%d failed with %d\n", + src_sd->entity.name, src_idx, + sink_sd->entity.name, sink_idx, ret); + + fwnode_handle_put(endpoint); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_create_fwnode_links_to_pad); + +int v4l2_create_fwnode_links(struct v4l2_subdev *src_sd, + struct v4l2_subdev *sink_sd) +{ + unsigned int i; + + for (i = 0; i < sink_sd->entity.num_pads; i++) { + struct media_pad *pad = &sink_sd->entity.pads[i]; + int ret; + + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + continue; + + ret = v4l2_create_fwnode_links_to_pad(src_sd, pad); + if (ret) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_create_fwnode_links); + /* ----------------------------------------------------------------------------- * Pipeline power management * @@ -240,7 +416,7 @@ * use_count field stores the total number of users of all video device nodes * in the pipeline. * - * The v4l2_pipeline_pm_use() function must be called in the open() and + * The v4l2_pipeline_pm_{get, put}() functions must be called in the open() and * close() handlers of video device nodes. It increments or decrements the use * count of all subdev entities in the pipeline. * @@ -342,7 +518,7 @@ return ret; } -int v4l2_pipeline_pm_use(struct media_entity *entity, int use) +static int v4l2_pipeline_pm_use(struct media_entity *entity, unsigned int use) { struct media_device *mdev = entity->graph_obj.mdev; int change = use ? 1 : -1; @@ -363,7 +539,19 @@ return ret; } -EXPORT_SYMBOL_GPL(v4l2_pipeline_pm_use); + +int v4l2_pipeline_pm_get(struct media_entity *entity) +{ + return v4l2_pipeline_pm_use(entity, 1); +} +EXPORT_SYMBOL_GPL(v4l2_pipeline_pm_get); + +void v4l2_pipeline_pm_put(struct media_entity *entity) +{ + /* Powering off entities shouldn't fail. */ + WARN_ON(v4l2_pipeline_pm_use(entity, 0)); +} +EXPORT_SYMBOL_GPL(v4l2_pipeline_pm_put); int v4l2_pipeline_link_notify(struct media_link *link, u32 flags, unsigned int notification) -- Gitblit v1.6.2