瀏覽代碼

Add the ability to load different IPTS firmware per model

Signed-off-by: Dorian Stoll <dorian.stoll@tmsp.io>
Dorian Stoll 5 年之前
父節點
當前提交
de86889877
共有 2 個文件被更改,包括 738 次插入84 次删除
  1. 371 44
      patches/4.19/0005-ipts.patch
  2. 367 40
      patches/5.2/0005-ipts.patch

+ 371 - 44
patches/4.19/0005-ipts.patch

@@ -1,4 +1,4 @@
-From d8171f6c5a5cdaad6171eda7bed33ebcd33c0323 Mon Sep 17 00:00:00 2001
+From 22e6d68a0a5c874507cd7af75f6945b2f0b38cf9 Mon Sep 17 00:00:00 2001
 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com>
 Date: Tue, 10 Sep 2019 21:52:46 +0900
 Subject: [PATCH 05/12] ipts
@@ -24,20 +24,27 @@ Subject: [PATCH 05/12] ipts
  drivers/hid/hid-multitouch.c                |   22 +-
  drivers/misc/Kconfig                        |    1 +
  drivers/misc/Makefile                       |    1 +
- drivers/misc/ipts/Kconfig                   |    9 +
- drivers/misc/ipts/Makefile                  |   13 +
+ drivers/misc/ipts/Kconfig                   |   11 +
+ drivers/misc/ipts/Makefile                  |   17 +
+ drivers/misc/ipts/companion/Kconfig         |    9 +
+ drivers/misc/ipts/companion/Makefile        |    1 +
+ drivers/misc/ipts/companion/ipts-surface.c  |   82 ++
  drivers/misc/ipts/ipts-binary-spec.h        |  118 +++
  drivers/misc/ipts/ipts-dbgfs.c              |  364 +++++++
+ drivers/misc/ipts/ipts-fw.c                 |  113 ++
+ drivers/misc/ipts/ipts-fw.h                 |   12 +
  drivers/misc/ipts/ipts-gfx.c                |  185 ++++
  drivers/misc/ipts/ipts-gfx.h                |   24 +
- drivers/misc/ipts/ipts-hid.c                |  504 +++++++++
+ drivers/misc/ipts/ipts-hid.c                |  503 +++++++++
  drivers/misc/ipts/ipts-hid.h                |   34 +
- drivers/misc/ipts/ipts-kernel.c             | 1050 +++++++++++++++++++
+ drivers/misc/ipts/ipts-kernel.c             | 1042 +++++++++++++++++++
  drivers/misc/ipts/ipts-kernel.h             |   23 +
  drivers/misc/ipts/ipts-mei-msgs.h           |  585 +++++++++++
- drivers/misc/ipts/ipts-mei.c                |  282 +++++
+ drivers/misc/ipts/ipts-mei.c                |  290 ++++++
  drivers/misc/ipts/ipts-msg-handler.c        |  437 ++++++++
  drivers/misc/ipts/ipts-msg-handler.h        |   33 +
+ drivers/misc/ipts/ipts-params.c             |   14 +
+ drivers/misc/ipts/ipts-params.h             |   13 +
  drivers/misc/ipts/ipts-resource.c           |  277 +++++
  drivers/misc/ipts/ipts-resource.h           |   30 +
  drivers/misc/ipts/ipts-sensor-regs.h        |  700 +++++++++++++
@@ -45,14 +52,20 @@ Subject: [PATCH 05/12] ipts
  drivers/misc/ipts/ipts.h                    |  200 ++++
  drivers/misc/mei/hw-me-regs.h               |    1 +
  drivers/misc/mei/pci-me.c                   |    1 +
+ include/linux/intel_ipts_fw.h               |   14 +
  include/linux/intel_ipts_if.h               |   76 ++
- 42 files changed, 5889 insertions(+), 26 deletions(-)
+ 50 files changed, 6152 insertions(+), 26 deletions(-)
  create mode 100644 drivers/gpu/drm/i915/intel_ipts.c
  create mode 100644 drivers/gpu/drm/i915/intel_ipts.h
  create mode 100644 drivers/misc/ipts/Kconfig
  create mode 100644 drivers/misc/ipts/Makefile
+ create mode 100644 drivers/misc/ipts/companion/Kconfig
+ create mode 100644 drivers/misc/ipts/companion/Makefile
+ create mode 100644 drivers/misc/ipts/companion/ipts-surface.c
  create mode 100644 drivers/misc/ipts/ipts-binary-spec.h
  create mode 100644 drivers/misc/ipts/ipts-dbgfs.c
+ create mode 100644 drivers/misc/ipts/ipts-fw.c
+ create mode 100644 drivers/misc/ipts/ipts-fw.h
  create mode 100644 drivers/misc/ipts/ipts-gfx.c
  create mode 100644 drivers/misc/ipts/ipts-gfx.h
  create mode 100644 drivers/misc/ipts/ipts-hid.c
@@ -63,11 +76,14 @@ Subject: [PATCH 05/12] ipts
  create mode 100644 drivers/misc/ipts/ipts-mei.c
  create mode 100644 drivers/misc/ipts/ipts-msg-handler.c
  create mode 100644 drivers/misc/ipts/ipts-msg-handler.h
+ create mode 100644 drivers/misc/ipts/ipts-params.c
+ create mode 100644 drivers/misc/ipts/ipts-params.h
  create mode 100644 drivers/misc/ipts/ipts-resource.c
  create mode 100644 drivers/misc/ipts/ipts-resource.h
  create mode 100644 drivers/misc/ipts/ipts-sensor-regs.h
  create mode 100644 drivers/misc/ipts/ipts-state.h
  create mode 100644 drivers/misc/ipts/ipts.h
+ create mode 100644 include/linux/intel_ipts_fw.h
  create mode 100644 include/linux/intel_ipts_if.h
 
 diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
@@ -85,7 +101,7 @@ index 5794f102f9b8..6ae0e91a213a 100644
  i915-$(CONFIG_DRM_I915_CAPTURE_ERROR) += i915_gpu_error.o
  i915-$(CONFIG_DRM_I915_SELFTEST) += \
 diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
-index f9ce35da4123..c8b88b1b7bd4 100644
+index e063e98d1e82..32d648c8adc5 100644
 --- a/drivers/gpu/drm/i915/i915_debugfs.c
 +++ b/drivers/gpu/drm/i915/i915_debugfs.c
 @@ -31,6 +31,7 @@
