From 3045696d0ce663d67c95dcb8206d3de57f6841ec Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Fri, 31 Jan 2020 13:46:25 +0100
Subject: [PATCH 01/11] HID: quirks: Remove ITE 8595 entry from
 hid_have_special_driver

The ITE 8595 chip used in various 2-in-1 keyboard docks works fine with
the hid-generic driver (minus the RF_KILL key) and also keeps working fine
when swapping drivers, so there is no need to have it in the
hid_have_special_driver list.

Note the other 2 USB ids in hid-ite.c were never added to
hid_have_special_driver.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
---
 drivers/hid/hid-quirks.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 0e7b2d998395..503cfbe207ab 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -397,9 +397,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A0C2) },
 #endif
-#if IS_ENABLED(CONFIG_HID_ITE)
-	{ HID_USB_DEVICE(USB_VENDOR_ID_ITE, USB_DEVICE_ID_ITE8595) },
-#endif
 #if IS_ENABLED(CONFIG_HID_ICADE)
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) },
 #endif

From 630dd6eaffc8adb11885b51d232c987415657230 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Filipe=20La=C3=ADns?= <lains@archlinux.org>
Date: Mon, 13 Jan 2020 19:23:00 +0000
Subject: [PATCH 02/11] HID: logitech-dj: add debug msg when exporting a HID++
 report descriptors
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

When exporting all other types of report descriptors we print a debug
message. Not doing so for HID++ descriptors makes unaware users think
that no HID++ descriptor was exported.

Signed-off-by: Filipe Laíns <lains@archlinux.org>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
---
 drivers/hid/hid-logitech-dj.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index bb50d6e7745b..37e54a401452 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -1368,6 +1368,8 @@ static int logi_dj_ll_parse(struct hid_device *hid)
 	}
 
 	if (djdev->reports_supported & HIDPP) {
+		dbg_hid("%s: sending a HID++ descriptor, reports_supported: %llx\n",
+			__func__, djdev->reports_supported);
 		rdcat(rdesc, &rsize, hidpp_descriptor,
 		      sizeof(hidpp_descriptor));
 	}

From 67a95c21463d066060b0f66d65a75d45bb386ffb Mon Sep 17 00:00:00 2001
From: Rishi Gupta <gupt21@gmail.com>
Date: Tue, 28 Jan 2020 09:48:57 +0530
Subject: [PATCH 03/11] HID: mcp2221: add usb to i2c-smbus host bridge

MCP2221 is a USB HID to I2C/SMbus host bridge device. This
commit implements i2c and smbus host adapter support. 7-bit
address and i2c multi-message transaction is also supported.

Signed-off-by: Rishi Gupta <gupt21@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
---
 MAINTAINERS               |   7 +
 drivers/hid/Kconfig       |  10 +
 drivers/hid/Makefile      |   1 +
 drivers/hid/hid-ids.h     |   1 +
 drivers/hid/hid-mcp2221.c | 742 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 761 insertions(+)
 create mode 100644 drivers/hid/hid-mcp2221.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 8f27f40d22bb..352a67fe7598 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10236,6 +10236,13 @@ F:	drivers/net/can/m_can/m_can.c
 F:	drivers/net/can/m_can/m_can.h
 F:	drivers/net/can/m_can/m_can_platform.c
 
+MCP2221A MICROCHIP USB-HID TO I2C BRIDGE DRIVER
+M:	Rishi Gupta <gupt21@gmail.com>
+L:	linux-i2c@vger.kernel.org
+L:	linux-input@vger.kernel.org
+S:	Maintained
+F:	drivers/hid/hid-mcp2221.c
+
 MCP4018 AND MCP4531 MICROCHIP DIGITAL POTENTIOMETER DRIVERS
 M:	Peter Rosin <peda@axentia.se>
 L:	linux-iio@vger.kernel.org
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 494a39e74939..5db6e6a709e0 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -1145,6 +1145,16 @@ config HID_ALPS
 	Say Y here if you have a Alps touchpads over i2c-hid or usbhid
 	and want support for its special functionalities.
 
+config HID_MCP2221
+	tristate "Microchip MCP2221 HID USB-to-I2C/SMbus host support"
+	depends on USB_HID && I2C
+	---help---
+	Provides I2C and SMBUS host adapter functionality over USB-HID
+	through MCP2221 device.
+
+	To compile this driver as a module, choose M here: the module
+	will be called hid-mcp2221.ko.
+
 endmenu
 
 endif # HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index bfefa365b1ce..21052a78a344 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_HID_LOGITECH_HIDPP)	+= hid-logitech-hidpp.o
 obj-$(CONFIG_HID_MACALLY)	+= hid-macally.o
 obj-$(CONFIG_HID_MAGICMOUSE)	+= hid-magicmouse.o
 obj-$(CONFIG_HID_MALTRON)	+= hid-maltron.o
+obj-$(CONFIG_HID_MCP2221)	+= hid-mcp2221.o
 obj-$(CONFIG_HID_MAYFLASH)	+= hid-mf.o
 obj-$(CONFIG_HID_MICROSOFT)	+= hid-microsoft.o
 obj-$(CONFIG_HID_MONTEREY)	+= hid-monterey.o
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 3a400ce603c4..53236ac34fcb 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -819,6 +819,7 @@
 #define USB_DEVICE_ID_PICK16F1454	0x0042
 #define USB_DEVICE_ID_PICK16F1454_V2	0xf2f7
 #define USB_DEVICE_ID_LUXAFOR		0xf372
+#define USB_DEVICE_ID_MCP2221		0x00dd
 
 #define USB_VENDOR_ID_MICROSOFT		0x045e
 #define USB_DEVICE_ID_SIDEWINDER_GV	0x003b
diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c
new file mode 100644
index 000000000000..d958475f8c81
--- /dev/null
+++ b/drivers/hid/hid-mcp2221.c
@@ -0,0 +1,742 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MCP2221A - Microchip USB to I2C Host Protocol Bridge
+ *
+ * Copyright (c) 2020, Rishi Gupta <gupt21@gmail.com>
+ *
+ * Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/20005565B.pdf
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/hid.h>
+#include <linux/hidraw.h>
+#include <linux/i2c.h>
+#include "hid-ids.h"
+
+/* Commands codes in a raw output report */
+enum {
+	MCP2221_I2C_WR_DATA = 0x90,
+	MCP2221_I2C_WR_NO_STOP = 0x94,
+	MCP2221_I2C_RD_DATA = 0x91,
+	MCP2221_I2C_RD_RPT_START = 0x93,
+	MCP2221_I2C_GET_DATA = 0x40,
+	MCP2221_I2C_PARAM_OR_STATUS	= 0x10,
+	MCP2221_I2C_SET_SPEED = 0x20,
+	MCP2221_I2C_CANCEL = 0x10,
+};
+
+/* Response codes in a raw input report */
+enum {
+	MCP2221_SUCCESS = 0x00,
+	MCP2221_I2C_ENG_BUSY = 0x01,
+	MCP2221_I2C_START_TOUT = 0x12,
+	MCP2221_I2C_STOP_TOUT = 0x62,
+	MCP2221_I2C_WRADDRL_TOUT = 0x23,
+	MCP2221_I2C_WRDATA_TOUT = 0x44,
+	MCP2221_I2C_WRADDRL_NACK = 0x25,
+	MCP2221_I2C_MASK_ADDR_NACK = 0x40,
+	MCP2221_I2C_WRADDRL_SEND = 0x21,
+	MCP2221_I2C_ADDR_NACK = 0x25,
+	MCP2221_I2C_READ_COMPL = 0x55,
+};
+
+/*
+ * There is no way to distinguish responses. Therefore next command
+ * is sent only after response to previous has been received. Mutex
+ * lock is used for this purpose mainly.
+ */
+struct mcp2221 {
+	struct hid_device *hdev;
+	struct i2c_adapter adapter;
+	struct mutex lock;
+	struct completion wait_in_report;
+	u8 *rxbuf;
+	u8 txbuf[64];
+	int rxbuf_idx;
+	int status;
+	u8 cur_i2c_clk_div;
+};
+
+/*
+ * Default i2c bus clock frequency 400 kHz. Modify this if you
+ * want to set some other frequency (min 50 kHz - max 400 kHz).
+ */
+static uint i2c_clk_freq = 400;
+
+/* Synchronously send output report to the device */
+static int mcp_send_report(struct mcp2221 *mcp,
+					u8 *out_report, size_t len)
+{
+	u8 *buf;
+	int ret;
+
+	buf = kmemdup(out_report, len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	/* mcp2221 uses interrupt endpoint for out reports */
+	ret = hid_hw_output_report(mcp->hdev, buf, len);
+	kfree(buf);
+
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+
+/*
+ * Send o/p report to the device and wait for i/p report to be
+ * received from the device. If the device does not respond,
+ * we timeout.
+ */
+static int mcp_send_data_req_status(struct mcp2221 *mcp,
+			u8 *out_report, int len)
+{
+	int ret;
+	unsigned long t;
+
+	reinit_completion(&mcp->wait_in_report);
+
+	ret = mcp_send_report(mcp, out_report, len);
+	if (ret)
+		return ret;
+
+	t = wait_for_completion_timeout(&mcp->wait_in_report,
+							msecs_to_jiffies(4000));
+	if (!t)
+		return -ETIMEDOUT;
+
+	return mcp->status;
+}
+
+/* Check pass/fail for actual communication with i2c slave */
+static int mcp_chk_last_cmd_status(struct mcp2221 *mcp)
+{
+	memset(mcp->txbuf, 0, 8);
+	mcp->txbuf[0] = MCP2221_I2C_PARAM_OR_STATUS;
+
+	return mcp_send_data_req_status(mcp, mcp->txbuf, 8);
+}
+
+/* Cancels last command releasing i2c bus just in case occupied */
+static int mcp_cancel_last_cmd(struct mcp2221 *mcp)
+{
+	memset(mcp->txbuf, 0, 8);
+	mcp->txbuf[0] = MCP2221_I2C_PARAM_OR_STATUS;
+	mcp->txbuf[2] = MCP2221_I2C_CANCEL;
+
+	return mcp_send_data_req_status(mcp, mcp->txbuf, 8);
+}
+
+static int mcp_set_i2c_speed(struct mcp2221 *mcp)
+{
+	int ret;
+
+	memset(mcp->txbuf, 0, 8);
+	mcp->txbuf[0] = MCP2221_I2C_PARAM_OR_STATUS;
+	mcp->txbuf[3] = MCP2221_I2C_SET_SPEED;
+	mcp->txbuf[4] = mcp->cur_i2c_clk_div;
+
+	ret = mcp_send_data_req_status(mcp, mcp->txbuf, 8);
+	if (ret) {
+		/* Small delay is needed here */
+		usleep_range(980, 1000);
+		mcp_cancel_last_cmd(mcp);
+	}
+
+	return 0;
+}
+
+/*
+ * An output report can contain minimum 1 and maximum 60 user data
+ * bytes. If the number of data bytes is more then 60, we send it
+ * in chunks of 60 bytes. Last chunk may contain exactly 60 or less
+ * bytes. Total number of bytes is informed in very first report to
+ * mcp2221, from that point onwards it first collect all the data
+ * from host and then send to i2c slave device.
+ */
+static int mcp_i2c_write(struct mcp2221 *mcp,
+				struct i2c_msg *msg, int type, u8 last_status)
+{
+	int ret, len, idx, sent;
+
+	idx = 0;
+	sent  = 0;
+	if (msg->len < 60)
+		len = msg->len;
+	else
+		len = 60;
+
+	do {
+		mcp->txbuf[0] = type;
+		mcp->txbuf[1] = msg->len & 0xff;
+		mcp->txbuf[2] = msg->len >> 8;
+		mcp->txbuf[3] = (u8)(msg->addr << 1);
+
+		memcpy(&mcp->txbuf[4], &msg->buf[idx], len);
+
+		ret = mcp_send_data_req_status(mcp, mcp->txbuf, len + 4);
+		if (ret)
+			return ret;
+
+		usleep_range(980, 1000);
+
+		if (last_status) {
+			ret = mcp_chk_last_cmd_status(mcp);
+			if (ret)
+				return ret;
+		}
+
+		sent = sent + len;
+		if (sent >= msg->len)
+			break;
+
+		idx = idx + len;
+		if ((msg->len - sent) < 60)
+			len = msg->len - sent;
+		else
+			len = 60;
+
+		/*
+		 * Testing shows delay is needed between successive writes
+		 * otherwise next write fails on first-try from i2c core.
+		 * This value is obtained through automated stress testing.
+		 */
+		usleep_range(980, 1000);
+	} while (len > 0);
+
+	return ret;
+}
+
+/*
+ * Device reads all data (0 - 65535 bytes) from i2c slave device and
+ * stores it in device itself. This data is read back from device to
+ * host in multiples of 60 bytes using input reports.
+ */
+static int mcp_i2c_smbus_read(struct mcp2221 *mcp,
+				struct i2c_msg *msg, int type, u16 smbus_addr,
+				u8 smbus_len, u8 *smbus_buf)
+{
+	int ret;
+	u16 total_len;
+
+	mcp->txbuf[0] = type;
+	if (msg) {
+		mcp->txbuf[1] = msg->len & 0xff;
+		mcp->txbuf[2] = msg->len >> 8;
+		mcp->txbuf[3] = (u8)(msg->addr << 1);
+		total_len = msg->len;
+		mcp->rxbuf = msg->buf;
+	} else {
+		mcp->txbuf[1] = smbus_len;
+		mcp->txbuf[2] = 0;
+		mcp->txbuf[3] = (u8)(smbus_addr << 1);
+		total_len = smbus_len;
+		mcp->rxbuf = smbus_buf;
+	}
+
+	ret = mcp_send_data_req_status(mcp, mcp->txbuf, 4);
+	if (ret)
+		return ret;
+
+	mcp->rxbuf_idx = 0;
+
+	do {
+		memset(mcp->txbuf, 0, 4);
+		mcp->txbuf[0] = MCP2221_I2C_GET_DATA;
+
+		ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1);
+		if (ret)
+			return ret;
+
+		ret = mcp_chk_last_cmd_status(mcp);
+		if (ret)
+			return ret;
+
+		usleep_range(980, 1000);
+	} while (mcp->rxbuf_idx < total_len);
+
+	return ret;
+}
+
+static int mcp_i2c_xfer(struct i2c_adapter *adapter,
+				struct i2c_msg msgs[], int num)
+{
+	int ret;
+	struct mcp2221 *mcp = i2c_get_adapdata(adapter);
+
+	hid_hw_power(mcp->hdev, PM_HINT_FULLON);
+
+	mutex_lock(&mcp->lock);
+
+	/* Setting speed before every transaction is required for mcp2221 */
+	ret = mcp_set_i2c_speed(mcp);
+	if (ret)
+		goto exit;
+
+	if (num == 1) {
+		if (msgs->flags & I2C_M_RD) {
+			ret = mcp_i2c_smbus_read(mcp, msgs, MCP2221_I2C_RD_DATA,
+							0, 0, NULL);
+		} else {
+			ret = mcp_i2c_write(mcp, msgs, MCP2221_I2C_WR_DATA, 1);
+		}
+		if (ret)
+			goto exit;
+		ret = num;
+	} else if (num == 2) {
+		/* Ex transaction; send reg address and read its contents */
+		if (msgs[0].addr == msgs[1].addr &&
+			!(msgs[0].flags & I2C_M_RD) &&
+			 (msgs[1].flags & I2C_M_RD)) {
+
+			ret = mcp_i2c_write(mcp, &msgs[0],
+						MCP2221_I2C_WR_NO_STOP, 0);
+			if (ret)
+				goto exit;
+
+			ret = mcp_i2c_smbus_read(mcp, &msgs[1],
+						MCP2221_I2C_RD_RPT_START,
+						0, 0, NULL);
+			if (ret)
+				goto exit;
+			ret = num;
+		} else {
+			dev_err(&adapter->dev,
+				"unsupported multi-msg i2c transaction\n");
+			ret = -EOPNOTSUPP;
+		}
+	} else {
+		dev_err(&adapter->dev,
+			"unsupported multi-msg i2c transaction\n");
+		ret = -EOPNOTSUPP;
+	}
+
+exit:
+	hid_hw_power(mcp->hdev, PM_HINT_NORMAL);
+	mutex_unlock(&mcp->lock);
+	return ret;
+}
+
+static int mcp_smbus_write(struct mcp2221 *mcp, u16 addr,
+				u8 command, u8 *buf, u8 len, int type,
+				u8 last_status)
+{
+	int data_len, ret;
+
+	mcp->txbuf[0] = type;
+	mcp->txbuf[1] = len + 1; /* 1 is due to command byte itself */
+	mcp->txbuf[2] = 0;
+	mcp->txbuf[3] = (u8)(addr << 1);
+	mcp->txbuf[4] = command;
+
+	switch (len) {
+	case 0:
+		data_len = 5;
+		break;
+	case 1:
+		mcp->txbuf[5] = buf[0];
+		data_len = 6;
+		break;
+	case 2:
+		mcp->txbuf[5] = buf[0];
+		mcp->txbuf[6] = buf[1];
+		data_len = 7;
+		break;
+	default:
+		memcpy(&mcp->txbuf[5], buf, len);
+		data_len = len + 5;
+	}
+
+	ret = mcp_send_data_req_status(mcp, mcp->txbuf, data_len);
+	if (ret)
+		return ret;
+
+	if (last_status) {
+		usleep_range(980, 1000);
+
+		ret = mcp_chk_last_cmd_status(mcp);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+static int mcp_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
+				unsigned short flags, char read_write,
+				u8 command, int size,
+				union i2c_smbus_data *data)
+{
+	int ret;
+	struct mcp2221 *mcp = i2c_get_adapdata(adapter);
+
+	hid_hw_power(mcp->hdev, PM_HINT_FULLON);
+
+	mutex_lock(&mcp->lock);
+
+	ret = mcp_set_i2c_speed(mcp);
+	if (ret)
+		goto exit;
+
+	switch (size) {
+
+	case I2C_SMBUS_QUICK:
+		if (read_write == I2C_SMBUS_READ)
+			ret = mcp_i2c_smbus_read(mcp, NULL, MCP2221_I2C_RD_DATA,
+						addr, 0, &data->byte);
+		else
+			ret = mcp_smbus_write(mcp, addr, command, NULL,
+						0, MCP2221_I2C_WR_DATA, 1);
+		break;
+	case I2C_SMBUS_BYTE:
+		if (read_write == I2C_SMBUS_READ)
+			ret = mcp_i2c_smbus_read(mcp, NULL, MCP2221_I2C_RD_DATA,
+						addr, 1, &data->byte);
+		else
+			ret = mcp_smbus_write(mcp, addr, command, NULL,
+						0, MCP2221_I2C_WR_DATA, 1);
+		break;
+	case I2C_SMBUS_BYTE_DATA:
+		if (read_write == I2C_SMBUS_READ) {
+			ret = mcp_smbus_write(mcp, addr, command, NULL,
+						0, MCP2221_I2C_WR_NO_STOP, 0);
+			if (ret)
+				goto exit;
+
+			ret = mcp_i2c_smbus_read(mcp, NULL,
+						MCP2221_I2C_RD_RPT_START,
+						addr, 1, &data->byte);
+		} else {
+			ret = mcp_smbus_write(mcp, addr, command, &data->byte,
+						1, MCP2221_I2C_WR_DATA, 1);
+		}
+		break;
+	case I2C_SMBUS_WORD_DATA:
+		if (read_write == I2C_SMBUS_READ) {
+			ret = mcp_smbus_write(mcp, addr, command, NULL,
+						0, MCP2221_I2C_WR_NO_STOP, 0);
+			if (ret)
+				goto exit;
+
+			ret = mcp_i2c_smbus_read(mcp, NULL,
+						MCP2221_I2C_RD_RPT_START,
+						addr, 2, (u8 *)&data->word);
+		} else {
+			ret = mcp_smbus_write(mcp, addr, command,
+						(u8 *)&data->word, 2,
+						MCP2221_I2C_WR_DATA, 1);
+		}
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+		if (read_write == I2C_SMBUS_READ) {
+			ret = mcp_smbus_write(mcp, addr, command, NULL,
+						0, MCP2221_I2C_WR_NO_STOP, 1);
+			if (ret)
+				goto exit;
+
+			mcp->rxbuf_idx = 0;
+			mcp->rxbuf = data->block;
+			mcp->txbuf[0] = MCP2221_I2C_GET_DATA;
+			ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1);
+			if (ret)
+				goto exit;
+		} else {
+			if (!data->block[0]) {
+				ret = -EINVAL;
+				goto exit;
+			}
+			ret = mcp_smbus_write(mcp, addr, command, data->block,
+						data->block[0] + 1,
+						MCP2221_I2C_WR_DATA, 1);
+		}
+		break;
+	case I2C_SMBUS_I2C_BLOCK_DATA:
+		if (read_write == I2C_SMBUS_READ) {
+			ret = mcp_smbus_write(mcp, addr, command, NULL,
+						0, MCP2221_I2C_WR_NO_STOP, 1);
+			if (ret)
+				goto exit;
+
+			mcp->rxbuf_idx = 0;
+			mcp->rxbuf = data->block;
+			mcp->txbuf[0] = MCP2221_I2C_GET_DATA;
+			ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1);
+			if (ret)
+				goto exit;
+		} else {
+			if (!data->block[0]) {
+				ret = -EINVAL;
+				goto exit;
+			}
+			ret = mcp_smbus_write(mcp, addr, command,
+						&data->block[1], data->block[0],
+						MCP2221_I2C_WR_DATA, 1);
+		}
+		break;
+	case I2C_SMBUS_PROC_CALL:
+		ret = mcp_smbus_write(mcp, addr, command,
+						(u8 *)&data->word,
+						2, MCP2221_I2C_WR_NO_STOP, 0);
+		if (ret)
+			goto exit;
+
+		ret = mcp_i2c_smbus_read(mcp, NULL,
+						MCP2221_I2C_RD_RPT_START,
+						addr, 2, (u8 *)&data->word);
+		break;
+	case I2C_SMBUS_BLOCK_PROC_CALL:
+		ret = mcp_smbus_write(mcp, addr, command, data->block,
+						data->block[0] + 1,
+						MCP2221_I2C_WR_NO_STOP, 0);
+		if (ret)
+			goto exit;
+
+		ret = mcp_i2c_smbus_read(mcp, NULL,
+						MCP2221_I2C_RD_RPT_START,
+						addr, I2C_SMBUS_BLOCK_MAX,
+						data->block);
+		break;
+	default:
+		dev_err(&mcp->adapter.dev,
+			"unsupported smbus transaction size:%d\n", size);
+		ret = -EOPNOTSUPP;
+	}
+
+exit:
+	hid_hw_power(mcp->hdev, PM_HINT_NORMAL);
+	mutex_unlock(&mcp->lock);
+	return ret;
+}
+
+static u32 mcp_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C |
+			I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+			I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
+			(I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_PEC);
+}
+
+static const struct i2c_algorithm mcp_i2c_algo = {
+	.master_xfer = mcp_i2c_xfer,
+	.smbus_xfer = mcp_smbus_xfer,
+	.functionality = mcp_i2c_func,
+};
+
+/* Gives current state of i2c engine inside mcp2221 */
+static int mcp_get_i2c_eng_state(struct mcp2221 *mcp,
+				u8 *data, u8 idx)
+{
+	int ret;
+
+	switch (data[idx]) {
+	case MCP2221_I2C_WRADDRL_NACK:
+	case MCP2221_I2C_WRADDRL_SEND:
+		ret = -ENXIO;
+		break;
+	case MCP2221_I2C_START_TOUT:
+	case MCP2221_I2C_STOP_TOUT:
+	case MCP2221_I2C_WRADDRL_TOUT:
+	case MCP2221_I2C_WRDATA_TOUT:
+		ret = -ETIMEDOUT;
+		break;
+	case MCP2221_I2C_ENG_BUSY:
+		ret = -EAGAIN;
+		break;
+	case MCP2221_SUCCESS:
+		ret = 0x00;
+		break;
+	default:
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+/*
+ * MCP2221 uses interrupt endpoint for input reports. This function
+ * is called by HID layer when it receives i/p report from mcp2221,
+ * which is actually a response to the previously sent command.
+ *
+ * MCP2221A firmware specific return codes are parsed and 0 or
+ * appropriate negative error code is returned. Delayed response
+ * results in timeout error and stray reponses results in -EIO.
+ */
+static int mcp2221_raw_event(struct hid_device *hdev,
+				struct hid_report *report, u8 *data, int size)
+{
+	u8 *buf;
+	struct mcp2221 *mcp = hid_get_drvdata(hdev);
+
+	switch (data[0]) {
+
+	case MCP2221_I2C_WR_DATA:
+	case MCP2221_I2C_WR_NO_STOP:
+	case MCP2221_I2C_RD_DATA:
+	case MCP2221_I2C_RD_RPT_START:
+		switch (data[1]) {
+		case MCP2221_SUCCESS:
+			mcp->status = 0;
+			break;
+		default:
+			mcp->status = mcp_get_i2c_eng_state(mcp, data, 2);
+		}
+		complete(&mcp->wait_in_report);
+		break;
+
+	case MCP2221_I2C_PARAM_OR_STATUS:
+		switch (data[1]) {
+		case MCP2221_SUCCESS:
+			if ((mcp->txbuf[3] == MCP2221_I2C_SET_SPEED) &&
+				(data[3] != MCP2221_I2C_SET_SPEED)) {
+				mcp->status = -EAGAIN;
+				break;
+			}
+			if (data[20] & MCP2221_I2C_MASK_ADDR_NACK) {
+				mcp->status = -ENXIO;
+				break;
+			}
+			mcp->status = mcp_get_i2c_eng_state(mcp, data, 8);
+			break;
+		default:
+			mcp->status = -EIO;
+		}
+		complete(&mcp->wait_in_report);
+		break;
+
+	case MCP2221_I2C_GET_DATA:
+		switch (data[1]) {
+		case MCP2221_SUCCESS:
+			if (data[2] == MCP2221_I2C_ADDR_NACK) {
+				mcp->status = -ENXIO;
+				break;
+			}
+			if (!mcp_get_i2c_eng_state(mcp, data, 2)
+				&& (data[3] == 0)) {
+				mcp->status = 0;
+				break;
+			}
+			if (data[3] == 127) {
+				mcp->status = -EIO;
+				break;
+			}
+			if (data[2] == MCP2221_I2C_READ_COMPL) {
+				buf = mcp->rxbuf;
+				memcpy(&buf[mcp->rxbuf_idx], &data[4], data[3]);
+				mcp->rxbuf_idx = mcp->rxbuf_idx + data[3];
+				mcp->status = 0;
+				break;
+			}
+			mcp->status = -EIO;
+			break;
+		default:
+			mcp->status = -EIO;
+		}
+		complete(&mcp->wait_in_report);
+		break;
+
+	default:
+		mcp->status = -EIO;
+		complete(&mcp->wait_in_report);
+	}
+
+	return 1;
+}
+
+static int mcp2221_probe(struct hid_device *hdev,
+					const struct hid_device_id *id)
+{
+	int ret;
+	struct mcp2221 *mcp;
+
+	mcp = devm_kzalloc(&hdev->dev, sizeof(*mcp), GFP_KERNEL);
+	if (!mcp)
+		return -ENOMEM;
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		hid_err(hdev, "can't parse reports\n");
+		return ret;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
+	if (ret) {
+		hid_err(hdev, "can't start hardware\n");
+		return ret;
+	}
+
+	ret = hid_hw_open(hdev);
+	if (ret) {
+		hid_err(hdev, "can't open device\n");
+		goto err_hstop;
+	}
+
+	mutex_init(&mcp->lock);
+	init_completion(&mcp->wait_in_report);
+	hid_set_drvdata(hdev, mcp);
+	mcp->hdev = hdev;
+
+	/* Set I2C bus clock diviser */
+	if (i2c_clk_freq > 400)
+		i2c_clk_freq = 400;
+	if (i2c_clk_freq < 50)
+		i2c_clk_freq = 50;
+	mcp->cur_i2c_clk_div = (12000000 / (i2c_clk_freq * 1000)) - 3;
+
+	mcp->adapter.owner = THIS_MODULE;
+	mcp->adapter.class = I2C_CLASS_HWMON;
+	mcp->adapter.algo = &mcp_i2c_algo;
+	mcp->adapter.retries = 1;
+	mcp->adapter.dev.parent = &hdev->dev;
+	snprintf(mcp->adapter.name, sizeof(mcp->adapter.name),
+			"MCP2221 usb-i2c bridge on hidraw%d",
+			((struct hidraw *)hdev->hidraw)->minor);
+
+	ret = i2c_add_adapter(&mcp->adapter);
+	if (ret) {
+		hid_err(hdev, "can't add usb-i2c adapter: %d\n", ret);
+		goto err_i2c;
+	}
+	i2c_set_adapdata(&mcp->adapter, mcp);
+
+	return 0;
+
+err_i2c:
+	hid_hw_close(mcp->hdev);
+err_hstop:
+	hid_hw_stop(mcp->hdev);
+	return ret;
+}
+
+static void mcp2221_remove(struct hid_device *hdev)
+{
+	struct mcp2221 *mcp = hid_get_drvdata(hdev);
+
+	i2c_del_adapter(&mcp->adapter);
+	hid_hw_close(mcp->hdev);
+	hid_hw_stop(mcp->hdev);
+}
+
+static const struct hid_device_id mcp2221_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_MCP2221) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, mcp2221_devices);
+
+static struct hid_driver mcp2221_driver = {
+	.name		= "mcp2221",
+	.id_table	= mcp2221_devices,
+	.probe		= mcp2221_probe,
+	.remove		= mcp2221_remove,
+	.raw_event	= mcp2221_raw_event,
+};
+
+/* Register with HID core */
+module_hid_driver(mcp2221_driver);
+
+MODULE_AUTHOR("Rishi Gupta <gupt21@gmail.com>");
+MODULE_DESCRIPTION("MCP2221 Microchip HID USB to I2C master bridge");
+MODULE_LICENSE("GPL v2");

