diff options
author | Benjamin Tissoires <benjamin.tissoires@gmail.com> | 2012-12-12 12:00:02 -0500 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2012-12-12 12:26:22 -0500 |
commit | 7a7d6d9c5fcd4b674da38e814cfc0724c67731b2 (patch) | |
tree | 8fdc9bdf269b31a706e20ac0ca1d1f135164c4c8 /drivers/hid/i2c-hid | |
parent | 9afd09a1db93cc9084846c2b9bc0d1194743e5dc (diff) |
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')
-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 6e1774c3a3f9..9ef222442ca0 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/jiffies.h> | 33 | #include <linux/jiffies.h> |
34 | #include <linux/kernel.h> | 34 | #include <linux/kernel.h> |
35 | #include <linux/hid.h> | 35 | #include <linux/hid.h> |
36 | #include <linux/mutex.h> | ||
36 | 37 | ||
37 | #include <linux/i2c/i2c-hid.h> | 38 | #include <linux/i2c/i2c-hid.h> |
38 | 39 | ||
@@ -117,6 +118,8 @@ static const struct i2c_hid_cmd hid_set_power_cmd = { I2C_HID_CMD(0x08) }; | |||
117 | * static const struct i2c_hid_cmd hid_set_protocol_cmd = { I2C_HID_CMD(0x07) }; | 118 | * static const struct i2c_hid_cmd hid_set_protocol_cmd = { I2C_HID_CMD(0x07) }; |
118 | */ | 119 | */ |
119 | 120 | ||
121 | static DEFINE_MUTEX(i2c_hid_open_mut); | ||
122 | |||
120 | /* The main device structure */ | 123 | /* The main device structure */ |
121 | struct i2c_hid { | 124 | struct i2c_hid { |
122 | struct i2c_client *client; /* i2c client */ | 125 | struct i2c_client *client; /* i2c client */ |
@@ -641,17 +644,20 @@ static int i2c_hid_open(struct hid_device *hid) | |||
641 | { | 644 | { |
642 | struct i2c_client *client = hid->driver_data; | 645 | struct i2c_client *client = hid->driver_data; |
643 | struct i2c_hid *ihid = i2c_get_clientdata(client); | 646 | struct i2c_hid *ihid = i2c_get_clientdata(client); |
644 | int ret; | 647 | int ret = 0; |
645 | 648 | ||
649 | mutex_lock(&i2c_hid_open_mut); | ||
646 | if (!hid->open++) { | 650 | if (!hid->open++) { |
647 | ret = i2c_hid_set_power(client, I2C_HID_PWR_ON); | 651 | ret = i2c_hid_set_power(client, I2C_HID_PWR_ON); |
648 | if (ret) { | 652 | if (ret) { |
649 | hid->open--; | 653 | hid->open--; |
650 | return -EIO; | 654 | goto done; |
651 | } | 655 | } |
652 | set_bit(I2C_HID_STARTED, &ihid->flags); | 656 | set_bit(I2C_HID_STARTED, &ihid->flags); |
653 | } | 657 | } |
654 | return 0; | 658 | done: |
659 | mutex_unlock(&i2c_hid_open_mut); | ||
660 | return ret; | ||
655 | } | 661 | } |
656 | 662 | ||
657 | static void i2c_hid_close(struct hid_device *hid) | 663 | static void i2c_hid_close(struct hid_device *hid) |
@@ -663,12 +669,14 @@ static void i2c_hid_close(struct hid_device *hid) | |||
663 | * data acquistion due to a resumption we no longer | 669 | * data acquistion due to a resumption we no longer |
664 | * care about | 670 | * care about |
665 | */ | 671 | */ |
672 | mutex_lock(&i2c_hid_open_mut); | ||
666 | if (!--hid->open) { | 673 | if (!--hid->open) { |
667 | clear_bit(I2C_HID_STARTED, &ihid->flags); | 674 | clear_bit(I2C_HID_STARTED, &ihid->flags); |
668 | 675 | ||
669 | /* Save some power */ | 676 | /* Save some power */ |
670 | i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); | 677 | i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); |
671 | } | 678 | } |
679 | mutex_unlock(&i2c_hid_open_mut); | ||
672 | } | 680 | } |
673 | 681 | ||
674 | static int i2c_hid_power(struct hid_device *hid, int lvl) | 682 | static int i2c_hid_power(struct hid_device *hid, int lvl) |