@@ -96,7 +112,7 @@ index f9ce35da4123..c8b88b1b7bd4 100644
  
  static inline struct drm_i915_private *node_to_i915(struct drm_info_node *node)
  {
-@@ -4691,6 +4692,64 @@ static const struct file_operations i915_fifo_underrun_reset_ops = {
+@@ -4695,6 +4696,64 @@ static const struct file_operations i915_fifo_underrun_reset_ops = {
  	.llseek = default_llseek,
  };
  
@@ -161,7 +177,7 @@ index f9ce35da4123..c8b88b1b7bd4 100644
  static const struct drm_info_list i915_debugfs_list[] = {
  	{"i915_capabilities", i915_capabilities, 0},
  	{"i915_gem_objects", i915_gem_object_info, 0},
-@@ -4769,7 +4828,9 @@ static const struct i915_debugfs_files {
+@@ -4773,7 +4832,9 @@ static const struct i915_debugfs_files {
  	{"i915_hpd_storm_ctl", &i915_hpd_storm_ctl_fops},
  	{"i915_ipc_status", &i915_ipc_status_fops},
  	{"i915_drrs_ctl", &i915_drrs_ctl_fops},
@@ -313,7 +329,7 @@ index 6c4d4a21474b..4ab800c3de6d 100644
  #define MEMBER(T, member, ...) T member;
  struct i915_params {
 diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
-index f92079e19de8..7c2d78044035 100644
+index 20cd4c8acecc..6ec301a91e87 100644
 --- a/drivers/gpu/drm/i915/intel_dp.c
 +++ b/drivers/gpu/drm/i915/intel_dp.c
 @@ -2634,8 +2634,8 @@ void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
@@ -1385,10 +1401,10 @@ index af22bbc3d00c..eb1eb0d58c32 100644
  obj-$(CONFIG_SRAM)		+= sram.o
 diff --git a/drivers/misc/ipts/Kconfig b/drivers/misc/ipts/Kconfig
 new file mode 100644
-index 000000000000..360ed3861b82
+index 000000000000..a24c4daaed42
 --- /dev/null
 +++ b/drivers/misc/ipts/Kconfig
-@@ -0,0 +1,9 @@
+@@ -0,0 +1,11 @@
 +config INTEL_IPTS
 +	tristate "Intel Precise Touch & Stylus"
 +	select INTEL_MEI
@@ -1398,25 +1414,141 @@ index 000000000000..360ed3861b82
 +	  Supported SoCs:
 +	  Intel Skylake
 +	  Intel Kabylake
++
++source "drivers/misc/ipts/companion/Kconfig"
 diff --git a/drivers/misc/ipts/Makefile b/drivers/misc/ipts/Makefile
 new file mode 100644
-index 000000000000..1783e9cf13c9
+index 000000000000..78bb61933387
 --- /dev/null
 +++ b/drivers/misc/ipts/Makefile
-@@ -0,0 +1,13 @@
+@@ -0,0 +1,17 @@
 +#
 +# Makefile - Intel Precise Touch & Stylus device driver
 +# Copyright (c) 2016, Intel Corporation.
 +#
 +
 +obj-$(CONFIG_INTEL_IPTS)+= intel-ipts.o
++intel-ipts-objs += ipts-fw.o
 +intel-ipts-objs += ipts-mei.o
 +intel-ipts-objs += ipts-hid.o
 +intel-ipts-objs += ipts-msg-handler.o
 +intel-ipts-objs += ipts-kernel.o
++intel-ipts-objs += ipts-params.o
 +intel-ipts-objs += ipts-resource.o
 +intel-ipts-objs += ipts-gfx.o
 +intel-ipts-$(CONFIG_DEBUG_FS) += ipts-dbgfs.o
++
++obj-y += companion/
+diff --git a/drivers/misc/ipts/companion/Kconfig b/drivers/misc/ipts/companion/Kconfig
+new file mode 100644
+index 000000000000..877a04494779
+--- /dev/null
++++ b/drivers/misc/ipts/companion/Kconfig
+@@ -0,0 +1,9 @@
++config INTEL_IPTS_SURFACE
++	tristate "IPTS companion driver for Microsoft Surface"
++	depends on INTEL_IPTS
++	depends on ACPI
++	help
++	  IPTS companion driver for Microsoft Surface. This driver is responsible
++	  for loading firmware using surface-specific hardware IDs.
++
++	  If you have a Microsoft Surface using IPTS, select y or m here.
+diff --git a/drivers/misc/ipts/companion/Makefile b/drivers/misc/ipts/companion/Makefile
+new file mode 100644
+index 000000000000..fb4d58935f01
+--- /dev/null
++++ b/drivers/misc/ipts/companion/Makefile
+@@ -0,0 +1 @@
++obj-$(CONFIG_INTEL_IPTS_SURFACE)+= ipts-surface.o
+diff --git a/drivers/misc/ipts/companion/ipts-surface.c b/drivers/misc/ipts/companion/ipts-surface.c
+new file mode 100644
+index 000000000000..4d6116dfa728
+--- /dev/null
++++ b/drivers/misc/ipts/companion/ipts-surface.c
+@@ -0,0 +1,82 @@
++#include <linux/acpi.h>
++#include <linux/firmware.h>
++#include <linux/intel_ipts_fw.h>
++#include <linux/intel_ipts_if.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#define IPTS_SURFACE_FW_PATH_FMT "intel/ipts/%s/%s"
++
++int ipts_surface_request_firmware(const struct firmware **fw, const char *name,
++	struct device *device, void *data)
++{
++	char fw_path[MAX_IOCL_FILE_PATH_LEN];
++
++	if (data == NULL) {
++		return -ENOENT;
++	}
++
++	snprintf(fw_path, MAX_IOCL_FILE_PATH_LEN, IPTS_SURFACE_FW_PATH_FMT,
++		(const char *)data, name);
++	return request_firmware(fw, fw_path, device);
++}
++
++static int ipts_surface_probe(struct platform_device *pdev)
++{
++	int ret;
++	struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
++
++	if (!adev) {
++		dev_err(&pdev->dev, "Unable to find ACPI info for device\n");
++		return -ENODEV;
++	}
++
++	ret = intel_ipts_add_fw_handler(&ipts_surface_request_firmware,
++		(void *)acpi_device_hid(adev));
++	if (ret) {
++		dev_info(&pdev->dev, "Adding IPTS firmware handler failed, "
++			"error: %d\n", ret);
++		return ret;
++	}
++
++	return 0;
++}
++
++static int ipts_surface_remove(struct platform_device *pdev)
++{
++	int ret;
++
++	ret = intel_ipts_rm_fw_handler(&ipts_surface_request_firmware);
++	if (ret) {
++		dev_info(&pdev->dev, "Removing IPTS firmware handler failed, "
++			"error: %d\n", ret);
++	}
++
++	return 0;
++}
++
++static const struct acpi_device_id ipts_surface_acpi_match[] = {
++	{ "MSHW0076", 0 },	/* Surface Book 1 / Surface Studio */
++	{ "MSHW0078", 0 },	/* Surface Pro 4 */
++	{ "MSHW0079", 0 },	/* Surface Laptop 1 / 2 */
++	{ "MSHW0101", 0 },	/* Surface Book 2 15" */
++	{ "MSHW0102", 0 },	/* Surface Pro 2017 / 6 */
++	{ "MSHW0103", 0 },	/* unknown, but firmware exists */
++	{ "MSHW0137", 0 },	/* Surface Book 2 */
++	{ },
++};
++MODULE_DEVICE_TABLE(acpi, ipts_surface_acpi_match);
++
++static struct platform_driver ipts_surface_driver = {
++	.probe = ipts_surface_probe,
++	.remove = ipts_surface_remove,
++	.driver = {
++		.name = "ipts_surface",
++		.acpi_match_table = ACPI_PTR(ipts_surface_acpi_match),
++	},
++};
++module_platform_driver(ipts_surface_driver);
++
++MODULE_AUTHOR("Dorian Stoll <dorian.stoll@tmsp.io>");
++MODULE_DESCRIPTION("IPTS companion driver for Microsoft Surface");
++MODULE_LICENSE("GPL v2");
 diff --git a/drivers/misc/ipts/ipts-binary-spec.h b/drivers/misc/ipts/ipts-binary-spec.h
 new file mode 100644
 index 000000000000..87d4bc4133c4
@@ -1911,6 +2043,143 @@ index 000000000000..7581b21f81e0
 +	ipts_dbgfs_deregister(ipts);
 +	return -ENODEV;
 +}
+diff --git a/drivers/misc/ipts/ipts-fw.c b/drivers/misc/ipts/ipts-fw.c
+new file mode 100644
+index 000000000000..82e6e44c9908
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-fw.c
+@@ -0,0 +1,113 @@
++#include <linux/firmware.h>
++#include <linux/intel_ipts_fw.h>
++#include <linux/intel_ipts_if.h>
++#include <linux/mutex.h>
++
++#include "ipts.h"
++#include "ipts-fw.h"
++#include "ipts-params.h"
++
++#define IPTS_GENERIC_FW_PATH_FMT "intel/ipts/%s"
++
++/*
++ * This function pointer allows a companion driver to register a custom logic
++ * for loading firmware files. This can be used to detect devices that can
++ * be used for IPTS versioning, but that are not connected over the MEI bus,
++ * and cannot be detected by the ME driver.
++ */
++IPTS_FW_HANDLER(ipts_fw_handler);
++DEFINE_MUTEX(ipts_fw_handler_lock);
++void *ipts_fw_handler_data = NULL;
++
++bool ipts_fw_handler_available(void)
++{
++	bool ret;
++	mutex_lock(&ipts_fw_handler_lock);
++
++	ret = ipts_fw_handler != NULL;
++
++	mutex_unlock(&ipts_fw_handler_lock);
++	return ret;
++}
++
++int intel_ipts_add_fw_handler(IPTS_FW_HANDLER(handler), void *data)
++{
++	int ret = 0;
++	mutex_lock(&ipts_fw_handler_lock);
++
++	if (ipts_fw_handler != NULL) {
++		ret = -EBUSY;
++		goto ipts_add_fw_handler_return;
++	}
++
++	ipts_fw_handler = handler;
++	ipts_fw_handler_data = data;
++
++ipts_add_fw_handler_return:
++
++	mutex_unlock(&ipts_fw_handler_lock);
++	return ret;
++}
++EXPORT_SYMBOL(intel_ipts_add_fw_handler);
++
++int intel_ipts_rm_fw_handler(IPTS_FW_HANDLER(handler))
++{
++	int ret = 0;
++	mutex_lock(&ipts_fw_handler_lock);
++
++	if (ipts_fw_handler == NULL) {
++		ret = 0;
++		goto ipts_rm_fw_handler_return;
++	}
++
++	if (*handler != *ipts_fw_handler) {
++		ret = -EPERM;
++		goto ipts_rm_fw_handler_return;
++	}
++
++	ipts_fw_handler = NULL;
++	ipts_fw_handler_data = NULL;
++
++ipts_rm_fw_handler_return:
++
++	mutex_unlock(&ipts_fw_handler_lock);
++	return ret;
++}
++EXPORT_SYMBOL(intel_ipts_rm_fw_handler);
++
++int ipts_request_firmware(const struct firmware **fw, const char *name,
++	struct device *device)
++{
++	int ret = 0;
++	char fw_path[MAX_IOCL_FILE_PATH_LEN];
++	mutex_lock(&ipts_fw_handler_lock);
++
++	// Check if a firmware handler was registered. If not, skip
++	// forward and try to load the firmware from the legacy path
++	if (ipts_fw_handler == NULL || ipts_modparams.ignore_companion) {
++		goto ipts_request_firmware_fallback;
++	}
++
++	ret = (*ipts_fw_handler)(fw, name, device, ipts_fw_handler_data);
++	if (!ret) {
++		goto ipts_request_firmware_return;
++	}
++
++ipts_request_firmware_fallback:
++
++	// If fallback loading for firmware was disabled, abort.
++	// Return -ENOENT as no firmware file was found.
++	if (ipts_modparams.ignore_fw_fallback) {
++		ret = -ENOENT;
++		goto ipts_request_firmware_return;
++	}
++
++	// No firmware was found by the companion driver, try the generic path now.
++	snprintf(fw_path, MAX_IOCL_FILE_PATH_LEN, IPTS_GENERIC_FW_PATH_FMT, name);
++	ret = request_firmware(fw, fw_path, device);
++
++ipts_request_firmware_return:
++
++	mutex_unlock(&ipts_fw_handler_lock);
++	return ret;
++}
+diff --git a/drivers/misc/ipts/ipts-fw.h b/drivers/misc/ipts/ipts-fw.h
+new file mode 100644
+index 000000000000..4c1c9a0dd77f
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-fw.h
+@@ -0,0 +1,12 @@
++#ifndef _IPTS_FW_H_
++#define _IPTS_FW_H_
++
++#include <linux/firmware.h>
++
++#include "ipts.h"
++
++int ipts_request_firmware(const struct firmware **fw, const char *name,
++	struct device *device);
++bool ipts_fw_handler_available(void);
++
++#endif // _IPTS_FW_H_
 diff --git a/drivers/misc/ipts/ipts-gfx.c b/drivers/misc/ipts/ipts-gfx.c
 new file mode 100644
 index 000000000000..4989a22227d2
@@ -2134,10 +2403,10 @@ index 000000000000..03a5f3551ddf
 +#endif // _IPTS_GFX_H_
 diff --git a/drivers/misc/ipts/ipts-hid.c b/drivers/misc/ipts/ipts-hid.c
 new file mode 100644
-index 000000000000..84e3fb6c34be
+index 000000000000..41c6508f1235
 --- /dev/null
 +++ b/drivers/misc/ipts/ipts-hid.c
-@@ -0,0 +1,504 @@
+@@ -0,0 +1,503 @@
 +/*
 + * Intel Precise Touch & Stylus HID driver
 + *
@@ -2160,16 +2429,15 @@ index 000000000000..84e3fb6c34be
 +#include <linux/dmi.h>
 +
 +#include "ipts.h"
++#include "ipts-fw.h"
 +#include "ipts-resource.h"
 +#include "ipts-sensor-regs.h"
 +#include "ipts-msg-handler.h"
 +
 +#define BUS_MEI				0x44
 +
-+#define	HID_DESC_INTEL	"intel/ipts/intel_desc.bin"
-+#define	HID_DESC_VENDOR	"intel/ipts/vendor_desc.bin"
-+MODULE_FIRMWARE(HID_DESC_INTEL);
-+MODULE_FIRMWARE(HID_DESC_VENDOR);
++#define	HID_DESC_INTEL	"intel_desc.bin"
++#define	HID_DESC_VENDOR	"vendor_desc.bin"
 +
 +typedef enum output_buffer_payload_type {
 +	OUTPUT_BUFFER_PAYLOAD_ERROR = 0,
@@ -2228,13 +2496,13 @@ index 000000000000..84e3fb6c34be
 +	const char *intel_desc_path = HID_DESC_INTEL;
 +	const char *vendor_desc_path = HID_DESC_VENDOR;
 +
-+	ret = request_firmware(&intel_desc, intel_desc_path, &ipts->cldev->dev);
++	ret = ipts_request_firmware(&intel_desc, intel_desc_path, &ipts->cldev->dev);
 +	if (ret) {
 +		goto no_hid;
 +	}
 +	hid_size = intel_desc->size;
 +
-+	ret = request_firmware(&vendor_desc, vendor_desc_path, &ipts->cldev->dev);
++	ret = ipts_request_firmware(&vendor_desc, vendor_desc_path, &ipts->cldev->dev);
 +	if (ret) {
 +		ipts_dbg(ipts, "error in reading HID Vendor Descriptor\n");
 +	} else {
@@ -2684,25 +2952,24 @@ index 000000000000..f1b22c912df7
 +#endif /* _IPTS_HID_H_ */
 diff --git a/drivers/misc/ipts/ipts-kernel.c b/drivers/misc/ipts/ipts-kernel.c
 new file mode 100644
-index 000000000000..86fd359d2eed
+index 000000000000..5933b190cdaf
 --- /dev/null
 +++ b/drivers/misc/ipts/ipts-kernel.c
-@@ -0,0 +1,1050 @@
+@@ -0,0 +1,1042 @@
 +#include <linux/module.h>
 +#include <linux/firmware.h>
 +#include <linux/vmalloc.h>
++#include <linux/intel_ipts_fw.h>
 +#include <linux/intel_ipts_if.h>
 +
 +#include "ipts.h"
++#include "ipts-fw.h"
 +#include "ipts-resource.h"
 +#include "ipts-binary-spec.h"
 +#include "ipts-state.h"
 +#include "ipts-msg-handler.h"
 +#include "ipts-gfx.h"
 +
-+#define MAX_IOCL_FILE_NAME_LEN		80
-+#define MAX_IOCL_FILE_PATH_LEN		256
-+
 +#pragma pack(1)
 +typedef struct bin_data_file_info {
 +    u32 io_buffer_type;
@@ -2784,10 +3051,7 @@ index 000000000000..86fd359d2eed
 +#define SBA_OFFSET_BYTES			16384
 +#define LASTSUBMITID_DEFAULT_VALUE		-1
 +
-+#define IPTS_FW_PATH_FMT			"intel/ipts/%s"
-+#define IPTS_FW_CONFIG_FILE			"intel/ipts/ipts_fw_config.bin"
-+
-+MODULE_FIRMWARE(IPTS_FW_CONFIG_FILE);
++#define IPTS_FW_CONFIG_FILE			"ipts_fw_config.bin"
 +
 +#define IPTS_INPUT_ON				((u32)1 << IPTS_INPUT)
 +#define IPTS_OUTPUT_ON				((u32)1 << IPTS_OUTPUT)
@@ -2802,13 +3066,11 @@ index 000000000000..86fd359d2eed
 +						u8* data, int size)
 +{
 +	const struct firmware *fw = NULL;
-+	char fw_path[MAX_IOCL_FILE_PATH_LEN];
 +	int ret = 0;
 +
-+	snprintf(fw_path, MAX_IOCL_FILE_PATH_LEN, IPTS_FW_PATH_FMT, fw_name);
-+	ret = request_firmware(&fw, fw_path, &ipts->cldev->dev);
++	ret = ipts_request_firmware(&fw, fw_name, &ipts->cldev->dev);
 +	if (ret) {
-+		ipts_err(ipts, "cannot read fw %s\n", fw_path);
++		ipts_err(ipts, "cannot read fw %s\n", fw_name);
 +		return ret;
 +	}
 +
@@ -3587,7 +3849,6 @@ index 000000000000..86fd359d2eed
 +	bin_parse_info_t parse_info;
 +	int ret = 0, kernel_idx = 0, num_of_kernels = 0;
 +	int vendor_output_idx, total_workload = 0;
-+	char fw_path[MAX_IOCL_FILE_PATH_LEN];
 +
 +	num_of_kernels = fw_list->num_of_fws;
 +	kernel_list = vmalloc(sizeof(*kernel) * num_of_kernels + sizeof(*kernel_list));
@@ -3603,10 +3864,9 @@ index 000000000000..86fd359d2eed
 +		fw_info = (bin_fw_info_t *)fw_data;
 +		fw_name = &fw_info->fw_name[0];
 +		vendor_output_idx = fw_info->vendor_output;
-+		snprintf(fw_path, MAX_IOCL_FILE_PATH_LEN, IPTS_FW_PATH_FMT, fw_name);
-+		ret = request_firmware(&fw, (const char *)fw_path, &ipts->cldev->dev);
++		ret = ipts_request_firmware(&fw, fw_name, &ipts->cldev->dev);
 +		if (ret) {
-+			ipts_err(ipts, "cannot read fw %s\n", fw_path);
++			ipts_err(ipts, "cannot read fw %s\n", fw_name);
 +			goto error_exit;
 +		}
 +
@@ -3707,7 +3967,7 @@ index 000000000000..86fd359d2eed
 +		return ret;
 +	}
 +
-+	ret = request_firmware(&config_fw, config_fw_path, &ipts->cldev->dev);
++	ret = ipts_request_firmware(&config_fw, config_fw_path,	&ipts->cldev->dev);
 +	if (ret) {
 +		ipts_err(ipts, "request firmware error : %d\n", ret);
 +		goto close_gpu;
@@ -4360,10 +4620,10 @@ index 000000000000..8ca146800a47
 +#endif // _IPTS_MEI_MSGS_H_
 diff --git a/drivers/misc/ipts/ipts-mei.c b/drivers/misc/ipts/ipts-mei.c
 new file mode 100644
-index 000000000000..199e49cb8d70
+index 000000000000..6fbe257bc7cc
 --- /dev/null
 +++ b/drivers/misc/ipts/ipts-mei.c
-@@ -0,0 +1,282 @@
+@@ -0,0 +1,290 @@
 +/*
 + * MEI client driver for Intel Precise Touch and Stylus
 + *
@@ -4388,7 +4648,9 @@ index 000000000000..199e49cb8d70
 +#include <linux/intel_ipts_if.h>
 +
 +#include "ipts.h"
++#include "ipts-fw.h"
 +#include "ipts-hid.h"
++#include "ipts-params.h"
 +#include "ipts-msg-handler.h"
 +#include "ipts-mei-msgs.h"
 +#include "ipts-binary-spec.h"
@@ -4540,6 +4802,12 @@ index 000000000000..199e49cb8d70
 +	int ret = 0;
 +	ipts_info_t *ipts = NULL;
 +
++	// Check if a companion driver for firmware loading was registered
++	// If not, defer probing until it was properly registere
++	if (!ipts_fw_handler_available() && !ipts_modparams.ignore_companion) {
++		return -EPROBE_DEFER;
++	}
++
 +	pr_info("probing Intel Precise Touch & Stylus\n");
 +
 +	// setup the DMA BIT mask, the system will choose the best possible
@@ -5128,6 +5396,45 @@ index 000000000000..f37d9ad9af8c
 +int ipts_restart(ipts_info_t *ipts);
 +
 +#endif /* _IPTS_MSG_HANDLER_H */
+diff --git a/drivers/misc/ipts/ipts-params.c b/drivers/misc/ipts/ipts-params.c
+new file mode 100644
+index 000000000000..17374039a161
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-params.c
+@@ -0,0 +1,14 @@
++#include <linux/moduleparam.h>
++
++#include "ipts-params.h"
++
++struct ipts_params ipts_modparams = {
++	.ignore_fw_fallback = false,
++	.ignore_companion = false,
++};
++
++module_param_named(ignore_fw_fallback, ipts_modparams.ignore_fw_fallback, bool, 0400);
++MODULE_PARM_DESC(ignore_fw_fallback, "Don't use the IPTS firmware fallback path");
++
++module_param_named(ignore_companion, ipts_modparams.ignore_companion, bool, 0400);
++MODULE_PARM_DESC(ignore_companion, "Don't use a companion driver to load firmware");
+diff --git a/drivers/misc/ipts/ipts-params.h b/drivers/misc/ipts/ipts-params.h
+new file mode 100644
+index 000000000000..d6f6faaef076
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-params.h
+@@ -0,0 +1,13 @@
++#ifndef _IPTS_PARAMS_H_
++#define _IPTS_PARAMS_H_
++
++#include <linux/types.h>
++
++struct ipts_params {
++	bool ignore_fw_fallback;
++	bool ignore_companion;
++};
++
++extern struct ipts_params ipts_modparams;
++
++#endif // _IPTS_PARAMS_H_
 diff --git a/drivers/misc/ipts/ipts-resource.c b/drivers/misc/ipts/ipts-resource.c
 new file mode 100644
 index 000000000000..47607ef7c461
@@ -6418,6 +6725,26 @@ index e41f9e0a3fdf..e61be367d7e4 100644
  	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H, MEI_ME_PCH8_SPS_CFG)},
  	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H_2, MEI_ME_PCH8_SPS_CFG)},
  	{MEI_PCI_DEVICE(MEI_DEV_ID_LBG, MEI_ME_PCH12_CFG)},
+diff --git a/include/linux/intel_ipts_fw.h b/include/linux/intel_ipts_fw.h
+new file mode 100644
+index 000000000000..adbfd29459a2
+--- /dev/null
++++ b/include/linux/intel_ipts_fw.h
+@@ -0,0 +1,14 @@
++#ifndef _INTEL_IPTS_FW_H_
++#define _INTEL_IPTS_FW_H_
++
++#include <linux/firmware.h>
++
++#define MAX_IOCL_FILE_NAME_LEN 80
++#define MAX_IOCL_FILE_PATH_LEN 256
++#define IPTS_FW_HANDLER(name) int(*name)(const struct firmware **, \
++	const char *, struct device *, void *)
++
++int intel_ipts_add_fw_handler(IPTS_FW_HANDLER(handler), void *data);
++int intel_ipts_rm_fw_handler(IPTS_FW_HANDLER(handler));
++
++#endif // _INTEL_IPTS_FW_H_
 diff --git a/include/linux/intel_ipts_if.h b/include/linux/intel_ipts_if.h
 new file mode 100644
 index 000000000000..bad44fb4f233
@@ -6501,5 +6828,5 @@ index 000000000000..bad44fb4f233
 +
 +#endif // INTEL_IPTS_IF_H
 -- 
-2.23.0
+2.21.0
 

+ 367 - 40
patches/5.2/0005-ipts.patch

@@ -1,4 +1,4 @@
-From 36650ae8bf4456b65601e46b23a3e1595009934e Mon Sep 17 00:00:00 2001
+From b67b956e393fffdecb0c0e8588536093ec177757 Mon Sep 17 00:00:00 2001
 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com>
 Date: Tue, 10 Sep 2019 21:54:42 +0900
 Subject: [PATCH 05/12] ipts
@@ -24,20 +24,27 @@ Subject: [PATCH 05/12] ipts
  drivers/hid/hid-multitouch.c                |   22 +-
  drivers/misc/Kconfig                        |    1 +
  drivers/misc/Makefile                       |    1 +
- drivers/misc/ipts/Kconfig                   |    9 +
- drivers/misc/ipts/Makefile                  |   13 +
+ drivers/misc/ipts/Kconfig                   |   11 +
+ drivers/misc/ipts/Makefile                  |   17 +
+ drivers/misc/ipts/companion/Kconfig         |    9 +
+ drivers/misc/ipts/companion/Makefile        |    1 +
+ drivers/misc/ipts/companion/ipts-surface.c  |   82 ++
  drivers/misc/ipts/ipts-binary-spec.h        |  118 +++
  drivers/misc/ipts/ipts-dbgfs.c              |  364 +++++++
+ drivers/misc/ipts/ipts-fw.c                 |  113 ++
+ drivers/misc/ipts/ipts-fw.h                 |   12 +
  drivers/misc/ipts/ipts-gfx.c                |  185 ++++
  drivers/misc/ipts/ipts-gfx.h                |   24 +
- drivers/misc/ipts/ipts-hid.c                |  504 +++++++++
+ drivers/misc/ipts/ipts-hid.c                |  503 +++++++++
  drivers/misc/ipts/ipts-hid.h                |   34 +
- drivers/misc/ipts/ipts-kernel.c             | 1050 +++++++++++++++++++
+ drivers/misc/ipts/ipts-kernel.c             | 1042 +++++++++++++++++++
  drivers/misc/ipts/ipts-kernel.h             |   23 +
  drivers/misc/ipts/ipts-mei-msgs.h           |  585 +++++++++++
- drivers/misc/ipts/ipts-mei.c                |  282 +++++
+ drivers/misc/ipts/ipts-mei.c                |  290 ++++++
  drivers/misc/ipts/ipts-msg-handler.c        |  437 ++++++++
  drivers/misc/ipts/ipts-msg-handler.h        |   33 +
+ drivers/misc/ipts/ipts-params.c             |   14 +
+ drivers/misc/ipts/ipts-params.h             |   13 +
  drivers/misc/ipts/ipts-resource.c           |  277 +++++
  drivers/misc/ipts/ipts-resource.h           |   30 +
  drivers/misc/ipts/ipts-sensor-regs.h        |  700 +++++++++++++
@@ -45,14 +52,20 @@ Subject: [PATCH 05/12] ipts
  drivers/misc/ipts/ipts.h                    |  200 ++++
  drivers/misc/mei/hw-me-regs.h               |    1 +
  drivers/misc/mei/pci-me.c                   |    1 +
+ include/linux/intel_ipts_fw.h               |   14 +
  include/linux/intel_ipts_if.h               |   76 ++
- 42 files changed, 5889 insertions(+), 26 deletions(-)
+ 50 files changed, 6152 insertions(+), 26 deletions(-)
  create mode 100644 drivers/gpu/drm/i915/intel_ipts.c
  create mode 100644 drivers/gpu/drm/i915/intel_ipts.h
  create mode 100644 drivers/misc/ipts/Kconfig
  create mode 100644 drivers/misc/ipts/Makefile
+ create mode 100644 drivers/misc/ipts/companion/Kconfig
+ create mode 100644 drivers/misc/ipts/companion/Makefile
+ create mode 100644 drivers/misc/ipts/companion/ipts-surface.c
  create mode 100644 drivers/misc/ipts/ipts-binary-spec.h
  create mode 100644 drivers/misc/ipts/ipts-dbgfs.c
+ create mode 100644 drivers/misc/ipts/ipts-fw.c
+ create mode 100644 drivers/misc/ipts/ipts-fw.h
  create mode 100644 drivers/misc/ipts/ipts-gfx.c
  create mode 100644 drivers/misc/ipts/ipts-gfx.h
  create mode 100644 drivers/misc/ipts/ipts-hid.c
@@ -63,11 +76,14 @@ Subject: [PATCH 05/12] ipts
  create mode 100644 drivers/misc/ipts/ipts-mei.c
  create mode 100644 drivers/misc/ipts/ipts-msg-handler.c
  create mode 100644 drivers/misc/ipts/ipts-msg-handler.h
+ create mode 100644 drivers/misc/ipts/ipts-params.c
+ create mode 100644 drivers/misc/ipts/ipts-params.h
  create mode 100644 drivers/misc/ipts/ipts-resource.c
  create mode 100644 drivers/misc/ipts/ipts-resource.h
  create mode 100644 drivers/misc/ipts/ipts-sensor-regs.h
  create mode 100644 drivers/misc/ipts/ipts-state.h
  create mode 100644 drivers/misc/ipts/ipts.h
+ create mode 100644 include/linux/intel_ipts_fw.h
  create mode 100644 include/linux/intel_ipts_if.h
 
 diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
@@ -1387,10 +1403,10 @@ index b9affcdaa3d6..e681e345a9ed 100644
  obj-$(CONFIG_SRAM)		+= sram.o
 diff --git a/drivers/misc/ipts/Kconfig b/drivers/misc/ipts/Kconfig
 new file mode 100644
-index 000000000000..360ed3861b82
+index 000000000000..a24c4daaed42
 --- /dev/null
 +++ b/drivers/misc/ipts/Kconfig
-@@ -0,0 +1,9 @@
+@@ -0,0 +1,11 @@
 +config INTEL_IPTS
 +	tristate "Intel Precise Touch & Stylus"
 +	select INTEL_MEI
@@ -1400,25 +1416,141 @@ index 000000000000..360ed3861b82
 +	  Supported SoCs:
 +	  Intel Skylake
 +	  Intel Kabylake
++
++source "drivers/misc/ipts/companion/Kconfig"
 diff --git a/drivers/misc/ipts/Makefile b/drivers/misc/ipts/Makefile
 new file mode 100644
-index 000000000000..1783e9cf13c9
+index 000000000000..78bb61933387
 --- /dev/null
 +++ b/drivers/misc/ipts/Makefile
-@@ -0,0 +1,13 @@
+@@ -0,0 +1,17 @@
 +#
 +# Makefile - Intel Precise Touch & Stylus device driver
 +# Copyright (c) 2016, Intel Corporation.
 +#
 +
 +obj-$(CONFIG_INTEL_IPTS)+= intel-ipts.o
++intel-ipts-objs += ipts-fw.o
 +intel-ipts-objs += ipts-mei.o
 +intel-ipts-objs += ipts-hid.o
 +intel-ipts-objs += ipts-msg-handler.o
 +intel-ipts-objs += ipts-kernel.o
++intel-ipts-objs += ipts-params.o
 +intel-ipts-objs += ipts-resource.o
 +intel-ipts-objs += ipts-gfx.o
 +intel-ipts-$(CONFIG_DEBUG_FS) += ipts-dbgfs.o
++
++obj-y += companion/
+diff --git a/drivers/misc/ipts/companion/Kconfig b/drivers/misc/ipts/companion/Kconfig
+new file mode 100644
+index 000000000000..877a04494779
+--- /dev/null
++++ b/drivers/misc/ipts/companion/Kconfig
+@@ -0,0 +1,9 @@
++config INTEL_IPTS_SURFACE
++	tristate "IPTS companion driver for Microsoft Surface"
++	depends on INTEL_IPTS
++	depends on ACPI
++	help
++	  IPTS companion driver for Microsoft Surface. This driver is responsible
++	  for loading firmware using surface-specific hardware IDs.
++
++	  If you have a Microsoft Surface using IPTS, select y or m here.
+diff --git a/drivers/misc/ipts/companion/Makefile b/drivers/misc/ipts/companion/Makefile
+new file mode 100644
+index 000000000000..fb4d58935f01
+--- /dev/null
++++ b/drivers/misc/ipts/companion/Makefile
+@@ -0,0 +1 @@
++obj-$(CONFIG_INTEL_IPTS_SURFACE)+= ipts-surface.o
+diff --git a/drivers/misc/ipts/companion/ipts-surface.c b/drivers/misc/ipts/companion/ipts-surface.c
+new file mode 100644
+index 000000000000..4d6116dfa728
+--- /dev/null
++++ b/drivers/misc/ipts/companion/ipts-surface.c
+@@ -0,0 +1,82 @@
++#include <linux/acpi.h>
++#include <linux/firmware.h>
++#include <linux/intel_ipts_fw.h>
++#include <linux/intel_ipts_if.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#define IPTS_SURFACE_FW_PATH_FMT "intel/ipts/%s/%s"
++
++int ipts_surface_request_firmware(const struct firmware **fw, const char *name,
++	struct device *device, void *data)
++{
++	char fw_path[MAX_IOCL_FILE_PATH_LEN];
++
++	if (data == NULL) {
++		return -ENOENT;
++	}
++
++	snprintf(fw_path, MAX_IOCL_FILE_PATH_LEN, IPTS_SURFACE_FW_PATH_FMT,
++		(const char *)data, name);
++	return request_firmware(fw, fw_path, device);
++}
++
++static int ipts_surface_probe(struct platform_device *pdev)
++{
++	int ret;
++	struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
++
++	if (!adev) {
++		dev_err(&pdev->dev, "Unable to find ACPI info for device\n");
++		return -ENODEV;
++	}
++
++	ret = intel_ipts_add_fw_handler(&ipts_surface_request_firmware,
++		(void *)acpi_device_hid(adev));
++	if (ret) {
++		dev_info(&pdev->dev, "Adding IPTS firmware handler failed, "
++			"error: %d\n", ret);
++		return ret;
++	}
++
++	return 0;
++}
++
++static int ipts_surface_remove(struct platform_device *pdev)
++{
++	int ret;
++
++	ret = intel_ipts_rm_fw_handler(&ipts_surface_request_firmware);
++	if (ret) {
++		dev_info(&pdev->dev, "Removing IPTS firmware handler failed, "
++			"error: %d\n", ret);
++	}
++
++	return 0;
++}
++
++static const struct acpi_device_id ipts_surface_acpi_match[] = {
++	{ "MSHW0076", 0 },	/* Surface Book 1 / Surface Studio */
++	{ "MSHW0078", 0 },	/* Surface Pro 4 */
++	{ "MSHW0079", 0 },	/* Surface Laptop 1 / 2 */
++	{ "MSHW0101", 0 },	/* Surface Book 2 15" */
++	{ "MSHW0102", 0 },	/* Surface Pro 2017 / 6 */
++	{ "MSHW0103", 0 },	/* unknown, but firmware exists */
++	{ "MSHW0137", 0 },	/* Surface Book 2 */
++	{ },
++};
++MODULE_DEVICE_TABLE(acpi, ipts_surface_acpi_match);
++
++static struct platform_driver ipts_surface_driver = {
++	.probe = ipts_surface_probe,
++	.remove = ipts_surface_remove,
++	.driver = {
++		.name = "ipts_surface",
++		.acpi_match_table = ACPI_PTR(ipts_surface_acpi_match),
++	},
++};
++module_platform_driver(ipts_surface_driver);
++
++MODULE_AUTHOR("Dorian Stoll <dorian.stoll@tmsp.io>");
++MODULE_DESCRIPTION("IPTS companion driver for Microsoft Surface");
++MODULE_LICENSE("GPL v2");
 diff --git a/drivers/misc/ipts/ipts-binary-spec.h b/drivers/misc/ipts/ipts-binary-spec.h
 new file mode 100644
 index 000000000000..87d4bc4133c4
@@ -1913,6 +2045,143 @@ index 000000000000..7581b21f81e0
 +	ipts_dbgfs_deregister(ipts);
 +	return -ENODEV;
 +}