From 8c9d734cdffc6e41344653ae9884feece33b4f92 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Filipe=20La=C3=ADns?= <lains@archlinux.org>
Date: Wed, 15 Jan 2020 20:18:11 +0000
Subject: [PATCH 04/11] HID: logitech-dj: add support for the static device in
 the Powerplay mat/receiver
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The Logitech G Powerplay has a lightspeed receiver with a static HID++
device with ID 7 attached to it to. It is used to configure the led on
the mat. For this reason I increased the max number of devices.

Signed-off-by: Filipe Laíns <lains@archlinux.org>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
---
 drivers/hid/hid-logitech-dj.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index 37e54a401452..ed9b1c1f460d 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -16,11 +16,11 @@
 #include <asm/unaligned.h>
 #include "hid-ids.h"
 
-#define DJ_MAX_PAIRED_DEVICES			6
+#define DJ_MAX_PAIRED_DEVICES			7
 #define DJ_MAX_NUMBER_NOTIFS			8
 #define DJ_RECEIVER_INDEX			0
 #define DJ_DEVICE_INDEX_MIN			1
-#define DJ_DEVICE_INDEX_MAX			6
+#define DJ_DEVICE_INDEX_MAX			7
 
 #define DJREPORT_SHORT_LENGTH			15
 #define DJREPORT_LONG_LENGTH			32
