aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2014-06-10 05:05:43 -0400
committerJiri Kosina <jkosina@suse.cz>2014-06-10 05:05:43 -0400
commit0ccf091d1fbc1f99bb7f93bff8cf346769a9b0cd (patch)
tree6423de601e8ee6eb56bc79403d6a05351e735ade
parentd6b92c2c373e0beefa8048c1448992cd5cda6e07 (diff)
HID: sensor-hub: make dyn_callback_lock IRQ-safe
dyn_callback_lock is being taken from IRQ context through hid_irq_in() -> hid_input_report() -> sensor_hub_raw_event() -> sensor_hub_get_callback(), therefore anyone else acquiring it needs to disable IRQs to disable deadlocks. Reported-by: Alexander Holler <holler@ahsoftware.de> Tested-by: Alexander Holler <holler@ahsoftware.de> Reported-by: Reyad Attiyat <reyad.attiyat@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--drivers/hid/hid-sensor-hub.c24
1 files changed, 14 insertions, 10 deletions
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
index a8d5c8faf8cf..13ce4e3aebf4 100644
--- a/drivers/hid/hid-sensor-hub.c
+++ b/drivers/hid/hid-sensor-hub.c
@@ -159,17 +159,18 @@ int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
159{ 159{
160 struct hid_sensor_hub_callbacks_list *callback; 160 struct hid_sensor_hub_callbacks_list *callback;
161 struct sensor_hub_data *pdata = hid_get_drvdata(hsdev->hdev); 161 struct sensor_hub_data *pdata = hid_get_drvdata(hsdev->hdev);
162 unsigned long flags;
162 163
163 spin_lock(&pdata->dyn_callback_lock); 164 spin_lock_irqsave(&pdata->dyn_callback_lock, flags);
164 list_for_each_entry(callback, &pdata->dyn_callback_list, list) 165 list_for_each_entry(callback, &pdata->dyn_callback_list, list)
165 if (callback->usage_id == usage_id && 166 if (callback->usage_id == usage_id &&
166 callback->hsdev == hsdev) { 167 callback->hsdev == hsdev) {
167 spin_unlock(&pdata->dyn_callback_lock); 168 spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags);
168 return -EINVAL; 169 return -EINVAL;
169 } 170 }
170 callback = kzalloc(sizeof(*callback), GFP_ATOMIC); 171 callback = kzalloc(sizeof(*callback), GFP_ATOMIC);
171 if (!callback) { 172 if (!callback) {
172 spin_unlock(&pdata->dyn_callback_lock); 173 spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags);
173 return -ENOMEM; 174 return -ENOMEM;
174 } 175 }
175 callback->hsdev = hsdev; 176 callback->hsdev = hsdev;
@@ -177,7 +178,7 @@ int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
177 callback->usage_id = usage_id; 178 callback->usage_id = usage_id;
178 callback->priv = NULL; 179 callback->priv = NULL;
179 list_add_tail(&callback->list, &pdata->dyn_callback_list); 180 list_add_tail(&callback->list, &pdata->dyn_callback_list);
180 spin_unlock(&pdata->dyn_callback_lock); 181 spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags);
181 182
182 return 0; 183 return 0;
183} 184}
@@ -188,8 +189,9 @@ int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
188{ 189{
189 struct hid_sensor_hub_callbacks_list *callback; 190 struct hid_sensor_hub_callbacks_list *callback;
190 struct sensor_hub_data *pdata = hid_get_drvdata(hsdev->hdev); 191 struct sensor_hub_data *pdata = hid_get_drvdata(hsdev->hdev);
192 unsigned long flags;
191 193
192 spin_lock(&pdata->dyn_callback_lock); 194 spin_lock_irqsave(&pdata->dyn_callback_lock, flags);
193 list_for_each_entry(callback, &pdata->dyn_callback_list, list) 195 list_for_each_entry(callback, &pdata->dyn_callback_list, list)
194 if (callback->usage_id == usage_id && 196 if (callback->usage_id == usage_id &&
195 callback->hsdev == hsdev) { 197 callback->hsdev == hsdev) {
@@ -197,7 +199,7 @@ int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
197 kfree(callback); 199 kfree(callback);
198 break; 200 break;
199 } 201 }
200 spin_unlock(&pdata->dyn_callback_lock); 202 spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags);
201 203
202 return 0; 204 return 0;
203} 205}
@@ -378,15 +380,16 @@ static int sensor_hub_suspend(struct hid_device *hdev, pm_message_t message)
378{ 380{
379 struct sensor_hub_data *pdata = hid_get_drvdata(hdev); 381 struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
380 struct hid_sensor_hub_callbacks_list *callback; 382 struct hid_sensor_hub_callbacks_list *callback;
383 unsigned long flags;
381 384
382 hid_dbg(hdev, " sensor_hub_suspend\n"); 385 hid_dbg(hdev, " sensor_hub_suspend\n");
383 spin_lock(&pdata->dyn_callback_lock); 386 spin_lock_irqsave(&pdata->dyn_callback_lock, flags);
384 list_for_each_entry(callback, &pdata->dyn_callback_list, list) { 387 list_for_each_entry(callback, &pdata->dyn_callback_list, list) {
385 if (callback->usage_callback->suspend) 388 if (callback->usage_callback->suspend)
386 callback->usage_callback->suspend( 389 callback->usage_callback->suspend(
387 callback->hsdev, callback->priv); 390 callback->hsdev, callback->priv);
388 } 391 }
389 spin_unlock(&pdata->dyn_callback_lock); 392 spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags);
390 393
391 return 0; 394 return 0;
392} 395}
@@ -395,15 +398,16 @@ static int sensor_hub_resume(struct hid_device *hdev)
395{ 398{
396 struct sensor_hub_data *pdata = hid_get_drvdata(hdev); 399 struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
397 struct hid_sensor_hub_callbacks_list *callback; 400 struct hid_sensor_hub_callbacks_list *callback;
401 unsigned long flags;
398 402
399 hid_dbg(hdev, " sensor_hub_resume\n"); 403 hid_dbg(hdev, " sensor_hub_resume\n");
400 spin_lock(&pdata->dyn_callback_lock); 404 spin_lock_irqsave(&pdata->dyn_callback_lock, flags);
401 list_for_each_entry(callback, &pdata->dyn_callback_list, list) { 405 list_for_each_entry(callback, &pdata->dyn_callback_list, list) {
402 if (callback->usage_callback->resume) 406 if (callback->usage_callback->resume)
403 callback->usage_callback->resume( 407 callback->usage_callback->resume(
404 callback->hsdev, callback->priv); 408 callback->hsdev, callback->priv);
405 } 409 }
406 spin_unlock(&pdata->dyn_callback_lock); 410 spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags);
407 411
408 return 0; 412 return 0;
409} 413}