+diff --git a/drivers/misc/ipts/ipts-fw.c b/drivers/misc/ipts/ipts-fw.c
+new file mode 100644
+index 000000000000..82e6e44c9908
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-fw.c
+@@ -0,0 +1,113 @@
++#include <linux/firmware.h>
++#include <linux/intel_ipts_fw.h>
++#include <linux/intel_ipts_if.h>
++#include <linux/mutex.h>
++
++#include "ipts.h"
++#include "ipts-fw.h"
++#include "ipts-params.h"
++
++#define IPTS_GENERIC_FW_PATH_FMT "intel/ipts/%s"
++
++/*
++ * This function pointer allows a companion driver to register a custom logic
++ * for loading firmware files. This can be used to detect devices that can
++ * be used for IPTS versioning, but that are not connected over the MEI bus,
++ * and cannot be detected by the ME driver.
++ */
++IPTS_FW_HANDLER(ipts_fw_handler);
++DEFINE_MUTEX(ipts_fw_handler_lock);
++void *ipts_fw_handler_data = NULL;
++
++bool ipts_fw_handler_available(void)
++{
++	bool ret;
++	mutex_lock(&ipts_fw_handler_lock);
++
++	ret = ipts_fw_handler != NULL;
++
++	mutex_unlock(&ipts_fw_handler_lock);
++	return ret;
++}
++
++int intel_ipts_add_fw_handler(IPTS_FW_HANDLER(handler), void *data)
++{
++	int ret = 0;
++	mutex_lock(&ipts_fw_handler_lock);
++
++	if (ipts_fw_handler != NULL) {
++		ret = -EBUSY;
++		goto ipts_add_fw_handler_return;
++	}
++
++	ipts_fw_handler = handler;
++	ipts_fw_handler_data = data;
++
++ipts_add_fw_handler_return:
++
++	mutex_unlock(&ipts_fw_handler_lock);
++	return ret;
++}
++EXPORT_SYMBOL(intel_ipts_add_fw_handler);
++
++int intel_ipts_rm_fw_handler(IPTS_FW_HANDLER(handler))
++{
++	int ret = 0;
++	mutex_lock(&ipts_fw_handler_lock);
++
++	if (ipts_fw_handler == NULL) {
++		ret = 0;
++		goto ipts_rm_fw_handler_return;
++	}
++
++	if (*handler != *ipts_fw_handler) {
++		ret = -EPERM;
++		goto ipts_rm_fw_handler_return;
++	}
++
++	ipts_fw_handler = NULL;
++	ipts_fw_handler_data = NULL;
++
++ipts_rm_fw_handler_return:
++
++	mutex_unlock(&ipts_fw_handler_lock);
++	return ret;
++}
++EXPORT_SYMBOL(intel_ipts_rm_fw_handler);
++
++int ipts_request_firmware(const struct firmware **fw, const char *name,
++	struct device *device)
++{
++	int ret = 0;
++	char fw_path[MAX_IOCL_FILE_PATH_LEN];
++	mutex_lock(&ipts_fw_handler_lock);
++
++	// Check if a firmware handler was registered. If not, skip
++	// forward and try to load the firmware from the legacy path
++	if (ipts_fw_handler == NULL || ipts_modparams.ignore_companion) {
++		goto ipts_request_firmware_fallback;
++	}
++
++	ret = (*ipts_fw_handler)(fw, name, device, ipts_fw_handler_data);
++	if (!ret) {
++		goto ipts_request_firmware_return;
++	}
++
++ipts_request_firmware_fallback:
++
++	// If fallback loading for firmware was disabled, abort.
++	// Return -ENOENT as no firmware file was found.
++	if (ipts_modparams.ignore_fw_fallback) {
++		ret = -ENOENT;
++		goto ipts_request_firmware_return;
++	}
++
++	// No firmware was found by the companion driver, try the generic path now.
++	snprintf(fw_path, MAX_IOCL_FILE_PATH_LEN, IPTS_GENERIC_FW_PATH_FMT, name);
++	ret = request_firmware(fw, fw_path, device);
++
++ipts_request_firmware_return:
++
++	mutex_unlock(&ipts_fw_handler_lock);
++	return ret;
++}
+diff --git a/drivers/misc/ipts/ipts-fw.h b/drivers/misc/ipts/ipts-fw.h
+new file mode 100644
+index 000000000000..4c1c9a0dd77f
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-fw.h
+@@ -0,0 +1,12 @@
++#ifndef _IPTS_FW_H_
++#define _IPTS_FW_H_
++
++#include <linux/firmware.h>
++
++#include "ipts.h"
++
++int ipts_request_firmware(const struct firmware **fw, const char *name,
++	struct device *device);
++bool ipts_fw_handler_available(void);
++
++#endif // _IPTS_FW_H_
 diff --git a/drivers/misc/ipts/ipts-gfx.c b/drivers/misc/ipts/ipts-gfx.c
 new file mode 100644
 index 000000000000..4989a22227d2
@@ -2136,10 +2405,10 @@ index 000000000000..03a5f3551ddf
 +#endif // _IPTS_GFX_H_
 diff --git a/drivers/misc/ipts/ipts-hid.c b/drivers/misc/ipts/ipts-hid.c
 new file mode 100644
-index 000000000000..84e3fb6c34be
+index 000000000000..41c6508f1235
 --- /dev/null
 +++ b/drivers/misc/ipts/ipts-hid.c
-@@ -0,0 +1,504 @@
+@@ -0,0 +1,503 @@
 +/*
 + * Intel Precise Touch & Stylus HID driver
 + *
@@ -2162,16 +2431,15 @@ index 000000000000..84e3fb6c34be
 +#include <linux/dmi.h>
 +
 +#include "ipts.h"
++#include "ipts-fw.h"
 +#include "ipts-resource.h"
 +#include "ipts-sensor-regs.h"
 +#include "ipts-msg-handler.h"
 +
 +#define BUS_MEI				0x44
 +
-+#define	HID_DESC_INTEL	"intel/ipts/intel_desc.bin"
-+#define	HID_DESC_VENDOR	"intel/ipts/vendor_desc.bin"
-+MODULE_FIRMWARE(HID_DESC_INTEL);
-+MODULE_FIRMWARE(HID_DESC_VENDOR);
++#define	HID_DESC_INTEL	"intel_desc.bin"
++#define	HID_DESC_VENDOR	"vendor_desc.bin"
 +
 +typedef enum output_buffer_payload_type {
 +	OUTPUT_BUFFER_PAYLOAD_ERROR = 0,
@@ -2230,13 +2498,13 @@ index 000000000000..84e3fb6c34be
 +	const char *intel_desc_path = HID_DESC_INTEL;
 +	const char *vendor_desc_path = HID_DESC_VENDOR;
 +
-+	ret = request_firmware(&intel_desc, intel_desc_path, &ipts->cldev->dev);
++	ret = ipts_request_firmware(&intel_desc, intel_desc_path, &ipts->cldev->dev);
 +	if (ret) {
 +		goto no_hid;
 +	}
 +	hid_size = intel_desc->size;
 +
-+	ret = request_firmware(&vendor_desc, vendor_desc_path, &ipts->cldev->dev);
++	ret = ipts_request_firmware(&vendor_desc, vendor_desc_path, &ipts->cldev->dev);
 +	if (ret) {
 +		ipts_dbg(ipts, "error in reading HID Vendor Descriptor\n");
 +	} else {
@@ -2686,25 +2954,24 @@ index 000000000000..f1b22c912df7
 +#endif /* _IPTS_HID_H_ */
 diff --git a/drivers/misc/ipts/ipts-kernel.c b/drivers/misc/ipts/ipts-kernel.c
 new file mode 100644