@@ -980,6 +980,11 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev,
 		break;
 	}
 
+	/* custom receiver device (eg. powerplay) */
+	if (hidpp_report->device_index == 7) {
+		workitem.reports_supported |= HIDPP;
+	}
+
 	if (workitem.type == WORKITEM_TYPE_EMPTY) {
 		hid_warn(hdev,
 			 "unusable device of type %s (0x%02x) connected on slot %d",

From b08e8d8a508a61d626e6fdd75869776dbe1b2e14 Mon Sep 17 00:00:00 2001
From: Lucas Tanure <tanure@linux.com>
Date: Sat, 29 Feb 2020 17:43:33 +0000
Subject: [PATCH 05/11] HID: appleir: Remove unnecessary goto label

Signed-off-by: Lucas Tanure <tanure@linux.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
---
 drivers/hid/hid-appleir.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/hid/hid-appleir.c b/drivers/hid/hid-appleir.c
index bf8d4afe0d6a..aafc285b538f 100644
--- a/drivers/hid/hid-appleir.c
+++ b/drivers/hid/hid-appleir.c
@@ -284,10 +284,8 @@ static int appleir_probe(struct hid_device *hid, const struct hid_device_id *id)
 	struct appleir *appleir;
 
 	appleir = kzalloc(sizeof(struct appleir), GFP_KERNEL);
-	if (!appleir) {
-		ret = -ENOMEM;
-		goto allocfail;
-	}
+	if (!appleir)
+		return -ENOMEM;
 
 	appleir->hid = hid;
 
@@ -314,7 +312,6 @@ static int appleir_probe(struct hid_device *hid, const struct hid_device_id *id)
 	return 0;
 fail:
 	kfree(appleir);
-allocfail:
 	return ret;
 }
 

From 910a7e89cec65efad254c947ce2bf8bf5b370962 Mon Sep 17 00:00:00 2001
From: Lucas Tanure <tanure@linux.com>
Date: Sat, 29 Feb 2020 17:43:34 +0000
Subject: [PATCH 06/11] HID: appleir: Use devm_kzalloc() instead of kzalloc()

Signed-off-by: Lucas Tanure <tanure@linux.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
---
 drivers/hid/hid-appleir.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/hid/hid-appleir.c b/drivers/hid/hid-appleir.c
index aafc285b538f..8deded185725 100644
--- a/drivers/hid/hid-appleir.c
+++ b/drivers/hid/hid-appleir.c
@@ -283,7 +283,7 @@ static int appleir_probe(struct hid_device *hid, const struct hid_device_id *id)
 	int ret;
 	struct appleir *appleir;
 
-	appleir = kzalloc(sizeof(struct appleir), GFP_KERNEL);
+	appleir = devm_kzalloc(&hid->dev, sizeof(struct appleir), GFP_KERNEL);
 	if (!appleir)
 		return -ENOMEM;
 
@@ -311,7 +311,7 @@ static int appleir_probe(struct hid_device *hid, const struct hid_device_id *id)
 
 	return 0;
 fail:
-	kfree(appleir);
+	devm_kfree(&hid->dev, appleir);
 	return ret;
 }
 
