Re: [PATCH 2/3] Input: synaptics_rmi4 - unmask F03 interrupts when port is opened

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

 



Looks good to me.

Reviewed-by: Lyude Paul <lyude@xxxxxxxxxx>

On Thu, 2018-01-18 at 16:49 -0800, Dmitry Torokhov wrote:
> Currently we register the pass-through serio port when we probe the F03 RMI
> function, and then, in sensor configure phase, we unmask interrupts.
> Unfortunately this is too late, as other drivers are free probe devices
> attached to the serio port as soon as it is probed. Because interrupts are
> masked, the IO times out, which may result in not being able to detect
> trackpoints on the pass-through port.
> 
> To fix the issue we implement open() and close() methods for the
> pass-through serio port and unmask interrupts from there. We also move
> creation of the pass-through port form probe to configure stage, as RMI
> driver does not enable transport interrupt until all functions are probed
> (we should change this, but this is a separate topic).
> 
> We also try to clear the pending data before unmasking interrupts, because
> some devices like to spam the system with multiple 0xaa 0x00 announcements,
> which may interfere with us trying to query ID of the device.
> 
> Fixes: c5e8848fc98e ("Input: synaptics-rmi4 - add support for F03")
> Cc: stable@xxxxxxxxxxxxxxx
> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@xxxxxxxxx>
> ---
>  drivers/input/rmi4/rmi_f03.c | 64 +++++++++++++++++++++++++++++++++++++--
> -----
>  1 file changed, 54 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/input/rmi4/rmi_f03.c b/drivers/input/rmi4/rmi_f03.c
> index ad71a5e768dc4..7ccbb370a9a81 100644
> --- a/drivers/input/rmi4/rmi_f03.c
> +++ b/drivers/input/rmi4/rmi_f03.c
> @@ -32,6 +32,7 @@ struct f03_data {
>  	struct rmi_function *fn;
>  
>  	struct serio *serio;
> +	bool serio_registered;
>  
>  	unsigned int overwrite_buttons;
>  
> @@ -138,6 +139,37 @@ static int rmi_f03_initialize(struct f03_data *f03)
>  	return 0;
>  }
>  
> +static int rmi_f03_pt_open(struct serio *serio)
> +{
> +	struct f03_data *f03 = serio->port_data;
> +	struct rmi_function *fn = f03->fn;
> +	const u8 ob_len = f03->rx_queue_length * RMI_F03_OB_SIZE;
> +	const u16 data_addr = fn->fd.data_base_addr + RMI_F03_OB_OFFSET;
> +	u8 obs[RMI_F03_QUEUE_LENGTH * RMI_F03_OB_SIZE];
> +	int error;
> +
> +	/*
> +	 * Consume any pending data. Some devices like to spam with
> +	 * 0xaa 0x00 announcements which may confuse us as we try to
> +	 * probe the device.
> +	 */
> +	error = rmi_read_block(fn->rmi_dev, data_addr, &obs, ob_len);
> +	if (!error)
> +		rmi_dbg(RMI_DEBUG_FN, &fn->dev,
> +			"%s: Consumed %*ph (%d) from PS2 guest\n",
> +			__func__, ob_len, obs, ob_len);
> +
> +	return fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn-
> >irq_mask);
> +}
> +
> +static void rmi_f03_pt_close(struct serio *serio)
> +{
> +	struct f03_data *f03 = serio->port_data;
> +	struct rmi_function *fn = f03->fn;
> +
> +	fn->rmi_dev->driver->clear_irq_bits(fn->rmi_dev, fn->irq_mask);
> +}
> +
>  static int rmi_f03_register_pt(struct f03_data *f03)
>  {
>  	struct serio *serio;
> @@ -148,6 +180,8 @@ static int rmi_f03_register_pt(struct f03_data *f03)
>  
>  	serio->id.type = SERIO_PS_PSTHRU;
>  	serio->write = rmi_f03_pt_write;
> +	serio->open = rmi_f03_pt_open;
> +	serio->close = rmi_f03_pt_close;
>  	serio->port_data = f03;
>  
>  	strlcpy(serio->name, "Synaptics RMI4 PS/2 pass-through",
> @@ -184,17 +218,27 @@ static int rmi_f03_probe(struct rmi_function *fn)
>  			 f03->device_count);
>  
>  	dev_set_drvdata(dev, f03);
> -
> -	error = rmi_f03_register_pt(f03);
> -	if (error)
> -		return error;
> -
>  	return 0;
>  }
>  
>  static int rmi_f03_config(struct rmi_function *fn)
>  {
> -	fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask);
> +	struct f03_data *f03 = dev_get_drvdata(&fn->dev);
> +	int error;
> +
> +	if (!f03->serio_registered) {
> +		error = rmi_f03_register_pt(f03);
> +		if (error)
> +			return error;
> +
> +		f03->serio_registered = true;
> +	} else {
> +		/*
> +		 * We must be re-configuring the sensor, just enable
> +		 * interrupts for this function.
> +		 */
> +		fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn-
> >irq_mask);
> +	}
>  
>  	return 0;
>  }
> @@ -204,7 +248,7 @@ static int rmi_f03_attention(struct rmi_function *fn,
> unsigned long *irq_bits)
>  	struct rmi_device *rmi_dev = fn->rmi_dev;
>  	struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
>  	struct f03_data *f03 = dev_get_drvdata(&fn->dev);
> -	u16 data_addr = fn->fd.data_base_addr;
> +	const u16 data_addr = fn->fd.data_base_addr + RMI_F03_OB_OFFSET;
>  	const u8 ob_len = f03->rx_queue_length * RMI_F03_OB_SIZE;
>  	u8 obs[RMI_F03_QUEUE_LENGTH * RMI_F03_OB_SIZE];
>  	u8 ob_status;
> @@ -226,8 +270,7 @@ static int rmi_f03_attention(struct rmi_function *fn,
> unsigned long *irq_bits)
>  		drvdata->attn_data.size -= ob_len;
>  	} else {
>  		/* Grab all of the data registers, and check them for data
> */
> -		error = rmi_read_block(fn->rmi_dev, data_addr +
> RMI_F03_OB_OFFSET,
> -				       &obs, ob_len);
> +		error = rmi_read_block(fn->rmi_dev, data_addr, &obs,
> ob_len);
>  		if (error) {
>  			dev_err(&fn->dev,
>  				"%s: Failed to read F03 output buffers:
> %d\n",
> @@ -266,7 +309,8 @@ static void rmi_f03_remove(struct rmi_function *fn)
>  {
>  	struct f03_data *f03 = dev_get_drvdata(&fn->dev);
>  
> -	serio_unregister_port(f03->serio);
> +	if (f03->serio_registered)
> +		serio_unregister_port(f03->serio);
>  }
>  
>  struct rmi_function_handler rmi_f03_handler = {



[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]