diff options
author | HungNien Chen <hn.chen@weidahitech.com> | 2016-11-09 22:47:13 -0500 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2016-11-10 04:23:31 -0500 |
commit | 71af01a8c85ad89449209594133bdfdfaa9f1e2a (patch) | |
tree | 59ed8a66644bc22e2c94ef470ffe05ff50598218 | |
parent | 93d26aeab54cc91119760bc4f1f22bff9a987d70 (diff) |
HID: i2c-hid: add a simple quirk to fix device defects
Certain devices produced by Weida Tech need to have a wakeup command sent to
them before powering on. The call itself will come back with error, but the
device can be powered on afterwards.
[jkosina@suse.cz: rewrite changelog]
[jkosina@suse.cz: remove unused device ID addition]
Signed-off-by: HungNien Chen <hn.chen@weidahitech.com>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r-- | drivers/hid/hid-ids.h | 4 | ||||
-rw-r--r-- | drivers/hid/i2c-hid/i2c-hid.c | 57 |
2 files changed, 61 insertions, 0 deletions
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index cd59c79eebdd..c36ec6d01b8b 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h | |||
@@ -1030,6 +1030,10 @@ | |||
1030 | #define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH 0x0500 | 1030 | #define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH 0x0500 |
1031 | #define USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET 0x0502 | 1031 | #define USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET 0x0502 |
1032 | 1032 | ||
1033 | #define USB_VENDOR_ID_WEIDA 0x2575 | ||
1034 | #define USB_DEVICE_ID_WEIDA_8752 0xC300 | ||
1035 | #define USB_DEVICE_ID_WEIDA_8755 0xC301 | ||
1036 | |||
1033 | #define USB_VENDOR_ID_WISEGROUP 0x0925 | 1037 | #define USB_VENDOR_ID_WISEGROUP 0x0925 |
1034 | #define USB_DEVICE_ID_SMARTJOY_PLUS 0x0005 | 1038 | #define USB_DEVICE_ID_SMARTJOY_PLUS 0x0005 |
1035 | #define USB_DEVICE_ID_SUPER_JOY_BOX_3 0x8888 | 1039 | #define USB_DEVICE_ID_SUPER_JOY_BOX_3 0x8888 |
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index fe6b4e0eab4a..ce518795cb30 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c | |||
@@ -40,6 +40,11 @@ | |||
40 | 40 | ||
41 | #include <linux/i2c/i2c-hid.h> | 41 | #include <linux/i2c/i2c-hid.h> |
42 | 42 | ||
43 | #include "../hid-ids.h" | ||
44 | |||
45 | /* quirks to control the device */ | ||
46 | #define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0) | ||
47 | |||
43 | /* flags */ | 48 | /* flags */ |
44 | #define I2C_HID_STARTED 0 | 49 | #define I2C_HID_STARTED 0 |
45 | #define I2C_HID_RESET_PENDING 1 | 50 | #define I2C_HID_RESET_PENDING 1 |
@@ -142,6 +147,7 @@ struct i2c_hid { | |||
142 | char *argsbuf; /* Command arguments buffer */ | 147 | char *argsbuf; /* Command arguments buffer */ |
143 | 148 | ||
144 | unsigned long flags; /* device flags */ | 149 | unsigned long flags; /* device flags */ |
150 | unsigned long quirks; /* Various quirks */ | ||
145 | 151 | ||
146 | wait_queue_head_t wait; /* For waiting the interrupt */ | 152 | wait_queue_head_t wait; /* For waiting the interrupt */ |
147 | 153 | ||
@@ -151,6 +157,39 @@ struct i2c_hid { | |||
151 | struct mutex reset_lock; | 157 | struct mutex reset_lock; |
152 | }; | 158 | }; |
153 | 159 | ||
160 | static const struct i2c_hid_quirks { | ||
161 | __u16 idVendor; | ||
162 | __u16 idProduct; | ||
163 | __u32 quirks; | ||
164 | } i2c_hid_quirks[] = { | ||
165 | { USB_VENDOR_ID_WEIDA, USB_DEVICE_ID_WEIDA_8752, | ||
166 | I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV }, | ||
167 | { USB_VENDOR_ID_WEIDA, USB_DEVICE_ID_WEIDA_8755, | ||
168 | I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV }, | ||
169 | { 0, 0 } | ||
170 | }; | ||
171 | |||
172 | /* | ||
173 | * i2c_hid_lookup_quirk: return any quirks associated with a I2C HID device | ||
174 | * @idVendor: the 16-bit vendor ID | ||
175 | * @idProduct: the 16-bit product ID | ||
176 | * | ||
177 | * Returns: a u32 quirks value. | ||
178 | */ | ||
179 | static u32 i2c_hid_lookup_quirk(const u16 idVendor, const u16 idProduct) | ||
180 | { | ||
181 | u32 quirks = 0; | ||
182 | int n; | ||
183 | |||
184 | for (n = 0; i2c_hid_quirks[n].idVendor; n++) | ||
185 | if (i2c_hid_quirks[n].idVendor == idVendor && | ||
186 | (i2c_hid_quirks[n].idProduct == (__u16)HID_ANY_ID || | ||
187 | i2c_hid_quirks[n].idProduct == idProduct)) | ||
188 | quirks = i2c_hid_quirks[n].quirks; | ||
189 | |||
190 | return quirks; | ||
191 | } | ||
192 | |||
154 | static int __i2c_hid_command(struct i2c_client *client, | 193 | static int __i2c_hid_command(struct i2c_client *client, |
155 | const struct i2c_hid_cmd *command, u8 reportID, | 194 | const struct i2c_hid_cmd *command, u8 reportID, |
156 | u8 reportType, u8 *args, int args_len, | 195 | u8 reportType, u8 *args, int args_len, |
@@ -343,11 +382,27 @@ static int i2c_hid_set_power(struct i2c_client *client, int power_state) | |||
343 | 382 | ||
344 | i2c_hid_dbg(ihid, "%s\n", __func__); | 383 | i2c_hid_dbg(ihid, "%s\n", __func__); |
345 | 384 | ||
385 | /* | ||
386 | * Some devices require to send a command to wakeup before power on. | ||
387 | * The call will get a return value (EREMOTEIO) but device will be | ||
388 | * triggered and activated. After that, it goes like a normal device. | ||
389 | */ | ||
390 | if (power_state == I2C_HID_PWR_ON && | ||
391 | ihid->quirks & I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV) { | ||
392 | ret = i2c_hid_command(client, &hid_set_power_cmd, NULL, 0); | ||
393 | |||
394 | /* Device was already activated */ | ||
395 | if (!ret) | ||
396 | goto set_pwr_exit; | ||
397 | } | ||
398 | |||
346 | ret = __i2c_hid_command(client, &hid_set_power_cmd, power_state, | 399 | ret = __i2c_hid_command(client, &hid_set_power_cmd, power_state, |
347 | 0, NULL, 0, NULL, 0); | 400 | 0, NULL, 0, NULL, 0); |
401 | |||
348 | if (ret) | 402 | if (ret) |
349 | dev_err(&client->dev, "failed to change power setting.\n"); | 403 | dev_err(&client->dev, "failed to change power setting.\n"); |
350 | 404 | ||
405 | set_pwr_exit: | ||
351 | return ret; | 406 | return ret; |
352 | } | 407 | } |
353 | 408 | ||
@@ -1032,6 +1087,8 @@ static int i2c_hid_probe(struct i2c_client *client, | |||
1032 | client->name, hid->vendor, hid->product); | 1087 | client->name, hid->vendor, hid->product); |
1033 | strlcpy(hid->phys, dev_name(&client->dev), sizeof(hid->phys)); | 1088 | strlcpy(hid->phys, dev_name(&client->dev), sizeof(hid->phys)); |
1034 | 1089 | ||
1090 | ihid->quirks = i2c_hid_lookup_quirk(hid->vendor, hid->product); | ||
1091 | |||
1035 | ret = hid_add_device(hid); | 1092 | ret = hid_add_device(hid); |
1036 | if (ret) { | 1093 | if (ret) { |
1037 | if (ret != -ENODEV) | 1094 | if (ret != -ENODEV) |