diff options
author | Benjamin Tissoires <benjamin.tissoires@gmail.com> | 2012-12-12 18:00:02 +0100 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2012-12-12 18:26:22 +0100 |
commit | 7a7d6d9c5fcd4b674da38e814cfc0724c67731b2 (patch) | |
tree | 8fdc9bdf269b31a706e20ac0ca1d1f135164c4c8 /drivers/hid/i2c-hid/i2c-hid.c | |
parent | 9afd09a1db93cc9084846c2b9bc0d1194743e5dc (diff) | |
download | op-kernel-dev-7a7d6d9c5fcd4b674da38e814cfc0724c67731b2.zip op-kernel-dev-7a7d6d9c5fcd4b674da38e814cfc0724c67731b2.tar.gz |
HID: i2c-hid: add mutex protecting open/close race
We should not enter close function while someone else is in open.
This mutex prevents this race.
There is also no need to override the ret value with -EIO in case of
a failure of i2c_hid_set_power.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
Reviewed-by: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/i2c-hid/i2c-hid.c')
-rw-r--r-- | drivers/hid/i2c-hid/i2c-hid.c | 14 |
1 files changed, 11 insertions, 3 deletions
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 6e1774c..9ef22244 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -33,6 +33,7 @@ #include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/hid.h> +#include <linux/mutex.h> #include <linux/i2c/i2c-hid.h> @@ -117,6 +118,8 @@ static const struct i2c_hid_cmd hid_set_power_cmd = { I2C_HID_CMD(0x08) }; * static const struct i2c_hid_cmd hid_set_protocol_cmd = { I2C_HID_CMD(0x07) }; */ +static DEFINE_MUTEX(i2c_hid_open_mut); + /* The main device structure */ struct i2c_hid { struct i2c_client *client; /* i2c client */ @@ -641,17 +644,20 @@ static int i2c_hid_open(struct hid_device *hid) { struct i2c_client *client = hid->driver_data; struct i2c_hid *ihid = i2c_get_clientdata(client); - int ret; + int ret = 0; + mutex_lock(&i2c_hid_open_mut); if (!hid->open++) { ret = i2c_hid_set_power(client, I2C_HID_PWR_ON); if (ret) { hid->open--; - return -EIO; + goto done; } set_bit(I2C_HID_STARTED, &ihid->flags); } - return 0; +done: + mutex_unlock(&i2c_hid_open_mut); + return ret; } static void i2c_hid_close(struct hid_device *hid) @@ -663,12 +669,14 @@ static void i2c_hid_close(struct hid_device *hid) * data acquistion due to a resumption we no longer * care about */ + mutex_lock(&i2c_hid_open_mut); if (!--hid->open) { clear_bit(I2C_HID_STARTED, &ihid->flags); /* Save some power */ i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); } + mutex_unlock(&i2c_hid_open_mut); } static int i2c_hid_power(struct hid_device *hid, int lvl) |