aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSrinivas Pandruvada <srinivas.pandruvada@linux.intel.com>2015-04-10 14:22:22 -0400
committerJiri Kosina <jkosina@suse.cz>2015-04-10 16:22:55 -0400
commit4a7de0519df5e8fb89cef6ee062330ffe4b50a4d (patch)
tree587a0694e6db263f10290d3f3b4efc0619ca6469
parent62fad137bb1fc1dd08352aba18e7e13d0d682ef3 (diff)
HID: sensor: Custom and Generic sensor support
HID Sensor Spec defines two usage ids for custom sensors HID_USAGE_SENSOR_TYPE_OTHER_CUSTOM (0x09, 0xE1) HID_USAGE_SENSOR_TYPE_OTHER_GENERIC(0x09, 0xE2) In addition the standard also defines usage ids for custom fields. The purpose of these sensors is to extend the functionality or provide a way to obfuscate the data being communicated by a sensor. Without knowing the mapping between the data and its encapsulated form, it is difficult for an driver to determine what data is being communicated by the sensor. This allows some differentiating use cases, where vendor can provide applications. Since these can't be represented by standard sensor interfaces like IIO, we present these as fields with - type (input/output) - units - min/max - get/set value In addition an dev interface to transfer report events. Details about this interface is described in /Documentation/hid/hid-sensor.txt. Manufacturers should not use these ids for any standard sensors, otherwise the the product/vendor id can be added to black list. Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> Reviewed-by: Jonathan Cameron <jic23@kernel.org> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--drivers/hid/Kconfig15
-rw-r--r--drivers/hid/Makefile1
-rw-r--r--drivers/hid/hid-sensor-custom.c849
3 files changed, 865 insertions, 0 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 152b006833cd..7de0e9ed98f3 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -885,6 +885,21 @@ config HID_SENSOR_HUB
885 for events and handle data streams. Each sensor driver can format 885 for events and handle data streams. Each sensor driver can format
886 data and present to user mode using input or IIO interface. 886 data and present to user mode using input or IIO interface.
887 887
888config HID_SENSOR_CUSTOM_SENSOR
889 tristate "HID Sensors hub custom sensor support"
890 depends on HID_SENSOR_HUB
891 default n
892 ---help---
893 HID Sensor hub specification allows definition of some custom and
894 generic sensors. Unlike other HID sensors, they can't be exported
895 via Linux IIO because of custom fields. This is up to the manufacturer
896 to decide how to interpret these special sensor ids and process in
897 the user space. Currently some manufacturers are using these ids for
898 sensor calibration and debugging other sensors. Manufacturers
899 should't use these special custom sensor ids to export any of the
900 standard sensors.
901 Select this config option for custom/generic sensor support.
902
888endmenu 903endmenu
889 904
890endif # HID 905endif # HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 6f19958dfc38..c90ce7b900b6 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -101,6 +101,7 @@ obj-$(CONFIG_HID_WACOM) += wacom.o
101obj-$(CONFIG_HID_WALTOP) += hid-waltop.o 101obj-$(CONFIG_HID_WALTOP) += hid-waltop.o
102obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o 102obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o
103obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o 103obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o
104obj-$(CONFIG_HID_SENSOR_CUSTOM_SENSOR) += hid-sensor-custom.o
104 105
105obj-$(CONFIG_USB_HID) += usbhid/ 106obj-$(CONFIG_USB_HID) += usbhid/
106obj-$(CONFIG_USB_MOUSE) += usbhid/ 107obj-$(CONFIG_USB_MOUSE) += usbhid/
diff --git a/drivers/hid/hid-sensor-custom.c b/drivers/hid/hid-sensor-custom.c
new file mode 100644
index 000000000000..5614fee82347
--- /dev/null
+++ b/drivers/hid/hid-sensor-custom.c
@@ -0,0 +1,849 @@
1/*
2 * hid-sensor-custom.c
3 * Copyright (c) 2015, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 */
14
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/init.h>
18#include <linux/miscdevice.h>
19#include <linux/kfifo.h>
20#include <linux/sched.h>
21#include <linux/wait.h>
22#include <linux/poll.h>
23#include <linux/bsearch.h>
24#include <linux/platform_device.h>
25#include <linux/hid-sensor-hub.h>
26
27#define HID_CUSTOM_NAME_LENGTH 64
28#define HID_CUSTOM_MAX_CORE_ATTRS 10
29#define HID_CUSTOM_TOTAL_ATTRS (HID_CUSTOM_MAX_CORE_ATTRS + 1)
30#define HID_CUSTOM_FIFO_SIZE 4096
31#define HID_CUSTOM_MAX_FEATURE_BYTES 64
32
33struct hid_sensor_custom_field {
34 int report_id;
35 char group_name[HID_CUSTOM_NAME_LENGTH];
36 struct hid_sensor_hub_attribute_info attribute;
37 struct device_attribute sd_attrs[HID_CUSTOM_MAX_CORE_ATTRS];
38 char attr_name[HID_CUSTOM_TOTAL_ATTRS][HID_CUSTOM_NAME_LENGTH];
39 struct attribute *attrs[HID_CUSTOM_TOTAL_ATTRS];
40 struct attribute_group hid_custom_attribute_group;
41};
42
43struct hid_sensor_custom {
44 struct mutex mutex;
45 struct platform_device *pdev;
46 struct hid_sensor_hub_device *hsdev;
47 struct hid_sensor_hub_callbacks callbacks;
48 int sensor_field_count;
49 struct hid_sensor_custom_field *fields;
50 int input_field_count;
51 int input_report_size;
52 int input_report_recd_size;
53 bool input_skip_sample;
54 bool enable;
55 struct hid_sensor_custom_field *power_state;
56 struct hid_sensor_custom_field *report_state;
57 struct miscdevice custom_dev;
58 struct kfifo data_fifo;
59 unsigned long misc_opened;
60 wait_queue_head_t wait;
61};
62
63/* Header for each sample to user space via dev interface */
64struct hid_sensor_sample {
65 u32 usage_id;
66 u64 timestamp;
67 u32 raw_len;
68} __packed;
69
70static struct attribute hid_custom_attrs[] = {
71 {.name = "name", .mode = S_IRUGO},
72 {.name = "units", .mode = S_IRUGO},
73 {.name = "unit-expo", .mode = S_IRUGO},
74 {.name = "minimum", .mode = S_IRUGO},
75 {.name = "maximum", .mode = S_IRUGO},
76 {.name = "size", .mode = S_IRUGO},
77 {.name = "value", .mode = S_IWUSR | S_IRUGO},
78 {.name = NULL}
79};
80
81static const struct hid_custom_usage_desc {
82 int usage_id;
83 char *desc;
84} hid_custom_usage_desc_table[] = {
85 {0x200201, "event-sensor-state"},
86 {0x200202, "event-sensor-event"},
87 {0x200301, "property-friendly-name"},
88 {0x200302, "property-persistent-unique-id"},
89 {0x200303, "property-sensor-status"},
90 {0x200304, "property-min-report-interval"},
91 {0x200305, "property-sensor-manufacturer"},
92 {0x200306, "property-sensor-model"},
93 {0x200307, "property-sensor-serial-number"},
94 {0x200308, "property-sensor-description"},
95 {0x200309, "property-sensor-connection-type"},
96 {0x20030A, "property-sensor-device-path"},
97 {0x20030B, "property-hardware-revision"},
98 {0x20030C, "property-firmware-version"},
99 {0x20030D, "property-release-date"},
100 {0x20030E, "property-report-interval"},
101 {0x20030F, "property-change-sensitivity-absolute"},
102 {0x200310, "property-change-sensitivity-percent-range"},
103 {0x200311, "property-change-sensitivity-percent-relative"},
104 {0x200312, "property-accuracy"},
105 {0x200313, "property-resolution"},
106 {0x200314, "property-maximum"},
107 {0x200315, "property-minimum"},
108 {0x200316, "property-reporting-state"},
109 {0x200317, "property-sampling-rate"},
110 {0x200318, "property-response-curve"},
111 {0x200319, "property-power-state"},
112 {0x200540, "data-field-custom"},
113 {0x200541, "data-field-custom-usage"},
114 {0x200542, "data-field-custom-boolean-array"},
115 {0x200543, "data-field-custom-value"},
116 {0x200544, "data-field-custom-value_1"},
117 {0x200545, "data-field-custom-value_2"},
118 {0x200546, "data-field-custom-value_3"},
119 {0x200547, "data-field-custom-value_4"},
120 {0x200548, "data-field-custom-value_5"},
121 {0x200549, "data-field-custom-value_6"},
122 {0x20054A, "data-field-custom-value_7"},
123 {0x20054B, "data-field-custom-value_8"},
124 {0x20054C, "data-field-custom-value_9"},
125 {0x20054D, "data-field-custom-value_10"},
126 {0x20054E, "data-field-custom-value_11"},
127 {0x20054F, "data-field-custom-value_12"},
128 {0x200550, "data-field-custom-value_13"},
129 {0x200551, "data-field-custom-value_14"},
130 {0x200552, "data-field-custom-value_15"},
131 {0x200553, "data-field-custom-value_16"},
132 {0x200554, "data-field-custom-value_17"},
133 {0x200555, "data-field-custom-value_18"},
134 {0x200556, "data-field-custom-value_19"},
135 {0x200557, "data-field-custom-value_20"},
136 {0x200558, "data-field-custom-value_21"},
137 {0x200559, "data-field-custom-value_22"},
138 {0x20055A, "data-field-custom-value_23"},
139 {0x20055B, "data-field-custom-value_24"},
140 {0x20055C, "data-field-custom-value_25"},
141 {0x20055D, "data-field-custom-value_26"},
142 {0x20055E, "data-field-custom-value_27"},
143 {0x20055F, "data-field-custom-value_28"},
144};
145
146static int usage_id_cmp(const void *p1, const void *p2)
147{
148 if (*(int *)p1 < *(int *)p2)
149 return -1;
150
151 if (*(int *)p1 > *(int *)p2)
152 return 1;
153
154 return 0;
155}
156
157static ssize_t enable_sensor_show(struct device *dev,
158 struct device_attribute *attr, char *buf)
159{
160 struct platform_device *pdev = to_platform_device(dev);
161 struct hid_sensor_custom *sensor_inst = platform_get_drvdata(pdev);
162
163 return sprintf(buf, "%d\n", sensor_inst->enable);
164}
165
166static int set_power_report_state(struct hid_sensor_custom *sensor_inst,
167 bool state)
168{
169 int power_val = -1;
170 int report_val = -1;
171 u32 power_state_usage_id;
172 u32 report_state_usage_id;
173 int ret;
174
175 /*
176 * It is possible that the power/report state ids are not present.
177 * In this case this function will return success. But if the
178 * ids are present, then it will return error if set fails.
179 */
180 if (state) {
181 power_state_usage_id =
182 HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM;
183 report_state_usage_id =
184 HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM;
185 } else {
186 power_state_usage_id =
187 HID_USAGE_SENSOR_PROP_POWER_STATE_D4_POWER_OFF_ENUM;
188 report_state_usage_id =
189 HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM;
190 }
191
192 if (sensor_inst->power_state)
193 power_val = hid_sensor_get_usage_index(sensor_inst->hsdev,
194 sensor_inst->power_state->attribute.report_id,
195 sensor_inst->power_state->attribute.index,
196 power_state_usage_id);
197 if (sensor_inst->report_state)
198 report_val = hid_sensor_get_usage_index(sensor_inst->hsdev,
199 sensor_inst->report_state->attribute.report_id,
200 sensor_inst->report_state->attribute.index,
201 report_state_usage_id);
202
203 if (power_val >= 0) {
204 power_val +=
205 sensor_inst->power_state->attribute.logical_minimum;
206 ret = sensor_hub_set_feature(sensor_inst->hsdev,
207 sensor_inst->power_state->attribute.report_id,
208 sensor_inst->power_state->attribute.index,
209 sizeof(power_val),
210 &power_val);
211 if (ret) {
212 hid_err(sensor_inst->hsdev->hdev,
213 "Set power state failed\n");
214 return ret;
215 }
216 }
217
218 if (report_val >= 0) {
219 report_val +=
220 sensor_inst->report_state->attribute.logical_minimum;
221 ret = sensor_hub_set_feature(sensor_inst->hsdev,
222 sensor_inst->report_state->attribute.report_id,
223 sensor_inst->report_state->attribute.index,
224 sizeof(report_val),
225 &report_val);
226 if (ret) {
227 hid_err(sensor_inst->hsdev->hdev,
228 "Set report state failed\n");
229 return ret;
230 }
231 }
232
233 return 0;
234}
235
236static ssize_t enable_sensor_store(struct device *dev,
237 struct device_attribute *attr,
238 const char *buf, size_t count)
239{
240 struct platform_device *pdev = to_platform_device(dev);
241 struct hid_sensor_custom *sensor_inst = platform_get_drvdata(pdev);
242 int value;
243 int ret = -EINVAL;
244
245 if (kstrtoint(buf, 0, &value) != 0)
246 return -EINVAL;
247
248 mutex_lock(&sensor_inst->mutex);
249 if (value && !sensor_inst->enable) {
250 ret = sensor_hub_device_open(sensor_inst->hsdev);
251 if (ret)
252 goto unlock_state;
253
254 ret = set_power_report_state(sensor_inst, true);
255 if (ret) {
256 sensor_hub_device_close(sensor_inst->hsdev);
257 goto unlock_state;
258 }
259 sensor_inst->enable = true;
260 } else if (!value && sensor_inst->enable) {
261 ret = set_power_report_state(sensor_inst, false);
262 sensor_hub_device_close(sensor_inst->hsdev);
263 sensor_inst->enable = false;
264 }
265unlock_state:
266 mutex_unlock(&sensor_inst->mutex);
267 if (ret < 0)
268 return ret;
269
270 return count;
271}
272static DEVICE_ATTR_RW(enable_sensor);
273
274static struct attribute *enable_sensor_attrs[] = {
275 &dev_attr_enable_sensor.attr,
276 NULL,
277};
278
279static struct attribute_group enable_sensor_attr_group = {
280 .attrs = enable_sensor_attrs,
281};
282
283static ssize_t show_value(struct device *dev, struct device_attribute *attr,
284 char *buf)
285{
286 struct platform_device *pdev = to_platform_device(dev);
287 struct hid_sensor_custom *sensor_inst = platform_get_drvdata(pdev);
288 struct hid_sensor_hub_attribute_info *attribute;
289 int index, usage, field_index;
290 char name[HID_CUSTOM_NAME_LENGTH];
291 bool feature = false;
292 bool input = false;
293 int value = 0;
294
295 if (sscanf(attr->attr.name, "feature-%d-%x-%s", &index, &usage,
296 name) == 3) {
297 feature = true;
298 field_index = index + sensor_inst->input_field_count;
299 } else if (sscanf(attr->attr.name, "input-%d-%x-%s", &index, &usage,
300 name) == 3) {
301 input = true;
302 field_index = index;
303 } else
304 return -EINVAL;
305
306 if (!strncmp(name, "value", strlen("value"))) {
307 u32 report_id;
308 int ret;
309
310 attribute = &sensor_inst->fields[field_index].attribute;
311 report_id = attribute->report_id;
312 if (feature) {
313 u8 values[HID_CUSTOM_MAX_FEATURE_BYTES];
314 int len = 0;
315 u64 value = 0;
316 int i = 0;
317
318 ret = sensor_hub_get_feature(sensor_inst->hsdev,
319 report_id,
320 index,
321 sizeof(values), values);
322 if (ret < 0)
323 return ret;
324
325 while (i < ret) {
326 if (i + attribute->size > ret) {
327 len += snprintf(&buf[len],
328 PAGE_SIZE - len,
329 "%d ", values[i]);
330 break;
331 }
332 switch (attribute->size) {
333 case 2:
334 value = (u64) *(u16 *)&values[i];
335 i += attribute->size;
336 break;
337 case 4:
338 value = (u64) *(u32 *)&values[i];
339 i += attribute->size;
340 break;
341 case 8:
342 value = *(u64 *)&values[i];
343 i += attribute->size;
344 break;
345 default:
346 value = (u64) values[i];
347 ++i;
348 break;
349 }
350 len += snprintf(&buf[len], PAGE_SIZE - len,
351 "%lld ", value);
352 }
353 len += snprintf(&buf[len], PAGE_SIZE - len, "\n");
354
355 return len;
356 } else if (input)
357 value = sensor_hub_input_attr_get_raw_value(
358 sensor_inst->hsdev,
359 sensor_inst->hsdev->usage,
360 usage, report_id,
361 SENSOR_HUB_SYNC);
362 } else if (!strncmp(name, "units", strlen("units")))
363 value = sensor_inst->fields[field_index].attribute.units;
364 else if (!strncmp(name, "unit-expo", strlen("unit-expo")))
365 value = sensor_inst->fields[field_index].attribute.unit_expo;
366 else if (!strncmp(name, "size", strlen("size")))
367 value = sensor_inst->fields[field_index].attribute.size;
368 else if (!strncmp(name, "minimum", strlen("minimum")))
369 value = sensor_inst->fields[field_index].attribute.
370 logical_minimum;
371 else if (!strncmp(name, "maximum", strlen("maximum")))
372 value = sensor_inst->fields[field_index].attribute.
373 logical_maximum;
374 else if (!strncmp(name, "name", strlen("name"))) {
375 struct hid_custom_usage_desc *usage_desc;
376
377 usage_desc = bsearch(&usage, hid_custom_usage_desc_table,
378 ARRAY_SIZE(hid_custom_usage_desc_table),
379 sizeof(struct hid_custom_usage_desc),
380 usage_id_cmp);
381 if (usage_desc)
382 return snprintf(buf, PAGE_SIZE, "%s\n",
383 usage_desc->desc);
384 else
385 return sprintf(buf, "not-specified\n");
386 } else
387 return -EINVAL;
388
389 return sprintf(buf, "%d\n", value);
390}
391
392static ssize_t store_value(struct device *dev, struct device_attribute *attr,
393 const char *buf, size_t count)
394{
395 struct platform_device *pdev = to_platform_device(dev);
396 struct hid_sensor_custom *sensor_inst = platform_get_drvdata(pdev);
397 int index, field_index, usage;
398 char name[HID_CUSTOM_NAME_LENGTH];
399 int value;
400
401 if (sscanf(attr->attr.name, "feature-%d-%x-%s", &index, &usage,
402 name) == 3) {
403 field_index = index + sensor_inst->input_field_count;
404 } else
405 return -EINVAL;
406
407 if (!strncmp(name, "value", strlen("value"))) {
408 u32 report_id;
409 int ret;
410
411 if (kstrtoint(buf, 0, &value) != 0)
412 return -EINVAL;
413
414 report_id = sensor_inst->fields[field_index].attribute.
415 report_id;
416 ret = sensor_hub_set_feature(sensor_inst->hsdev, report_id,
417 index, sizeof(value), &value);
418 } else
419 return -EINVAL;
420
421 return count;
422}
423
424static int hid_sensor_capture_sample(struct hid_sensor_hub_device *hsdev,
425 unsigned usage_id, size_t raw_len,
426 char *raw_data, void *priv)
427{
428 struct hid_sensor_custom *sensor_inst = platform_get_drvdata(priv);
429 struct hid_sensor_sample header;
430
431 /* If any error occurs in a sample, rest of the fields are ignored */
432 if (sensor_inst->input_skip_sample) {
433 hid_err(sensor_inst->hsdev->hdev, "Skipped remaining data\n");
434 return 0;
435 }
436
437 hid_dbg(sensor_inst->hsdev->hdev, "%s received %d of %d\n", __func__,
438 (int) (sensor_inst->input_report_recd_size + raw_len),
439 sensor_inst->input_report_size);
440
441 if (!test_bit(0, &sensor_inst->misc_opened))
442 return 0;
443
444 if (!sensor_inst->input_report_recd_size) {
445 int required_size = sizeof(struct hid_sensor_sample) +
446 sensor_inst->input_report_size;
447 header.usage_id = hsdev->usage;
448 header.raw_len = sensor_inst->input_report_size;
449 header.timestamp = ktime_get_real_ns();
450 if (kfifo_avail(&sensor_inst->data_fifo) >= required_size) {
451 kfifo_in(&sensor_inst->data_fifo,
452 (unsigned char *)&header,
453 sizeof(header));
454 } else
455 sensor_inst->input_skip_sample = true;
456 }
457 if (kfifo_avail(&sensor_inst->data_fifo) >= raw_len)
458 kfifo_in(&sensor_inst->data_fifo, (unsigned char *)raw_data,
459 raw_len);
460
461 sensor_inst->input_report_recd_size += raw_len;
462
463 return 0;
464}
465
466static int hid_sensor_send_event(struct hid_sensor_hub_device *hsdev,
467 unsigned usage_id, void *priv)
468{
469 struct hid_sensor_custom *sensor_inst = platform_get_drvdata(priv);
470
471 if (!test_bit(0, &sensor_inst->misc_opened))
472 return 0;
473
474 sensor_inst->input_report_recd_size = 0;
475 sensor_inst->input_skip_sample = false;
476
477 wake_up(&sensor_inst->wait);
478
479 return 0;
480}
481
482static int hid_sensor_custom_add_field(struct hid_sensor_custom *sensor_inst,
483 int index, int report_type,
484 struct hid_report *report,
485 struct hid_field *field)
486{
487 struct hid_sensor_custom_field *sensor_field;
488 void *fields;
489
490 fields = krealloc(sensor_inst->fields,
491 (sensor_inst->sensor_field_count + 1) *
492 sizeof(struct hid_sensor_custom_field), GFP_KERNEL);
493 if (!fields) {
494 kfree(sensor_inst->fields);
495 return -ENOMEM;
496 }
497 sensor_inst->fields = fields;
498 sensor_field = &sensor_inst->fields[sensor_inst->sensor_field_count];
499 sensor_field->attribute.usage_id = sensor_inst->hsdev->usage;
500 if (field->logical)
501 sensor_field->attribute.attrib_id = field->logical;
502 else
503 sensor_field->attribute.attrib_id = field->usage[0].hid;
504
505 sensor_field->attribute.index = index;
506 sensor_field->attribute.report_id = report->id;
507 sensor_field->attribute.units = field->unit;
508 sensor_field->attribute.unit_expo = field->unit_exponent;
509 sensor_field->attribute.size = (field->report_size / 8);
510 sensor_field->attribute.logical_minimum = field->logical_minimum;
511 sensor_field->attribute.logical_maximum = field->logical_maximum;
512
513 if (report_type == HID_FEATURE_REPORT)
514 snprintf(sensor_field->group_name,
515 sizeof(sensor_field->group_name), "feature-%x-%x",
516 sensor_field->attribute.index,
517 sensor_field->attribute.attrib_id);
518 else if (report_type == HID_INPUT_REPORT) {
519 snprintf(sensor_field->group_name,
520 sizeof(sensor_field->group_name),
521 "input-%x-%x", sensor_field->attribute.index,
522 sensor_field->attribute.attrib_id);
523 sensor_inst->input_field_count++;
524 sensor_inst->input_report_size += (field->report_size *
525 field->report_count) / 8;
526 }
527
528 memset(&sensor_field->hid_custom_attribute_group, 0,
529 sizeof(struct attribute_group));
530 sensor_inst->sensor_field_count++;
531
532 return 0;
533}
534
535static int hid_sensor_custom_add_fields(struct hid_sensor_custom *sensor_inst,
536 struct hid_report_enum *report_enum,
537 int report_type)
538{
539 int i;
540 int ret;
541 struct hid_report *report;
542 struct hid_field *field;
543 struct hid_sensor_hub_device *hsdev = sensor_inst->hsdev;
544
545 list_for_each_entry(report, &report_enum->report_list, list) {
546 for (i = 0; i < report->maxfield; ++i) {
547 field = report->field[i];
548 if (field->maxusage &&
549 ((field->usage[0].collection_index >=
550 hsdev->start_collection_index) &&
551 (field->usage[0].collection_index <
552 hsdev->end_collection_index))) {
553
554 ret = hid_sensor_custom_add_field(sensor_inst,
555 i,
556 report_type,
557 report,
558 field);
559 if (ret)
560 return ret;
561
562 }
563 }
564 }
565
566 return 0;
567}
568
569static int hid_sensor_custom_add_attributes(struct hid_sensor_custom
570 *sensor_inst)
571{
572 struct hid_sensor_hub_device *hsdev = sensor_inst->hsdev;
573 struct hid_device *hdev = hsdev->hdev;
574 int ret = -1;
575 int i, j;
576
577 for (j = 0; j < HID_REPORT_TYPES; ++j) {
578 if (j == HID_OUTPUT_REPORT)
579 continue;
580
581 ret = hid_sensor_custom_add_fields(sensor_inst,
582 &hdev->report_enum[j], j);
583 if (ret)
584 return ret;
585
586 }
587
588 /* Create sysfs attributes */
589 for (i = 0; i < sensor_inst->sensor_field_count; ++i) {
590 j = 0;
591 while (j < HID_CUSTOM_TOTAL_ATTRS &&
592 hid_custom_attrs[j].name) {
593 struct device_attribute *device_attr;
594
595 device_attr = &sensor_inst->fields[i].sd_attrs[j];
596
597 snprintf((char *)&sensor_inst->fields[i].attr_name[j],
598 HID_CUSTOM_NAME_LENGTH, "%s-%s",
599 sensor_inst->fields[i].group_name,
600 hid_custom_attrs[j].name);
601 sysfs_attr_init(&device_attr->attr);
602 device_attr->attr.name =
603 (char *)&sensor_inst->fields[i].attr_name[j];
604 device_attr->attr.mode = hid_custom_attrs[j].mode;
605 device_attr->show = show_value;
606 if (hid_custom_attrs[j].mode & S_IWUSR)
607 device_attr->store = store_value;
608 sensor_inst->fields[i].attrs[j] = &device_attr->attr;
609 ++j;
610 }
611 sensor_inst->fields[i].attrs[j] = NULL;
612 sensor_inst->fields[i].hid_custom_attribute_group.attrs =
613 sensor_inst->fields[i].attrs;
614 sensor_inst->fields[i].hid_custom_attribute_group.name =
615 sensor_inst->fields[i].group_name;
616 ret = sysfs_create_group(&sensor_inst->pdev->dev.kobj,
617 &sensor_inst->fields[i].
618 hid_custom_attribute_group);
619 if (ret)
620 break;
621
622 /* For power or report field store indexes */
623 if (sensor_inst->fields[i].attribute.attrib_id ==
624 HID_USAGE_SENSOR_PROY_POWER_STATE)
625 sensor_inst->power_state = &sensor_inst->fields[i];
626 else if (sensor_inst->fields[i].attribute.attrib_id ==
627 HID_USAGE_SENSOR_PROP_REPORT_STATE)
628 sensor_inst->report_state = &sensor_inst->fields[i];
629 }
630
631 return ret;
632}
633
634static void hid_sensor_custom_remove_attributes(struct hid_sensor_custom *
635 sensor_inst)
636{
637 int i;
638
639 for (i = 0; i < sensor_inst->sensor_field_count; ++i)
640 sysfs_remove_group(&sensor_inst->pdev->dev.kobj,
641 &sensor_inst->fields[i].
642 hid_custom_attribute_group);
643
644 kfree(sensor_inst->fields);
645}
646
647static ssize_t hid_sensor_custom_read(struct file *file, char __user *buf,
648 size_t count, loff_t *f_ps)
649{
650 struct hid_sensor_custom *sensor_inst;
651 unsigned int copied;
652 int ret;
653
654 sensor_inst = container_of(file->private_data,
655 struct hid_sensor_custom, custom_dev);
656
657 if (count < sizeof(struct hid_sensor_sample))
658 return -EINVAL;
659
660 do {
661 if (kfifo_is_empty(&sensor_inst->data_fifo)) {
662 if (file->f_flags & O_NONBLOCK)
663 return -EAGAIN;
664
665 ret = wait_event_interruptible(sensor_inst->wait,
666 !kfifo_is_empty(&sensor_inst->data_fifo));
667 if (ret)
668 return ret;
669 }
670 ret = kfifo_to_user(&sensor_inst->data_fifo, buf, count,
671 &copied);
672 if (ret)
673 return ret;
674
675 } while (copied == 0);
676
677 return copied;
678}
679
680static int hid_sensor_custom_release(struct inode *inode, struct file *file)
681{
682 struct hid_sensor_custom *sensor_inst;
683
684 sensor_inst = container_of(file->private_data,
685 struct hid_sensor_custom, custom_dev);
686
687 clear_bit(0, &sensor_inst->misc_opened);
688
689 return 0;
690}
691
692static int hid_sensor_custom_open(struct inode *inode, struct file *file)
693{
694 struct hid_sensor_custom *sensor_inst;
695
696 sensor_inst = container_of(file->private_data,
697 struct hid_sensor_custom, custom_dev);
698 /* We essentially have single reader and writer */
699 if (test_and_set_bit(0, &sensor_inst->misc_opened))
700 return -EBUSY;
701
702 return nonseekable_open(inode, file);
703}
704
705static unsigned int hid_sensor_custom_poll(struct file *file,
706 struct poll_table_struct *wait)
707{
708 struct hid_sensor_custom *sensor_inst;
709 unsigned int mask = 0;
710
711 sensor_inst = container_of(file->private_data,
712 struct hid_sensor_custom, custom_dev);
713
714 poll_wait(file, &sensor_inst->wait, wait);
715
716 if (!kfifo_is_empty(&sensor_inst->data_fifo))
717 mask = POLLIN | POLLRDNORM;
718
719 return mask;
720}
721
722static const struct file_operations hid_sensor_custom_fops = {
723 .open = hid_sensor_custom_open,
724 .read = hid_sensor_custom_read,
725 .release = hid_sensor_custom_release,
726 .poll = hid_sensor_custom_poll,
727 .llseek = noop_llseek,
728};
729
730static int hid_sensor_custom_dev_if_add(struct hid_sensor_custom *sensor_inst)
731{
732 int ret;
733
734 ret = kfifo_alloc(&sensor_inst->data_fifo, HID_CUSTOM_FIFO_SIZE,
735 GFP_KERNEL);
736 if (ret)
737 return ret;
738
739 init_waitqueue_head(&sensor_inst->wait);
740
741 sensor_inst->custom_dev.minor = MISC_DYNAMIC_MINOR;
742 sensor_inst->custom_dev.name = dev_name(&sensor_inst->pdev->dev);
743 sensor_inst->custom_dev.fops = &hid_sensor_custom_fops,
744 ret = misc_register(&sensor_inst->custom_dev);
745 if (ret) {
746 kfifo_free(&sensor_inst->data_fifo);
747 return ret;
748 }
749 return 0;
750}
751
752static void hid_sensor_custom_dev_if_remove(struct hid_sensor_custom
753 *sensor_inst)
754{
755 wake_up(&sensor_inst->wait);
756 misc_deregister(&sensor_inst->custom_dev);
757 kfifo_free(&sensor_inst->data_fifo);
758
759}
760
761static int hid_sensor_custom_probe(struct platform_device *pdev)
762{
763 struct hid_sensor_custom *sensor_inst;
764 struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
765 int ret;
766
767 sensor_inst = devm_kzalloc(&pdev->dev, sizeof(*sensor_inst),
768 GFP_KERNEL);
769 if (!sensor_inst)
770 return -ENOMEM;
771
772 sensor_inst->callbacks.capture_sample = hid_sensor_capture_sample;
773 sensor_inst->callbacks.send_event = hid_sensor_send_event;
774 sensor_inst->callbacks.pdev = pdev;
775 sensor_inst->hsdev = hsdev;
776 sensor_inst->pdev = pdev;
777 mutex_init(&sensor_inst->mutex);
778 platform_set_drvdata(pdev, sensor_inst);
779 ret = sensor_hub_register_callback(hsdev, hsdev->usage,
780 &sensor_inst->callbacks);
781 if (ret < 0) {
782 dev_err(&pdev->dev, "callback reg failed\n");
783 return ret;
784 }
785
786 ret = sysfs_create_group(&sensor_inst->pdev->dev.kobj,
787 &enable_sensor_attr_group);
788 if (ret)
789 goto err_remove_callback;
790
791 ret = hid_sensor_custom_add_attributes(sensor_inst);
792 if (ret)
793 goto err_remove_group;
794
795 ret = hid_sensor_custom_dev_if_add(sensor_inst);
796 if (ret)
797 goto err_remove_attributes;
798
799 return 0;
800
801err_remove_attributes:
802 hid_sensor_custom_remove_attributes(sensor_inst);
803err_remove_group:
804 sysfs_remove_group(&sensor_inst->pdev->dev.kobj,
805 &enable_sensor_attr_group);
806err_remove_callback:
807 sensor_hub_remove_callback(hsdev, hsdev->usage);
808
809 return ret;
810}
811
812static int hid_sensor_custom_remove(struct platform_device *pdev)
813{
814 struct hid_sensor_custom *sensor_inst = platform_get_drvdata(pdev);
815 struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
816
817 hid_sensor_custom_dev_if_remove(sensor_inst);
818 hid_sensor_custom_remove_attributes(sensor_inst);
819 sysfs_remove_group(&sensor_inst->pdev->dev.kobj,
820 &enable_sensor_attr_group);
821 sensor_hub_remove_callback(hsdev, hsdev->usage);
822
823 return 0;
824}
825
826static struct platform_device_id hid_sensor_custom_ids[] = {
827 {
828 .name = "HID-SENSOR-2000e1",
829 },
830 {
831 .name = "HID-SENSOR-2000e2",
832 },
833 { /* sentinel */ }
834};
835MODULE_DEVICE_TABLE(platform, hid_sensor_custom_ids);
836
837static struct platform_driver hid_sensor_custom_platform_driver = {
838 .id_table = hid_sensor_custom_ids,
839 .driver = {
840 .name = KBUILD_MODNAME,
841 },
842 .probe = hid_sensor_custom_probe,
843 .remove = hid_sensor_custom_remove,
844};
845module_platform_driver(hid_sensor_custom_platform_driver);
846
847MODULE_DESCRIPTION("HID Sensor Custom and Generic sensor Driver");
848MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
849MODULE_LICENSE("GPL");