diff options
Diffstat (limited to 'drivers/hid/hid-sensor-hub.c')
-rw-r--r-- | drivers/hid/hid-sensor-hub.c | 198 |
1 files changed, 124 insertions, 74 deletions
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index e54ce1097e2c..c3f6f1e311ea 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c | |||
@@ -29,29 +29,10 @@ | |||
29 | #define HID_SENSOR_HUB_ENUM_QUIRK 0x01 | 29 | #define HID_SENSOR_HUB_ENUM_QUIRK 0x01 |
30 | 30 | ||
31 | /** | 31 | /** |
32 | * struct sensor_hub_pending - Synchronous read pending information | ||
33 | * @status: Pending status true/false. | ||
34 | * @ready: Completion synchronization data. | ||
35 | * @usage_id: Usage id for physical device, E.g. Gyro usage id. | ||
36 | * @attr_usage_id: Usage Id of a field, E.g. X-AXIS for a gyro. | ||
37 | * @raw_size: Response size for a read request. | ||
38 | * @raw_data: Place holder for received response. | ||
39 | */ | ||
40 | struct sensor_hub_pending { | ||
41 | bool status; | ||
42 | struct completion ready; | ||
43 | u32 usage_id; | ||
44 | u32 attr_usage_id; | ||
45 | int raw_size; | ||
46 | u8 *raw_data; | ||
47 | }; | ||
48 | |||
49 | /** | ||
50 | * struct sensor_hub_data - Hold a instance data for a HID hub device | 32 | * struct sensor_hub_data - Hold a instance data for a HID hub device |
51 | * @hsdev: Stored hid instance for current hub device. | 33 | * @hsdev: Stored hid instance for current hub device. |
52 | * @mutex: Mutex to serialize synchronous request. | 34 | * @mutex: Mutex to serialize synchronous request. |
53 | * @lock: Spin lock to protect pending request structure. | 35 | * @lock: Spin lock to protect pending request structure. |
54 | * @pending: Holds information of pending sync read request. | ||
55 | * @dyn_callback_list: Holds callback function | 36 | * @dyn_callback_list: Holds callback function |
56 | * @dyn_callback_lock: spin lock to protect callback list | 37 | * @dyn_callback_lock: spin lock to protect callback list |
57 | * @hid_sensor_hub_client_devs: Stores all MFD cells for a hub instance. | 38 | * @hid_sensor_hub_client_devs: Stores all MFD cells for a hub instance. |
@@ -61,7 +42,6 @@ struct sensor_hub_pending { | |||
61 | struct sensor_hub_data { | 42 | struct sensor_hub_data { |
62 | struct mutex mutex; | 43 | struct mutex mutex; |
63 | spinlock_t lock; | 44 | spinlock_t lock; |
64 | struct sensor_hub_pending pending; | ||
65 | struct list_head dyn_callback_list; | 45 | struct list_head dyn_callback_list; |
66 | spinlock_t dyn_callback_lock; | 46 | spinlock_t dyn_callback_lock; |
67 | struct mfd_cell *hid_sensor_hub_client_devs; | 47 | struct mfd_cell *hid_sensor_hub_client_devs; |
@@ -106,7 +86,8 @@ static int sensor_hub_get_physical_device_count(struct hid_device *hdev) | |||
106 | 86 | ||
107 | for (i = 0; i < hdev->maxcollection; ++i) { | 87 | for (i = 0; i < hdev->maxcollection; ++i) { |
108 | struct hid_collection *collection = &hdev->collection[i]; | 88 | struct hid_collection *collection = &hdev->collection[i]; |
109 | if (collection->type == HID_COLLECTION_PHYSICAL) | 89 | if (collection->type == HID_COLLECTION_PHYSICAL || |
90 | collection->type == HID_COLLECTION_APPLICATION) | ||
110 | ++count; | 91 | ++count; |
111 | } | 92 | } |
112 | 93 | ||
@@ -139,7 +120,8 @@ static struct hid_sensor_hub_callbacks *sensor_hub_get_callback( | |||
139 | 120 | ||
140 | spin_lock_irqsave(&pdata->dyn_callback_lock, flags); | 121 | spin_lock_irqsave(&pdata->dyn_callback_lock, flags); |
141 | list_for_each_entry(callback, &pdata->dyn_callback_list, list) | 122 | list_for_each_entry(callback, &pdata->dyn_callback_list, list) |
142 | if (callback->usage_id == usage_id && | 123 | if ((callback->usage_id == usage_id || |
124 | callback->usage_id == HID_USAGE_SENSOR_COLLECTION) && | ||
143 | (collection_index >= | 125 | (collection_index >= |
144 | callback->hsdev->start_collection_index) && | 126 | callback->hsdev->start_collection_index) && |
145 | (collection_index < | 127 | (collection_index < |
@@ -179,7 +161,18 @@ int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev, | |||
179 | callback->usage_callback = usage_callback; | 161 | callback->usage_callback = usage_callback; |
180 | callback->usage_id = usage_id; | 162 | callback->usage_id = usage_id; |
181 | callback->priv = NULL; | 163 | callback->priv = NULL; |
182 | list_add_tail(&callback->list, &pdata->dyn_callback_list); | 164 | /* |
165 | * If there is a handler registered for the collection type, then | ||
166 | * it will handle all reports for sensors in this collection. If | ||
167 | * there is also an individual sensor handler registration, then | ||
168 | * we want to make sure that the reports are directed to collection | ||
169 | * handler, as this may be a fusion sensor. So add collection handlers | ||
170 | * to the beginning of the list, so that they are matched first. | ||
171 | */ | ||
172 | if (usage_id == HID_USAGE_SENSOR_COLLECTION) | ||
173 | list_add(&callback->list, &pdata->dyn_callback_list); | ||
174 | else | ||
175 | list_add_tail(&callback->list, &pdata->dyn_callback_list); | ||
183 | spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); | 176 | spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags); |
184 | 177 | ||
185 | return 0; | 178 | return 0; |
@@ -208,10 +201,14 @@ int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev, | |||
208 | EXPORT_SYMBOL_GPL(sensor_hub_remove_callback); | 201 | EXPORT_SYMBOL_GPL(sensor_hub_remove_callback); |
209 | 202 | ||
210 | int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, | 203 | int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, |
211 | u32 field_index, s32 value) | 204 | u32 field_index, int buffer_size, void *buffer) |
212 | { | 205 | { |
213 | struct hid_report *report; | 206 | struct hid_report *report; |
214 | struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); | 207 | struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); |
208 | __s32 *buf32 = buffer; | ||
209 | int i = 0; | ||
210 | int remaining_bytes; | ||
211 | __s32 value; | ||
215 | int ret = 0; | 212 | int ret = 0; |
216 | 213 | ||
217 | mutex_lock(&data->mutex); | 214 | mutex_lock(&data->mutex); |
@@ -220,7 +217,21 @@ int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, | |||
220 | ret = -EINVAL; | 217 | ret = -EINVAL; |
221 | goto done_proc; | 218 | goto done_proc; |
222 | } | 219 | } |
223 | hid_set_field(report->field[field_index], 0, value); | 220 | |
221 | remaining_bytes = do_div(buffer_size, sizeof(__s32)); | ||
222 | if (buffer_size) { | ||
223 | for (i = 0; i < buffer_size; ++i) { | ||
224 | hid_set_field(report->field[field_index], i, | ||
225 | (__force __s32)cpu_to_le32(*buf32)); | ||
226 | ++buf32; | ||
227 | } | ||
228 | } | ||
229 | if (remaining_bytes) { | ||
230 | value = 0; | ||
231 | memcpy(&value, (u8 *)buf32, remaining_bytes); | ||
232 | hid_set_field(report->field[field_index], i, | ||
233 | (__force __s32)cpu_to_le32(value)); | ||
234 | } | ||
224 | hid_hw_request(hsdev->hdev, report, HID_REQ_SET_REPORT); | 235 | hid_hw_request(hsdev->hdev, report, HID_REQ_SET_REPORT); |
225 | hid_hw_wait(hsdev->hdev); | 236 | hid_hw_wait(hsdev->hdev); |
226 | 237 | ||
@@ -232,10 +243,11 @@ done_proc: | |||
232 | EXPORT_SYMBOL_GPL(sensor_hub_set_feature); | 243 | EXPORT_SYMBOL_GPL(sensor_hub_set_feature); |
233 | 244 | ||
234 | int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, | 245 | int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, |
235 | u32 field_index, s32 *value) | 246 | u32 field_index, int buffer_size, void *buffer) |
236 | { | 247 | { |
237 | struct hid_report *report; | 248 | struct hid_report *report; |
238 | struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); | 249 | struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); |
250 | int report_size; | ||
239 | int ret = 0; | 251 | int ret = 0; |
240 | 252 | ||
241 | mutex_lock(&data->mutex); | 253 | mutex_lock(&data->mutex); |
@@ -247,7 +259,17 @@ int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, | |||
247 | } | 259 | } |
248 | hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT); | 260 | hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT); |
249 | hid_hw_wait(hsdev->hdev); | 261 | hid_hw_wait(hsdev->hdev); |
250 | *value = report->field[field_index]->value[0]; | 262 | |
263 | /* calculate number of bytes required to read this field */ | ||
264 | report_size = DIV_ROUND_UP(report->field[field_index]->report_size, | ||
265 | 8) * | ||
266 | report->field[field_index]->report_count; | ||
267 | if (!report_size) { | ||
268 | ret = -EINVAL; | ||
269 | goto done_proc; | ||
270 | } | ||
271 | ret = min(report_size, buffer_size); | ||
272 | memcpy(buffer, report->field[field_index]->value, ret); | ||
251 | 273 | ||
252 | done_proc: | 274 | done_proc: |
253 | mutex_unlock(&data->mutex); | 275 | mutex_unlock(&data->mutex); |
@@ -259,47 +281,54 @@ EXPORT_SYMBOL_GPL(sensor_hub_get_feature); | |||
259 | 281 | ||
260 | int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev, | 282 | int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev, |
261 | u32 usage_id, | 283 | u32 usage_id, |
262 | u32 attr_usage_id, u32 report_id) | 284 | u32 attr_usage_id, u32 report_id, |
285 | enum sensor_hub_read_flags flag) | ||
263 | { | 286 | { |
264 | struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); | 287 | struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); |
265 | unsigned long flags; | 288 | unsigned long flags; |
266 | struct hid_report *report; | 289 | struct hid_report *report; |
267 | int ret_val = 0; | 290 | int ret_val = 0; |
268 | 291 | ||
269 | mutex_lock(&data->mutex); | 292 | report = sensor_hub_report(report_id, hsdev->hdev, |
270 | memset(&data->pending, 0, sizeof(data->pending)); | 293 | HID_INPUT_REPORT); |
271 | init_completion(&data->pending.ready); | ||
272 | data->pending.usage_id = usage_id; | ||
273 | data->pending.attr_usage_id = attr_usage_id; | ||
274 | data->pending.raw_size = 0; | ||
275 | |||
276 | spin_lock_irqsave(&data->lock, flags); | ||
277 | data->pending.status = true; | ||
278 | spin_unlock_irqrestore(&data->lock, flags); | ||
279 | report = sensor_hub_report(report_id, hsdev->hdev, HID_INPUT_REPORT); | ||
280 | if (!report) | 294 | if (!report) |
281 | goto err_free; | 295 | return -EINVAL; |
282 | 296 | ||
283 | hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT); | 297 | mutex_lock(&hsdev->mutex); |
284 | wait_for_completion_interruptible_timeout(&data->pending.ready, HZ*5); | 298 | if (flag == SENSOR_HUB_SYNC) { |
285 | switch (data->pending.raw_size) { | 299 | memset(&hsdev->pending, 0, sizeof(hsdev->pending)); |
286 | case 1: | 300 | init_completion(&hsdev->pending.ready); |
287 | ret_val = *(u8 *)data->pending.raw_data; | 301 | hsdev->pending.usage_id = usage_id; |
288 | break; | 302 | hsdev->pending.attr_usage_id = attr_usage_id; |
289 | case 2: | 303 | hsdev->pending.raw_size = 0; |
290 | ret_val = *(u16 *)data->pending.raw_data; | 304 | |
291 | break; | 305 | spin_lock_irqsave(&data->lock, flags); |
292 | case 4: | 306 | hsdev->pending.status = true; |
293 | ret_val = *(u32 *)data->pending.raw_data; | 307 | spin_unlock_irqrestore(&data->lock, flags); |
294 | break; | ||
295 | default: | ||
296 | ret_val = 0; | ||
297 | } | 308 | } |
298 | kfree(data->pending.raw_data); | 309 | mutex_lock(&data->mutex); |
299 | 310 | hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT); | |
300 | err_free: | ||
301 | data->pending.status = false; | ||
302 | mutex_unlock(&data->mutex); | 311 | mutex_unlock(&data->mutex); |
312 | if (flag == SENSOR_HUB_SYNC) { | ||
313 | wait_for_completion_interruptible_timeout( | ||
314 | &hsdev->pending.ready, HZ*5); | ||
315 | switch (hsdev->pending.raw_size) { | ||
316 | case 1: | ||
317 | ret_val = *(u8 *)hsdev->pending.raw_data; | ||
318 | break; | ||
319 | case 2: | ||
320 | ret_val = *(u16 *)hsdev->pending.raw_data; | ||
321 | break; | ||
322 | case 4: | ||
323 | ret_val = *(u32 *)hsdev->pending.raw_data; | ||
324 | break; | ||
325 | default: | ||
326 | ret_val = 0; | ||
327 | } | ||
328 | kfree(hsdev->pending.raw_data); | ||
329 | hsdev->pending.status = false; | ||
330 | } | ||
331 | mutex_unlock(&hsdev->mutex); | ||
303 | 332 | ||
304 | return ret_val; | 333 | return ret_val; |
305 | } | 334 | } |
@@ -455,16 +484,6 @@ static int sensor_hub_raw_event(struct hid_device *hdev, | |||
455 | report->field[i]->report_count)/8); | 484 | report->field[i]->report_count)/8); |
456 | sz = (report->field[i]->report_size * | 485 | sz = (report->field[i]->report_size * |
457 | report->field[i]->report_count)/8; | 486 | report->field[i]->report_count)/8; |
458 | if (pdata->pending.status && pdata->pending.attr_usage_id == | ||
459 | report->field[i]->usage->hid) { | ||
460 | hid_dbg(hdev, "data was pending ...\n"); | ||
461 | pdata->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC); | ||
462 | if (pdata->pending.raw_data) | ||
463 | pdata->pending.raw_size = sz; | ||
464 | else | ||
465 | pdata->pending.raw_size = 0; | ||
466 | complete(&pdata->pending.ready); | ||
467 | } | ||
468 | collection = &hdev->collection[ | 487 | collection = &hdev->collection[ |
469 | report->field[i]->usage->collection_index]; | 488 | report->field[i]->usage->collection_index]; |
470 | hid_dbg(hdev, "collection->usage %x\n", | 489 | hid_dbg(hdev, "collection->usage %x\n", |
@@ -474,8 +493,23 @@ static int sensor_hub_raw_event(struct hid_device *hdev, | |||
474 | report->field[i]->physical, | 493 | report->field[i]->physical, |
475 | report->field[i]->usage[0].collection_index, | 494 | report->field[i]->usage[0].collection_index, |
476 | &hsdev, &priv); | 495 | &hsdev, &priv); |
477 | 496 | if (!callback) { | |
478 | if (callback && callback->capture_sample) { | 497 | ptr += sz; |
498 | continue; | ||
499 | } | ||
500 | if (hsdev->pending.status && (hsdev->pending.attr_usage_id == | ||
501 | report->field[i]->usage->hid || | ||
502 | hsdev->pending.attr_usage_id == | ||
503 | report->field[i]->logical)) { | ||
504 | hid_dbg(hdev, "data was pending ...\n"); | ||
505 | hsdev->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC); | ||
506 | if (hsdev->pending.raw_data) | ||
507 | hsdev->pending.raw_size = sz; | ||
508 | else | ||
509 | hsdev->pending.raw_size = 0; | ||
510 | complete(&hsdev->pending.ready); | ||
511 | } | ||
512 | if (callback->capture_sample) { | ||
479 | if (report->field[i]->logical) | 513 | if (report->field[i]->logical) |
480 | callback->capture_sample(hsdev, | 514 | callback->capture_sample(hsdev, |
481 | report->field[i]->logical, sz, ptr, | 515 | report->field[i]->logical, sz, ptr, |
@@ -572,6 +606,7 @@ static int sensor_hub_probe(struct hid_device *hdev, | |||
572 | int dev_cnt; | 606 | int dev_cnt; |
573 | struct hid_sensor_hub_device *hsdev; | 607 | struct hid_sensor_hub_device *hsdev; |
574 | struct hid_sensor_hub_device *last_hsdev = NULL; | 608 | struct hid_sensor_hub_device *last_hsdev = NULL; |
609 | struct hid_sensor_hub_device *collection_hsdev = NULL; | ||
575 | 610 | ||
576 | sd = devm_kzalloc(&hdev->dev, sizeof(*sd), GFP_KERNEL); | 611 | sd = devm_kzalloc(&hdev->dev, sizeof(*sd), GFP_KERNEL); |
577 | if (!sd) { | 612 | if (!sd) { |
@@ -618,7 +653,8 @@ static int sensor_hub_probe(struct hid_device *hdev, | |||
618 | for (i = 0; i < hdev->maxcollection; ++i) { | 653 | for (i = 0; i < hdev->maxcollection; ++i) { |
619 | struct hid_collection *collection = &hdev->collection[i]; | 654 | struct hid_collection *collection = &hdev->collection[i]; |
620 | 655 | ||
621 | if (collection->type == HID_COLLECTION_PHYSICAL) { | 656 | if (collection->type == HID_COLLECTION_PHYSICAL || |
657 | collection->type == HID_COLLECTION_APPLICATION) { | ||
622 | 658 | ||
623 | hsdev = devm_kzalloc(&hdev->dev, sizeof(*hsdev), | 659 | hsdev = devm_kzalloc(&hdev->dev, sizeof(*hsdev), |
624 | GFP_KERNEL); | 660 | GFP_KERNEL); |
@@ -630,6 +666,8 @@ static int sensor_hub_probe(struct hid_device *hdev, | |||
630 | hsdev->hdev = hdev; | 666 | hsdev->hdev = hdev; |
631 | hsdev->vendor_id = hdev->vendor; | 667 | hsdev->vendor_id = hdev->vendor; |
632 | hsdev->product_id = hdev->product; | 668 | hsdev->product_id = hdev->product; |
669 | hsdev->usage = collection->usage; | ||
670 | mutex_init(&hsdev->mutex); | ||
633 | hsdev->start_collection_index = i; | 671 | hsdev->start_collection_index = i; |
634 | if (last_hsdev) | 672 | if (last_hsdev) |
635 | last_hsdev->end_collection_index = i; | 673 | last_hsdev->end_collection_index = i; |
@@ -653,10 +691,17 @@ static int sensor_hub_probe(struct hid_device *hdev, | |||
653 | hid_dbg(hdev, "Adding %s:%d\n", name, | 691 | hid_dbg(hdev, "Adding %s:%d\n", name, |
654 | hsdev->start_collection_index); | 692 | hsdev->start_collection_index); |
655 | sd->hid_sensor_client_cnt++; | 693 | sd->hid_sensor_client_cnt++; |
694 | if (collection_hsdev) | ||
695 | collection_hsdev->end_collection_index = i; | ||
696 | if (collection->type == HID_COLLECTION_APPLICATION && | ||
697 | collection->usage == HID_USAGE_SENSOR_COLLECTION) | ||
698 | collection_hsdev = hsdev; | ||
656 | } | 699 | } |
657 | } | 700 | } |
658 | if (last_hsdev) | 701 | if (last_hsdev) |
659 | last_hsdev->end_collection_index = i; | 702 | last_hsdev->end_collection_index = i; |
703 | if (collection_hsdev) | ||
704 | collection_hsdev->end_collection_index = i; | ||
660 | 705 | ||
661 | ret = mfd_add_hotplug_devices(&hdev->dev, | 706 | ret = mfd_add_hotplug_devices(&hdev->dev, |
662 | sd->hid_sensor_hub_client_devs, | 707 | sd->hid_sensor_hub_client_devs, |
@@ -676,13 +721,18 @@ static void sensor_hub_remove(struct hid_device *hdev) | |||
676 | { | 721 | { |
677 | struct sensor_hub_data *data = hid_get_drvdata(hdev); | 722 | struct sensor_hub_data *data = hid_get_drvdata(hdev); |
678 | unsigned long flags; | 723 | unsigned long flags; |
724 | int i; | ||
679 | 725 | ||
680 | hid_dbg(hdev, " hardware removed\n"); | 726 | hid_dbg(hdev, " hardware removed\n"); |
681 | hid_hw_close(hdev); | 727 | hid_hw_close(hdev); |
682 | hid_hw_stop(hdev); | 728 | hid_hw_stop(hdev); |
683 | spin_lock_irqsave(&data->lock, flags); | 729 | spin_lock_irqsave(&data->lock, flags); |
684 | if (data->pending.status) | 730 | for (i = 0; i < data->hid_sensor_client_cnt; ++i) { |
685 | complete(&data->pending.ready); | 731 | struct hid_sensor_hub_device *hsdev = |
732 | data->hid_sensor_hub_client_devs[i].platform_data; | ||
733 | if (hsdev->pending.status) | ||
734 | complete(&hsdev->pending.ready); | ||
735 | } | ||
686 | spin_unlock_irqrestore(&data->lock, flags); | 736 | spin_unlock_irqrestore(&data->lock, flags); |
687 | mfd_remove_devices(&hdev->dev); | 737 | mfd_remove_devices(&hdev->dev); |
688 | hid_set_drvdata(hdev, NULL); | 738 | hid_set_drvdata(hdev, NULL); |