|
@@ -40,6 +40,11 @@
|
|
|
|
|
|
#include <linux/i2c/i2c-hid.h>
|
|
|
|
|
|
+#include "../hid-ids.h"
|
|
|
+
|
|
|
+/* quirks to control the device */
|
|
|
+#define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0)
|
|
|
+
|
|
|
/* flags */
|
|
|
#define I2C_HID_STARTED 0
|
|
|
#define I2C_HID_RESET_PENDING 1
|
|
@@ -142,6 +147,7 @@ struct i2c_hid {
|
|
|
char *argsbuf; /* Command arguments buffer */
|
|
|
|
|
|
unsigned long flags; /* device flags */
|
|
|
+ unsigned long quirks; /* Various quirks */
|
|
|
|
|
|
wait_queue_head_t wait; /* For waiting the interrupt */
|
|
|
|
|
@@ -151,6 +157,39 @@ struct i2c_hid {
|
|
|
struct mutex reset_lock;
|
|
|
};
|
|
|
|
|
|
+static const struct i2c_hid_quirks {
|
|
|
+ __u16 idVendor;
|
|
|
+ __u16 idProduct;
|
|
|
+ __u32 quirks;
|
|
|
+} i2c_hid_quirks[] = {
|
|
|
+ { USB_VENDOR_ID_WEIDA, USB_DEVICE_ID_WEIDA_8752,
|
|
|
+ I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV },
|
|
|
+ { USB_VENDOR_ID_WEIDA, USB_DEVICE_ID_WEIDA_8755,
|
|
|
+ I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV },
|
|
|
+ { 0, 0 }
|
|
|
+};
|
|
|
+
|
|
|
+/*
|
|
|
+ * i2c_hid_lookup_quirk: return any quirks associated with a I2C HID device
|
|
|
+ * @idVendor: the 16-bit vendor ID
|
|
|
+ * @idProduct: the 16-bit product ID
|
|
|
+ *
|
|
|
+ * Returns: a u32 quirks value.
|
|
|
+ */
|
|
|
+static u32 i2c_hid_lookup_quirk(const u16 idVendor, const u16 idProduct)
|
|
|
+{
|
|
|
+ u32 quirks = 0;
|
|
|
+ int n;
|
|
|
+
|
|
|
+ for (n = 0; i2c_hid_quirks[n].idVendor; n++)
|
|
|
+ if (i2c_hid_quirks[n].idVendor == idVendor &&
|
|
|
+ (i2c_hid_quirks[n].idProduct == (__u16)HID_ANY_ID ||
|
|
|
+ i2c_hid_quirks[n].idProduct == idProduct))
|
|
|
+ quirks = i2c_hid_quirks[n].quirks;
|
|
|
+
|
|
|
+ return quirks;
|
|
|
+}
|
|
|
+
|
|
|
static int __i2c_hid_command(struct i2c_client *client,
|
|
|
const struct i2c_hid_cmd *command, u8 reportID,
|
|
|
u8 reportType, u8 *args, int args_len,
|
|
@@ -343,11 +382,27 @@ static int i2c_hid_set_power(struct i2c_client *client, int power_state)
|
|
|
|
|
|
i2c_hid_dbg(ihid, "%s\n", __func__);
|
|
|
|
|
|
+ /*
|
|
|
+ * Some devices require to send a command to wakeup before power on.
|
|
|
+ * The call will get a return value (EREMOTEIO) but device will be
|
|
|
+ * triggered and activated. After that, it goes like a normal device.
|
|
|
+ */
|
|
|
+ if (power_state == I2C_HID_PWR_ON &&
|
|
|
+ ihid->quirks & I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV) {
|
|
|
+ ret = i2c_hid_command(client, &hid_set_power_cmd, NULL, 0);
|
|
|
+
|
|
|
+ /* Device was already activated */
|
|
|
+ if (!ret)
|
|
|
+ goto set_pwr_exit;
|
|
|
+ }
|
|
|
+
|
|
|
ret = __i2c_hid_command(client, &hid_set_power_cmd, power_state,
|
|
|
0, NULL, 0, NULL, 0);
|
|
|
+
|
|
|
if (ret)
|
|
|
dev_err(&client->dev, "failed to change power setting.\n");
|
|
|
|
|
|
+set_pwr_exit:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -1032,6 +1087,8 @@ static int i2c_hid_probe(struct i2c_client *client,
|
|
|
client->name, hid->vendor, hid->product);
|
|
|
strlcpy(hid->phys, dev_name(&client->dev), sizeof(hid->phys));
|
|
|
|
|
|
+ ihid->quirks = i2c_hid_lookup_quirk(hid->vendor, hid->product);
|
|
|
+
|
|
|
ret = hid_add_device(hid);
|
|
|
if (ret) {
|
|
|
if (ret != -ENODEV)
|