@@ -320,7 +320,6 @@ static void appleir_remove(struct hid_device *hid)
 	struct appleir *appleir = hid_get_drvdata(hid);
 	hid_hw_stop(hid);
 	del_timer_sync(&appleir->key_up_timer);
-	kfree(appleir);
 }
 
 static const struct hid_device_id appleir_devices[] = {

From b8a75eaddae9410767c7d95a1c5f3a547aae7b81 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Sun, 15 Mar 2020 18:34:49 +0100
Subject: [PATCH 07/11] HID: lg-g15: Do not fail the probe when we fail to
 disable F# emulation

By default the G1-G12 keys on the Logitech gaming keyboards send
F1 - F12 when in "generic HID" mode.

The first thing the hid-lg-g15 driver does is disable this behavior.

We have received a bugreport that this does not work when the keyboard
is connected through an Aten KVM switch. Using a gaming keyboard with
a KVM is a bit weird setup, but still we can try to fail a bit more
gracefully here.

On the G510 keyboards the same USB-interface which is used for the gaming
keys is also used for the media-keys. Before this commit we would call
hid_hw_stop() on failure to disable the F# emulation and then exit the
probe method with an error code.

This not only causes us to not handle the gaming-keys, but this also
breaks the media keys which is a regression compared to the situation
when these keyboards where handled by the generic hidinput driver.

This commit changes the error handling to clear the hiddev drvdata
(to disable our .raw_event handler) and then returning from the probe
method with success.

The net result of this is that, when connected through a KVM, things
work as well as they did before the hid-lg-g15 driver was introduced.

Fixes: ad4203f5a243 ("HID: lg-g15: Add support for the G510 keyboards' gaming keys")
BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1806321
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
---
 drivers/hid/hid-lg-g15.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/hid/hid-lg-g15.c b/drivers/hid/hid-lg-g15.c
index 8a9268a5c66a..ad4b5412a9f4 100644
--- a/drivers/hid/hid-lg-g15.c
+++ b/drivers/hid/hid-lg-g15.c
@@ -803,8 +803,10 @@ static int lg_g15_probe(struct hid_device *hdev, const struct hid_device_id *id)
 	}
 
 	if (ret < 0) {
-		hid_err(hdev, "Error disabling keyboard emulation for the G-keys\n");
-		goto error_hw_stop;
+		hid_err(hdev, "Error %d disabling keyboard emulation for the G-keys, falling back to generic hid-input driver\n",
+			ret);
+		hid_set_drvdata(hdev, NULL);
+		return 0;
 	}
 
 	/* Get initial brightness levels */