-index 000000000000..86fd359d2eed
+index 000000000000..5933b190cdaf
 --- /dev/null
 +++ b/drivers/misc/ipts/ipts-kernel.c
-@@ -0,0 +1,1050 @@
+@@ -0,0 +1,1042 @@
 +#include <linux/module.h>
 +#include <linux/firmware.h>
 +#include <linux/vmalloc.h>
++#include <linux/intel_ipts_fw.h>
 +#include <linux/intel_ipts_if.h>
 +
 +#include "ipts.h"
++#include "ipts-fw.h"
 +#include "ipts-resource.h"
 +#include "ipts-binary-spec.h"
 +#include "ipts-state.h"
 +#include "ipts-msg-handler.h"
 +#include "ipts-gfx.h"
 +
-+#define MAX_IOCL_FILE_NAME_LEN		80
-+#define MAX_IOCL_FILE_PATH_LEN		256
-+
 +#pragma pack(1)
 +typedef struct bin_data_file_info {
 +    u32 io_buffer_type;
@@ -2786,10 +3053,7 @@ index 000000000000..86fd359d2eed
 +#define SBA_OFFSET_BYTES			16384
 +#define LASTSUBMITID_DEFAULT_VALUE		-1
 +
-+#define IPTS_FW_PATH_FMT			"intel/ipts/%s"
-+#define IPTS_FW_CONFIG_FILE			"intel/ipts/ipts_fw_config.bin"
-+
-+MODULE_FIRMWARE(IPTS_FW_CONFIG_FILE);
++#define IPTS_FW_CONFIG_FILE			"ipts_fw_config.bin"
 +
 +#define IPTS_INPUT_ON				((u32)1 << IPTS_INPUT)
 +#define IPTS_OUTPUT_ON				((u32)1 << IPTS_OUTPUT)
@@ -2804,13 +3068,11 @@ index 000000000000..86fd359d2eed
 +						u8* data, int size)
 +{
 +	const struct firmware *fw = NULL;
-+	char fw_path[MAX_IOCL_FILE_PATH_LEN];
 +	int ret = 0;
 +
-+	snprintf(fw_path, MAX_IOCL_FILE_PATH_LEN, IPTS_FW_PATH_FMT, fw_name);
-+	ret = request_firmware(&fw, fw_path, &ipts->cldev->dev);
++	ret = ipts_request_firmware(&fw, fw_name, &ipts->cldev->dev);
 +	if (ret) {
-+		ipts_err(ipts, "cannot read fw %s\n", fw_path);
++		ipts_err(ipts, "cannot read fw %s\n", fw_name);
 +		return ret;
 +	}
 +
@@ -3589,7 +3851,6 @@ index 000000000000..86fd359d2eed
 +	bin_parse_info_t parse_info;
 +	int ret = 0, kernel_idx = 0, num_of_kernels = 0;
 +	int vendor_output_idx, total_workload = 0;
-+	char fw_path[MAX_IOCL_FILE_PATH_LEN];
 +
 +	num_of_kernels = fw_list->num_of_fws;
 +	kernel_list = vmalloc(sizeof(*kernel) * num_of_kernels + sizeof(*kernel_list));
@@ -3605,10 +3866,9 @@ index 000000000000..86fd359d2eed
 +		fw_info = (bin_fw_info_t *)fw_data;
 +		fw_name = &fw_info->fw_name[0];
 +		vendor_output_idx = fw_info->vendor_output;
-+		snprintf(fw_path, MAX_IOCL_FILE_PATH_LEN, IPTS_FW_PATH_FMT, fw_name);
-+		ret = request_firmware(&fw, (const char *)fw_path, &ipts->cldev->dev);
++		ret = ipts_request_firmware(&fw, fw_name, &ipts->cldev->dev);
 +		if (ret) {
-+			ipts_err(ipts, "cannot read fw %s\n", fw_path);
++			ipts_err(ipts, "cannot read fw %s\n", fw_name);
 +			goto error_exit;
 +		}
 +
@@ -3709,7 +3969,7 @@ index 000000000000..86fd359d2eed
 +		return ret;
 +	}
 +
