HID: mcp2221: fix probing of the I2C bus added by hid_mcp2221

Message ID 55d7a712-5862-4d51-9ec8-7479dce15f78@vigem.de
State New
Headers
Series HID: mcp2221: fix probing of the I2C bus added by hid_mcp2221 |

Commit Message

Sven Zühlsdorf Dec. 13, 2022, 2:04 p.m. UTC
  From: Karl Georg Esser <kgesser@vigem.de>
Date: Fri, 9 Dec 2022 16:17:59 +0100
Subject: [PATCH] HID: mcp2221: fix probing of the I2C bus added by hid_mcp2221

As soon as the I2C driver part will be enabled in mcp2221_probe(), the
first HID reports might be exchanged with the chip due to other drivers
probing for their devices on the just added I2C bus. HID I/O has to be
enabled explicitly during mcp2221_probe() to receive response reports.
In addition, the I2C bus' adapdata has to be set before any use of the bus,
otherwise mcp_{i2c,smbus}_xfer will attempt to dereference a NULL pointer.

Fixes: 67a95c21463d ("HID: mcp2221: add usb to i2c-smbus host bridge")
Signed-off-by: Karl Georg Esser <kgesser@vigem.de>
Signed-off-by: Sven Zühlsdorf <sven.zuehlsdorf@vigem.de>
---
  drivers/hid/hid-mcp2221.c | 10 +++++++++-
  1 file changed, 9 insertions(+), 1 deletion(-)
  

Patch

diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c
index 5886543b17f3..35b7d6939b38 100644
--- a/drivers/hid/hid-mcp2221.c
+++ b/drivers/hid/hid-mcp2221.c
@@ -324,6 +324,9 @@  static int mcp_i2c_xfer(struct i2c_adapter *adapter,
  	int ret;
  	struct mcp2221 *mcp = i2c_get_adapdata(adapter);

+	if(!mcp)
+		return -ECONNREFUSED;
+
  	hid_hw_power(mcp->hdev, PM_HINT_FULLON);

  	mutex_lock(&mcp->lock);
@@ -433,6 +436,9 @@  static int mcp_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
  	int ret;
  	struct mcp2221 *mcp = i2c_get_adapdata(adapter);

+	if(!mcp)
+		return -ECONNREFUSED;
+
  	hid_hw_power(mcp->hdev, PM_HINT_FULLON);

  	mutex_lock(&mcp->lock);
@@ -1148,12 +1154,14 @@  static int mcp2221_probe(struct hid_device *hdev,
  			"MCP2221 usb-i2c bridge on hidraw%d",
  			((struct hidraw *)hdev->hidraw)->minor);

+	i2c_set_adapdata(&mcp->adapter, mcp);
+	hid_device_io_start(hdev);
+
  	ret = devm_i2c_add_adapter(&hdev->dev, &mcp->adapter);
  	if (ret) {
  		hid_err(hdev, "can't add usb-i2c adapter: %d\n", ret);
  		return ret;
  	}
-	i2c_set_adapdata(&mcp->adapter, mcp);

  #if IS_REACHABLE(CONFIG_GPIOLIB)
  	/* Setup GPIO chip */