Re: [PATCH regression fix 1/2] Input: silead - Add support for EFI-embedded fw using different min/max coordinates

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

 



Hi,

These 2 patches obviously are not regression-fixes, I accidentally
still had a subjectprefix set when sending these, sorry about that.

Other then that these are ready for merging :)

Regards,

Hans


On 9/5/21 2:45 PM, Hans de Goede wrote:
> Unfortunately, at the time of writing this commit message, we have been
> unable to get permission from Silead, or from device OEMs, to distribute
> the necessary Silead firmware files in linux-firmware.
> 
> On a whole bunch of devices the UEFI BIOS code contains a touchscreen
> driver, which contains an embedded copy of the firmware. The fw-loader
> code has a "platform" fallback mechanism, which together with info on the
> firmware from drivers/platform/x86/touchscreen_dmi.c will use the firmware
> from the UEFI driver when the firmware is missing from /lib/firmware. This
> makes the touchscreen work OOTB without users needing to manually download
> the firmware.
> 
> The firmware bundled with the original Windows/Android is usually newer
> then the firmware in the UEFI driver and it is better calibrated. This
> better calibration can lead to significant differences in the reported
> min/max coordinates.
> 
> Add support for a new (optional) "silead,efi-fw-min-max" property which
> provides a set of alternative min/max values to use for the x/y axis when
> the EFI embedded firmware is used.
> 
> The new property is only used on (x86) devices which do not use devicetree,
> IOW it is not used in actual devicetree files. The devicetree-bindings
> maintainers have requested properties like these to not be added to the
> devicetree-bindings, so the new property is deliberately not added to the
> existing silead devicetree-bindings documentation.
> 
> Signed-off-by: Hans de Goede <hdegoede@xxxxxxxxxx>
> ---
>  drivers/input/touchscreen/silead.c | 73 ++++++++++++++++++++++++++++--
>  1 file changed, 68 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c
> index 1ee760bac0cf..caa25af53e6e 100644
> --- a/drivers/input/touchscreen/silead.c
> +++ b/drivers/input/touchscreen/silead.c
> @@ -75,6 +75,8 @@ struct silead_ts_data {
>  	struct input_mt_pos pos[SILEAD_MAX_FINGERS];
>  	int slots[SILEAD_MAX_FINGERS];
>  	int id[SILEAD_MAX_FINGERS];
> +	u32 efi_fw_min_max[4];
> +	bool efi_fw_min_max_set;
>  };
>  
>  struct silead_fw_data {
> @@ -82,6 +84,35 @@ struct silead_fw_data {
>  	u32 val;
>  };
>  
> +static void silead_apply_efi_fw_min_max(struct silead_ts_data *data)
> +{
> +	struct input_absinfo *absinfo_x = &data->input->absinfo[ABS_MT_POSITION_X];
> +	struct input_absinfo *absinfo_y = &data->input->absinfo[ABS_MT_POSITION_Y];
> +
> +	if (!data->efi_fw_min_max_set)
> +		return;
> +
> +	absinfo_x->minimum = data->efi_fw_min_max[0];
> +	absinfo_x->maximum = data->efi_fw_min_max[1];
> +	absinfo_y->minimum = data->efi_fw_min_max[2];
> +	absinfo_y->maximum = data->efi_fw_min_max[3];
> +
> +	if (data->prop.invert_x) {
> +		absinfo_x->maximum -= absinfo_x->minimum;
> +		absinfo_x->minimum = 0;
> +	}
> +
> +	if (data->prop.invert_y) {
> +		absinfo_y->maximum -= absinfo_y->minimum;
> +		absinfo_y->minimum = 0;
> +	}
> +
> +	if (data->prop.swap_x_y) {
> +		swap(absinfo_x->minimum, absinfo_y->minimum);
> +		swap(absinfo_x->maximum, absinfo_y->maximum);
> +	}
> +}
> +
>  static int silead_ts_request_input_dev(struct silead_ts_data *data)
>  {
>  	struct device *dev = &data->client->dev;
> @@ -97,6 +128,7 @@ static int silead_ts_request_input_dev(struct silead_ts_data *data)
>  	input_set_abs_params(data->input, ABS_MT_POSITION_X, 0, 4095, 0, 0);
>  	input_set_abs_params(data->input, ABS_MT_POSITION_Y, 0, 4095, 0, 0);
>  	touchscreen_parse_properties(data->input, true, &data->prop);
> +	silead_apply_efi_fw_min_max(data);
>  
>  	input_mt_init_slots(data->input, data->max_fingers,
>  			    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED |
> @@ -282,17 +314,48 @@ static int silead_ts_load_fw(struct i2c_client *client)
>  {
>  	struct device *dev = &client->dev;
>  	struct silead_ts_data *data = i2c_get_clientdata(client);
> -	unsigned int fw_size, i;
> -	const struct firmware *fw;
> +	const struct firmware *fw = NULL;
>  	struct silead_fw_data *fw_data;
> +	unsigned int fw_size, i;
>  	int error;
>  
>  	dev_dbg(dev, "Firmware file name: %s", data->fw_name);
>  
> -	error = firmware_request_platform(&fw, data->fw_name, dev);
> +	/*
> +	 * Unfortunately, at the time of writing this comment, we have been unable to
> +	 * get permission from Silead, or from device OEMs, to distribute the necessary
> +	 * Silead firmware files in linux-firmware.
> +	 *
> +	 * On a whole bunch of devices the UEFI BIOS code contains a touchscreen driver,
> +	 * which contains an embedded copy of the firmware. The fw-loader code has a
> +	 * "platform" fallback mechanism, which together with info on the firmware
> +	 * from drivers/platform/x86/touchscreen_dmi.c will use the firmware from the
> +	 * UEFI driver when the firmware is missing from /lib/firmware. This makes the
> +	 * touchscreen work OOTB without users needing to manually download the firmware.
> +	 *
> +	 * The firmware bundled with the original Windows/Android is usually newer then
> +	 * the firmware in the UEFI driver and it is better calibrated. This better
> +	 * calibration can lead to significant differences in the reported min/max
> +	 * coordinates.
> +	 *
> +	 * To deal with this we first try to load the firmware without "platform"
> +	 * fallback. If that fails we retry with "platform" fallback and if that
> +	 * succeeds we apply an (optional) set of alternative min/max values from the
> +	 * "silead,efi-fw-min-max" property.
> +	 */
> +	error = firmware_request_nowarn(&fw, data->fw_name, dev);
>  	if (error) {
> -		dev_err(dev, "Firmware request error %d\n", error);
> -		return error;
> +		error = firmware_request_platform(&fw, data->fw_name, dev);
> +		if (error) {
> +			dev_err(dev, "Firmware request error %d\n", error);
> +			return error;
> +		}
> +
> +		error = device_property_read_u32_array(dev, "silead,efi-fw-min-max",
> +						       data->efi_fw_min_max,
> +						       ARRAY_SIZE(data->efi_fw_min_max));
> +		if (!error)
> +			data->efi_fw_min_max_set = true;
>  	}
>  
>  	fw_size = fw->size / sizeof(*fw_data);
> 




[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux