summaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
authorHeiner Kallweit <hkallweit1@gmail.com>2016-03-01 20:49:54 +0100
committerJiri Kosina <jkosina@suse.cz>2016-03-02 10:20:31 +0100
commit43a4a04d4ddb268373d5857c7a7bcbe3658e5b48 (patch)
tree7bcaa4f2b7774bdfddb465b903c79e9fd05ff83e /drivers/hid
parentHID: thingm: switch to managed version of led_classdev_register (diff)
downloadlinux-43a4a04d4ddb268373d5857c7a7bcbe3658e5b48.tar.xz
linux-43a4a04d4ddb268373d5857c7a7bcbe3658e5b48.zip
HID: thingm: improve locking
Reading from the device consists of two operations: sending the read command and the actual read from the device. If the device is accessed in between we might read wrong data. Therefore protect the full sequence of both operations with a mutex. Also change the semantics of thingm_recv to include both operations. Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/hid-thingm.c33
1 files changed, 22 insertions, 11 deletions
diff --git a/drivers/hid/hid-thingm.c b/drivers/hid/hid-thingm.c
index 5e35ec1b6d8a..f4196ac25a64 100644
--- a/drivers/hid/hid-thingm.c
+++ b/drivers/hid/hid-thingm.c
@@ -77,9 +77,13 @@ static int thingm_send(struct thingm_device *tdev, u8 buf[REPORT_SIZE])
buf[0], buf[1], buf[2], buf[3], buf[4],
buf[5], buf[6], buf[7], buf[8]);
+ mutex_lock(&tdev->lock);
+
ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+ mutex_unlock(&tdev->lock);
+
return ret < 0 ? ret : 0;
}
@@ -87,16 +91,31 @@ static int thingm_recv(struct thingm_device *tdev, u8 buf[REPORT_SIZE])
{
int ret;
+ /*
+ * A read consists of two operations: sending the read command
+ * and the actual read from the device. Use the mutex to protect
+ * the full sequence of both operations.
+ */
+ mutex_lock(&tdev->lock);
+
+ ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+ if (ret < 0)
+ goto err;
+
ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
if (ret < 0)
- return ret;
+ goto err;
+
+ ret = 0;
hid_dbg(tdev->hdev, "<- %d %c %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n",
buf[0], buf[1], buf[2], buf[3], buf[4],
buf[5], buf[6], buf[7], buf[8]);
-
- return 0;
+err:
+ mutex_unlock(&tdev->lock);
+ return ret;
}
static int thingm_version(struct thingm_device *tdev)
@@ -104,10 +123,6 @@ static int thingm_version(struct thingm_device *tdev)
u8 buf[REPORT_SIZE] = { REPORT_ID, 'v', 0, 0, 0, 0, 0, 0, 0 };
int err;
- err = thingm_send(tdev, buf);
- if (err)
- return err;
-
err = thingm_recv(tdev, buf);
if (err)
return err;
@@ -135,14 +150,10 @@ static int thingm_led_set(struct led_classdev *ldev,
struct thingm_led *led = container_of(ldev, struct thingm_led, ldev);
int ret;
- mutex_lock(&led->rgb->tdev->lock);
-
ret = thingm_write_color(led->rgb);
if (ret)
hid_err(led->rgb->tdev->hdev, "failed to write color\n");
- mutex_unlock(&led->rgb->tdev->lock);
-
return ret;
}