diff options
Diffstat (limited to 'drivers/hid/i2c-hid')
-rw-r--r-- | drivers/hid/i2c-hid/i2c-hid.c | 21 |
1 files changed, 18 insertions, 3 deletions
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 10bd8e6e4c9c..fc5ef1c25ed4 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -151,6 +151,7 @@ struct i2c_hid { struct i2c_hid_platform_data pdata; bool irq_wake_enabled; + struct mutex reset_lock; }; static int __i2c_hid_command(struct i2c_client *client, @@ -356,9 +357,16 @@ static int i2c_hid_hwreset(struct i2c_client *client) i2c_hid_dbg(ihid, "%s\n", __func__); + /* + * This prevents sending feature reports while the device is + * being reset. Otherwise we may lose the reset complete + * interrupt. + */ + mutex_lock(&ihid->reset_lock); + ret = i2c_hid_set_power(client, I2C_HID_PWR_ON); if (ret) - return ret; + goto out_unlock; i2c_hid_dbg(ihid, "resetting...\n"); @@ -366,10 +374,11 @@ static int i2c_hid_hwreset(struct i2c_client *client) if (ret) { dev_err(&client->dev, "failed to reset device.\n"); i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); - return ret; } - return 0; +out_unlock: + mutex_unlock(&ihid->reset_lock); + return ret; } static void i2c_hid_get_input(struct i2c_hid *ihid) @@ -587,12 +596,15 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count, unsigned char report_type, bool use_data) { struct i2c_client *client = hid->driver_data; + struct i2c_hid *ihid = i2c_get_clientdata(client); int report_id = buf[0]; int ret; if (report_type == HID_INPUT_REPORT) return -EINVAL; + mutex_lock(&ihid->reset_lock); + if (report_id) { buf++; count--; @@ -605,6 +617,8 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, if (report_id && ret >= 0) ret++; /* add report_id to the number of transfered bytes */ + mutex_unlock(&ihid->reset_lock); + return ret; } @@ -990,6 +1004,7 @@ static int i2c_hid_probe(struct i2c_client *client, ihid->wHIDDescRegister = cpu_to_le16(hidRegister); init_waitqueue_head(&ihid->wait); + mutex_init(&ihid->reset_lock); /* we need to allocate the command buffer without knowing the maximum * size of the reports. Let's use HID_MIN_BUFFER_SIZE, then we do the |