From 77a36a3ab4ff17fad23831192e3694a3c5a1750d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20=C4=8Cavoj?= <sammko@sammserver.com>
Date: Fri, 13 Mar 2020 03:12:38 +0100
Subject: [PATCH 08/11] HID: Add driver fixing Glorious PC Gaming Race mouse
 report descriptor
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The Glorious Model O mice (and also at least the Model O-, which is
driver-wise the same mouse) have a bug in the descriptor of HID
Report with ID 2. This report is used for Consumer Control buttons,
which can be mapped using the provided Windows only software.

Here is an excerpt from the original descriptor:

  INPUT(2)[INPUT]
    Field(0)
      Flags( Constant Variable Absolute )
    Field(1)
      Flags( Constant Variable Absolute )
    Field(2)
      Flags( Constant Variable Absolute )

The issue is the Constant flag specified on all 3 fields, which
causes the hid driver to ignore changes in these fields and
essentialy causes the buttons to not work at all. The submitted driver
patches the descriptor to end up with the following:

  INPUT(2)[INPUT]
    Field(0)
      Flags( Variable Relative )
    Field(1)
      Flags( Variable Relative )
    Field(2)
      Flags( Variable Relative )

The Constant bit is reset and the Relative bit has been set in
order to prevent repeat events when holding down the button.