-+	ret = request_firmware(&config_fw, config_fw_path, &ipts->cldev->dev);
++	ret = ipts_request_firmware(&config_fw, config_fw_path,	&ipts->cldev->dev);
 +	if (ret) {
 +		ipts_err(ipts, "request firmware error : %d\n", ret);
 +		goto close_gpu;
@@ -4362,10 +4622,10 @@ index 000000000000..8ca146800a47
 +#endif // _IPTS_MEI_MSGS_H_
 diff --git a/drivers/misc/ipts/ipts-mei.c b/drivers/misc/ipts/ipts-mei.c
 new file mode 100644
-index 000000000000..199e49cb8d70
+index 000000000000..6fbe257bc7cc
 --- /dev/null
 +++ b/drivers/misc/ipts/ipts-mei.c
-@@ -0,0 +1,282 @@
+@@ -0,0 +1,290 @@
 +/*
 + * MEI client driver for Intel Precise Touch and Stylus
 + *
@@ -4390,7 +4650,9 @@ index 000000000000..199e49cb8d70
 +#include <linux/intel_ipts_if.h>
 +
 +#include "ipts.h"
++#include "ipts-fw.h"
 +#include "ipts-hid.h"
++#include "ipts-params.h"
 +#include "ipts-msg-handler.h"
 +#include "ipts-mei-msgs.h"
 +#include "ipts-binary-spec.h"
@@ -4542,6 +4804,12 @@ index 000000000000..199e49cb8d70
 +	int ret = 0;
 +	ipts_info_t *ipts = NULL;
 +
++	// Check if a companion driver for firmware loading was registered
++	// If not, defer probing until it was properly registere
++	if (!ipts_fw_handler_available() && !ipts_modparams.ignore_companion) {
++		return -EPROBE_DEFER;
++	}
++
 +	pr_info("probing Intel Precise Touch & Stylus\n");
 +
 +	// setup the DMA BIT mask, the system will choose the best possible
@@ -5130,6 +5398,45 @@ index 000000000000..f37d9ad9af8c
 +int ipts_restart(ipts_info_t *ipts);
 +
 +#endif /* _IPTS_MSG_HANDLER_H */
+diff --git a/drivers/misc/ipts/ipts-params.c b/drivers/misc/ipts/ipts-params.c
+new file mode 100644
+index 000000000000..17374039a161
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-params.c
+@@ -0,0 +1,14 @@
++#include <linux/moduleparam.h>
++
++#include "ipts-params.h"
++
++struct ipts_params ipts_modparams = {
++	.ignore_fw_fallback = false,
++	.ignore_companion = false,
++};
++
++module_param_named(ignore_fw_fallback, ipts_modparams.ignore_fw_fallback, bool, 0400);
++MODULE_PARM_DESC(ignore_fw_fallback, "Don't use the IPTS firmware fallback path");
++
++module_param_named(ignore_companion, ipts_modparams.ignore_companion, bool, 0400);
++MODULE_PARM_DESC(ignore_companion, "Don't use a companion driver to load firmware");
+diff --git a/drivers/misc/ipts/ipts-params.h b/drivers/misc/ipts/ipts-params.h
+new file mode 100644
+index 000000000000..d6f6faaef076
+--- /dev/null
++++ b/drivers/misc/ipts/ipts-params.h
+@@ -0,0 +1,13 @@
++#ifndef _IPTS_PARAMS_H_
++#define _IPTS_PARAMS_H_
++
++#include <linux/types.h>
++
++struct ipts_params {
++	bool ignore_fw_fallback;
++	bool ignore_companion;
++};
++
++extern struct ipts_params ipts_modparams;
++
++#endif // _IPTS_PARAMS_H_
 diff --git a/drivers/misc/ipts/ipts-resource.c b/drivers/misc/ipts/ipts-resource.c
 new file mode 100644
 index 000000000000..47607ef7c461
@@ -6420,6 +6727,26 @@ index 541538eff8b1..49ab69d7a273 100644
  	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H, MEI_ME_PCH8_SPS_CFG)},
  	{MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H_2, MEI_ME_PCH8_SPS_CFG)},
  	{MEI_PCI_DEVICE(MEI_DEV_ID_LBG, MEI_ME_PCH12_CFG)},
+diff --git a/include/linux/intel_ipts_fw.h b/include/linux/intel_ipts_fw.h
+new file mode 100644
+index 000000000000..adbfd29459a2
+--- /dev/null
++++ b/include/linux/intel_ipts_fw.h
+@@ -0,0 +1,14 @@
++#ifndef _INTEL_IPTS_FW_H_
++#define _INTEL_IPTS_FW_H_
++
++#include <linux/firmware.h>
++
++#define MAX_IOCL_FILE_NAME_LEN 80
++#define MAX_IOCL_FILE_PATH_LEN 256
++#define IPTS_FW_HANDLER(name) int(*name)(const struct firmware **, \
++	const char *, struct device *, void *)
++
++int intel_ipts_add_fw_handler(IPTS_FW_HANDLER(handler), void *data);
++int intel_ipts_rm_fw_handler(IPTS_FW_HANDLER(handler));
++
++#endif // _INTEL_IPTS_FW_H_
 diff --git a/include/linux/intel_ipts_if.h b/include/linux/intel_ipts_if.h
 new file mode 100644
 index 000000000000..bad44fb4f233
@@ -6503,5 +6830,5 @@ index 000000000000..bad44fb4f233
 +
 +#endif // INTEL_IPTS_IF_H
 -- 
-2.23.0
+2.21.0