Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754199AbdDJRkE (ORCPT ); Mon, 10 Apr 2017 13:40:04 -0400 Received: from mail.linuxfoundation.org ([140.211.169.12]:34886 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754080AbdDJQqO (ORCPT ); Mon, 10 Apr 2017 12:46:14 -0400 From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, HungNien Chen , Benjamin Tissoires , Jiri Kosina , Sasha Levin Subject: [PATCH 4.9 062/152] HID: i2c-hid: add a simple quirk to fix device defects Date: Mon, 10 Apr 2017 18:41:54 +0200 Message-Id: <20170410164203.279058287@linuxfoundation.org> X-Mailer: git-send-email 2.12.2 In-Reply-To: <20170410164159.934755016@linuxfoundation.org> References: <20170410164159.934755016@linuxfoundation.org> User-Agent: quilt/0.65 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 4162 Lines: 137 4.9-stable review patch. If anyone has any objections, please let me know. ------------------ From: HungNien Chen [ Upstream commit 71af01a8c85ad89449209594133bdfdfaa9f1e2a ] 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 Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-ids.h | 4 ++ drivers/hid/i2c-hid/i2c-hid.c | 57 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -1039,6 +1039,10 @@ #define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH 0x0500 #define USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET 0x0502 +#define USB_VENDOR_ID_WEIDA 0x2575 +#define USB_DEVICE_ID_WEIDA_8752 0xC300 +#define USB_DEVICE_ID_WEIDA_8755 0xC301 + #define USB_VENDOR_ID_WISEGROUP 0x0925 #define USB_DEVICE_ID_SMARTJOY_PLUS 0x0005 #define USB_DEVICE_ID_SUPER_JOY_BOX_3 0x8888 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -41,6 +41,11 @@ #include +#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 @@ -143,6 +148,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 */ struct gpio_desc *desc; @@ -154,6 +160,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, @@ -346,11 +385,27 @@ static int i2c_hid_set_power(struct i2c_ 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; } @@ -1050,6 +1105,8 @@ static int i2c_hid_probe(struct i2c_clie 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)