Additionally, the device name is changed from the hardware-reported
"SINOWEALTH Wired Gaming Mouse" to "Glorious Model O" or "Glorious
Model D".

Signed-off-by: Samuel Čavoj <sammko@sammserver.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
---
 drivers/hid/Kconfig        |  7 ++++
 drivers/hid/Makefile       |  1 +
 drivers/hid/hid-glorious.c | 86 ++++++++++++++++++++++++++++++++++++++
 drivers/hid/hid-ids.h      |  4 ++
 4 files changed, 98 insertions(+)
 create mode 100644 drivers/hid/hid-glorious.c

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 494a39e74939..945533b36010 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -362,6 +362,13 @@ config HID_GFRM
 	---help---
 	Support for Google Fiber TV Box remote controls
 
+config HID_GLORIOUS
+	tristate "Glorious PC Gaming Race mice"
+	depends on HID
+	help
+	  Support for Glorious PC Gaming Race mice such as
+	  the Glorious Model O, O- and D.
+
 config HID_HOLTEK
 	tristate "Holtek HID devices"
 	depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index bfefa365b1ce..be0f38dcf942 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -48,6 +48,7 @@ obj-$(CONFIG_HID_ELO)		+= hid-elo.o
 obj-$(CONFIG_HID_EZKEY)		+= hid-ezkey.o
 obj-$(CONFIG_HID_GEMBIRD)	+= hid-gembird.o
 obj-$(CONFIG_HID_GFRM)		+= hid-gfrm.o
+obj-$(CONFIG_HID_GLORIOUS)  += hid-glorious.o
 obj-$(CONFIG_HID_GOOGLE_HAMMER)	+= hid-google-hammer.o
 obj-$(CONFIG_HID_GT683R)	+= hid-gt683r.o
 obj-$(CONFIG_HID_GYRATION)	+= hid-gyration.o
diff --git a/drivers/hid/hid-glorious.c b/drivers/hid/hid-glorious.c
new file mode 100644
index 000000000000..558eb08c19ef
--- /dev/null
+++ b/drivers/hid/hid-glorious.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  USB HID driver for Glorious PC Gaming Race
+ *  Glorious Model O, O- and D mice.
+ *
+ *  Copyright (c) 2020 Samuel Čavoj <sammko@sammserver.com>
+ */
+
+/*
+ */
+
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+MODULE_AUTHOR("Samuel Čavoj <sammko@sammserver.com>");
+MODULE_DESCRIPTION("HID driver for Glorious PC Gaming Race mice");
+
+/*
+ * Glorious Model O and O- specify the const flag in the consumer input
+ * report descriptor, which leads to inputs being ignored. Fix this
+ * by patching the descriptor.
+ */
+static __u8 *glorious_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+		unsigned int *rsize)
+{
+	if (*rsize == 213 &&
+		rdesc[84] == 129 && rdesc[112] == 129 && rdesc[140] == 129 &&
+		rdesc[85] == 3   && rdesc[113] == 3   && rdesc[141] == 3) {
+		hid_info(hdev, "patching Glorious Model O consumer control report descriptor\n");
+		rdesc[85] = rdesc[113] = rdesc[141] = \
+			HID_MAIN_ITEM_VARIABLE | HID_MAIN_ITEM_RELATIVE;
+	}
+	return rdesc;
+}
+
+static void glorious_update_name(struct hid_device *hdev)
+{
+	const char *model = "Device";
+
+	switch (hdev->product) {
+	case USB_DEVICE_ID_GLORIOUS_MODEL_O:
+		model = "Model O"; break;
+	case USB_DEVICE_ID_GLORIOUS_MODEL_D:
+		model = "Model D"; break;
+	}
+
+	snprintf(hdev->name, sizeof(hdev->name), "%s %s", "Glorious", model);
+}
+
+static int glorious_probe(struct hid_device *hdev,
+		const struct hid_device_id *id)
+{
+	int ret;
+
+	hdev->quirks |= HID_QUIRK_INPUT_PER_APP;
+
+	ret = hid_parse(hdev);
+	if (ret)
+		return ret;
+
+	glorious_update_name(hdev);
+
+	return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+}
+
+static const struct hid_device_id glorious_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GLORIOUS,
+		USB_DEVICE_ID_GLORIOUS_MODEL_O) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_GLORIOUS,
+		USB_DEVICE_ID_GLORIOUS_MODEL_D) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, glorious_devices);
+
+static struct hid_driver glorious_driver = {
+	.name = "glorious",
+	.id_table = glorious_devices,
+	.probe = glorious_probe,
+	.report_fixup = glorious_report_fixup
+};
+
+module_hid_driver(glorious_driver);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 9f2213426556..54474205b12c 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -464,6 +464,10 @@
 #define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_010A 0x010a
 #define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_E100 0xe100
 
