|
@@ -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
|