Re: [PATCH 1/2] media: i2c: adv748x: Support probing a single output

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Jacopo,

Thank you for the patch,


On 27/08/18 12:28, Jacopo Mondi wrote:
> Currently the adv748x driver refuses to probe if both its output endpoints
> (TXA and TXB) are not connected.
> 
> Make the driver support probing with (at least) one output endpoint connected
> and protect the cleanup function from accessing un-initialized fields.
> 
> Following patches will fix other user of un-initialized TXs in the driver,
> such as power management functions.
> 
> Signed-off-by: Jacopo Mondi <jacopo+renesas@xxxxxxxxxx>
> ---
>  drivers/media/i2c/adv748x/adv748x-core.c | 38 +++++++++++++++++++++++++-------
>  drivers/media/i2c/adv748x/adv748x-csi2.c | 17 ++++----------
>  drivers/media/i2c/adv748x/adv748x.h      |  2 ++
>  3 files changed, 36 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c
> index 6ca88daa..78d5996 100644
> --- a/drivers/media/i2c/adv748x/adv748x-core.c
> +++ b/drivers/media/i2c/adv748x/adv748x-core.c
> @@ -654,6 +654,24 @@ static int adv748x_probe(struct i2c_client *client,
>  		goto err_cleanup_clients;
>  	}
>  
> +	/*
> +	 * We can not use container_of to get back to the state with two TXs;
> +	 * Initialize the TXs's fields unconditionally on the endpoint
> +	 * presence to access them later.
> +	 */
> +	state->txa.state = state->txb.state = state;
> +	state->txa.page = ADV748X_PAGE_TXA;
> +	state->txb.page = ADV748X_PAGE_TXB;
> +	state->txa.port = ADV748X_PORT_TXA;
> +	state->txb.port = ADV748X_PORT_TXB;
> +

Initialising this data here feels a bit hacky...


> +	if (!is_tx_enabled(&state->txa) &&
> +	    !is_tx_enabled(&state->txb)) {

Could we make is_tx_enabled() based on the information it needs?

	is_tx_enabled(ADV748X_PORT_TXA);

Or perhaps:
	is_port_enabled(ADV748X_PORT_TXA)
	


> +		ret = -ENODEV;
> +		adv_err(state, "No output endpoint defined\n");
> +		goto err_cleanup_clients;
> +	}
> +

I approached this slightly differently at [0], by allowing the CSI
object to initialise, but if they return -ENODEV, then it's fine.

The only thing missing from [0] is a check to see if at least one of the
CSI devices probed.



You might be interested in [1], from my old 'adv748x/dev' branch [2] for
looking at the link creation too.

[0]
https://git.kernel.org/pub/scm/linux/kernel/git/kbingham/rcar.git/commit/?h=adv748x/for-next&id=ee53e0f7e6e0f3dacc79dcf157ce3c403b17ec14

[1]
https://git.kernel.org/pub/scm/linux/kernel/git/kbingham/rcar.git/commit/?h=adv748x/dev&id=e0e975d73a70a5b73ad674e206103cd7df983a04


[2]
https://git.kernel.org/pub/scm/linux/kernel/git/kbingham/rcar.git/log/?h=adv748x/dev


>  	/* SW reset ADV748X to its default values */
>  	ret = adv748x_reset(state);
>  	if (ret) {
> @@ -676,17 +694,21 @@ static int adv748x_probe(struct i2c_client *client,
>  	}
>  
>  	/* Initialise TXA */
> -	ret = adv748x_csi2_init(state, &state->txa);
> -	if (ret) {
> -		adv_err(state, "Failed to probe TXA");
> -		goto err_cleanup_afe;
> +	if (is_tx_enabled(&state->txa)) {
> +		ret = adv748x_csi2_init(state, &state->txa);
> +		if (ret) {
> +			adv_err(state, "Failed to probe TXA");
> +			goto err_cleanup_afe;
> +		}
>  	}
>  
>  	/* Initialise TXB */
> -	ret = adv748x_csi2_init(state, &state->txb);
> -	if (ret) {
> -		adv_err(state, "Failed to probe TXB");
> -		goto err_cleanup_txa;
> +	if (is_tx_enabled(&state->txb)) {
> +		ret = adv748x_csi2_init(state, &state->txb);
> +		if (ret) {
> +			adv_err(state, "Failed to probe TXB");
> +			goto err_cleanup_txa;
> +		}
>  	}
>  
>  	return 0;
> diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
> index 469be87..709cdea 100644
> --- a/drivers/media/i2c/adv748x/adv748x-csi2.c
> +++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
> @@ -266,20 +266,8 @@ static int adv748x_csi2_init_controls(struct adv748x_csi2 *tx)
>  
>  int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
>  {
> -	struct device_node *ep;
>  	int ret;
>  
> -	/* We can not use container_of to get back to the state with two TXs */
> -	tx->state = state;
> -	tx->page = is_txa(tx) ? ADV748X_PAGE_TXA : ADV748X_PAGE_TXB;
> -
> -	ep = state->endpoints[is_txa(tx) ? ADV748X_PORT_TXA : ADV748X_PORT_TXB];
> -	if (!ep) {
> -		adv_err(state, "No endpoint found for %s\n",
> -				is_txa(tx) ? "txa" : "txb");

If you used the -ENODEV approach, this adv_err should be removed.

> -		return -ENODEV;
> -	}
> -
>  	/* Initialise the virtual channel */
>  	adv748x_csi2_set_virtual_channel(tx, 0);
>  
> @@ -288,7 +276,7 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
>  			    is_txa(tx) ? "txa" : "txb");
>  
>  	/* Ensure that matching is based upon the endpoint fwnodes */
> -	tx->sd.fwnode = of_fwnode_handle(ep);
> +	tx->sd.fwnode = of_fwnode_handle(state->endpoints[tx->port]);
>  
>  	/* Register internal ops for incremental subdev registration */
>  	tx->sd.internal_ops = &adv748x_csi2_internal_ops;
> @@ -321,6 +309,9 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
>  
>  void adv748x_csi2_cleanup(struct adv748x_csi2 *tx)
>  {
> +	if (!is_tx_enabled(tx))
> +		return;
> +
>  	v4l2_async_unregister_subdev(&tx->sd);
>  	media_entity_cleanup(&tx->sd.entity);
>  	v4l2_ctrl_handler_free(&tx->ctrl_hdl);
> diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h
> index 65f8374..1cf46c40 100644
> --- a/drivers/media/i2c/adv748x/adv748x.h
> +++ b/drivers/media/i2c/adv748x/adv748x.h
> @@ -82,6 +82,7 @@ struct adv748x_csi2 {
>  	struct adv748x_state *state;
>  	struct v4l2_mbus_framefmt format;
>  	unsigned int page;
> +	unsigned int port;
>  
>  	struct media_pad pads[ADV748X_CSI2_NR_PADS];
>  	struct v4l2_ctrl_handler ctrl_hdl;
> @@ -91,6 +92,7 @@ struct adv748x_csi2 {
>  
>  #define notifier_to_csi2(n) container_of(n, struct adv748x_csi2, notifier)
>  #define adv748x_sd_to_csi2(sd) container_of(sd, struct adv748x_csi2, sd)
> +#define is_tx_enabled(_tx) ((_tx)->state->endpoints[(_tx)->port] != NULL)

>  
>  enum adv748x_hdmi_pads {
>  	ADV748X_HDMI_SINK,
> 




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux