diff options
Diffstat (limited to 'drivers/hid/hid-core.c')
-rw-r--r-- | drivers/hid/hid-core.c | 16 |
1 files changed, 12 insertions, 4 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index bb6f334f05bd..e9b5f44683fd 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2027,7 +2027,8 @@ EXPORT_SYMBOL_GPL(hid_report_raw_event); static int __hid_input_report(struct hid_device *hid, enum hid_report_type type, - u8 *data, u32 size, int interrupt, u64 source) + u8 *data, u32 size, int interrupt, u64 source, + bool lock_already_taken) { struct hid_report_enum *report_enum; struct hid_driver *hdrv; @@ -2037,8 +2038,13 @@ static int __hid_input_report(struct hid_device *hid, enum hid_report_type type, if (!hid) return -ENODEV; - if (down_trylock(&hid->driver_input_lock)) + ret = down_trylock(&hid->driver_input_lock); + if (lock_already_taken && !ret) { + up(&hid->driver_input_lock); + return -EINVAL; + } else if (!lock_already_taken && ret) { return -EBUSY; + } if (!hid->driver) { ret = -ENODEV; @@ -2079,7 +2085,8 @@ static int __hid_input_report(struct hid_device *hid, enum hid_report_type type, ret = hid_report_raw_event(hid, type, data, size, interrupt); unlock: - up(&hid->driver_input_lock); + if (!lock_already_taken) + up(&hid->driver_input_lock); return ret; } @@ -2097,7 +2104,8 @@ unlock: int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size, int interrupt) { - return __hid_input_report(hid, type, data, size, interrupt, 0); + return __hid_input_report(hid, type, data, size, interrupt, 0, + false /* lock_already_taken */); } EXPORT_SYMBOL_GPL(hid_input_report); |