+#define USB_VENDOR_ID_GLORIOUS  0x258a
+#define USB_DEVICE_ID_GLORIOUS_MODEL_D 0x0033
+#define USB_DEVICE_ID_GLORIOUS_MODEL_O 0x0036
+
 #define I2C_VENDOR_ID_GOODIX		0x27c6
 #define I2C_DEVICE_ID_GOODIX_01F0	0x01f0
 

From 71559219ce36d5861ecc1d31697687c08819b6e5 Mon Sep 17 00:00:00 2001
From: "Gustavo A. R. Silva" <gustavo@embeddedor.com>
Date: Thu, 19 Mar 2020 16:31:08 -0500
Subject: [PATCH 09/11] HID: intel-ish-hid: ishtp-dev.h: Replace zero-length
 array with flexible-array member

The current codebase makes use of the zero-length array language
extension to the C90 standard, but the preferred mechanism to declare
variable-length types such as these ones is a flexible array member[1][2],
introduced in C99:

struct foo {
        int stuff;
        struct boo array[];
};

By making use of the mechanism above, we will get a compiler warning
in case the flexible array does not occur last in the structure, which
will help us prevent some kind of undefined behavior bugs from being
inadvertently introduced[3] to the codebase from now on.

Also, notice that, dynamic memory allocations won't be affected by
this change:

"Flexible array members have incomplete type, and so the sizeof operator
may not be applied. As a quirk of the original implementation of
zero-length arrays, sizeof evaluates to zero."[1]

This issue was found with the help of Coccinelle.

[1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
[2] https://github.com/KSPP/linux/issues/21
[3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour")

Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
---
 drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h b/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h
index 39e0e6c73adf..1cc6364aa957 100644
--- a/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h
+++ b/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h
@@ -214,7 +214,7 @@ struct ishtp_device {
 	const struct ishtp_hw_ops *ops;
 	size_t	mtu;
 	uint32_t	ishtp_msg_hdr;
-	char hw[0] __aligned(sizeof(void *));
+	char hw[] __aligned(sizeof(void *));
 };
 
 static inline unsigned long ishtp_secs_to_jiffies(unsigned long sec)

From 56d8623cedf929bfb1385868e423b978d0e76eea Mon Sep 17 00:00:00 2001
From: "Gustavo A. R. Silva" <gustavo@embeddedor.com>
Date: Thu, 19 Mar 2020 16:29:50 -0500
Subject: [PATCH 10/11] HID: intel-ish-hid: hbm.h: Replace zero-length array
 with flexible-array member

The current codebase makes use of the zero-length array language
extension to the C90 standard, but the preferred mechanism to declare
variable-length types such as these ones is a flexible array member[1][2],
introduced in C99:

struct foo {
        int stuff;
        struct boo array[];
};

By making use of the mechanism above, we will get a compiler warning
in case the flexible array does not occur last in the structure, which
will help us prevent some kind of undefined behavior bugs from being
inadvertently introduced[3] to the codebase from now on.

Also, notice that, dynamic memory allocations won't be affected by
this change:

"Flexible array members have incomplete type, and so the sizeof operator
may not be applied. As a quirk of the original implementation of
zero-length arrays, sizeof evaluates to zero."[1]

This issue was found with the help of Coccinelle.

[1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
[2] https://github.com/KSPP/linux/issues/21
[3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour")

Signed-off-by: Gustavo A. R. Silva <gustavo@embeddedor.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
---
 drivers/hid/intel-ish-hid/ishtp/hbm.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/hid/intel-ish-hid/ishtp/hbm.h b/drivers/hid/intel-ish-hid/ishtp/hbm.h
index bb85985b1620..7c445b203f2a 100644
--- a/drivers/hid/intel-ish-hid/ishtp/hbm.h
+++ b/drivers/hid/intel-ish-hid/ishtp/hbm.h
@@ -82,7 +82,7 @@ struct ishtp_msg_hdr {
 
 struct ishtp_bus_message {
 	uint8_t hbm_cmd;
-	uint8_t data[0];
+	uint8_t data[];
 } __packed;
 
 /**

From 2e1b9e1edff7fe19d37f0a5993ac03c5389af809 Mon Sep 17 00:00:00 2001
From: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
Date: Sat, 21 Mar 2020 07:40:48 +0100
Subject: [PATCH 11/11] HID: rmi: Simplify an error handling path in
 'rmi_hid_read_block()'

The 'RMI_READ_REQUEST_PENDING' bit is already cleared in the error handling
path. There is no need to reset it twice.

Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
---
 drivers/hid/hid-rmi.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c
index 9ce22acdfaca..8cffa84c9650 100644
--- a/drivers/hid/hid-rmi.c
+++ b/drivers/hid/hid-rmi.c
@@ -217,7 +217,6 @@ static int rmi_hid_read_block(struct rmi_transport_dev *xport, u16 addr,
 		ret = rmi_write_report(hdev, data->writeReport,
 						data->output_report_size);
 		if (ret != data->output_report_size) {
-			clear_bit(RMI_READ_REQUEST_PENDING, &data->flags);
 			dev_err(&hdev->dev,
 				"failed to write request output report (%d)\n",
 				ret);