18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * hid-sensor-custom.c
48c2ecf20Sopenharmony_ci * Copyright (c) 2015, Intel Corporation.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/kernel.h>
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <linux/init.h>
108c2ecf20Sopenharmony_ci#include <linux/miscdevice.h>
118c2ecf20Sopenharmony_ci#include <linux/kfifo.h>
128c2ecf20Sopenharmony_ci#include <linux/sched.h>
138c2ecf20Sopenharmony_ci#include <linux/wait.h>
148c2ecf20Sopenharmony_ci#include <linux/poll.h>
158c2ecf20Sopenharmony_ci#include <linux/bsearch.h>
168c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
178c2ecf20Sopenharmony_ci#include <linux/hid-sensor-hub.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define HID_CUSTOM_NAME_LENGTH		64
208c2ecf20Sopenharmony_ci#define HID_CUSTOM_MAX_CORE_ATTRS	10
218c2ecf20Sopenharmony_ci#define HID_CUSTOM_TOTAL_ATTRS		(HID_CUSTOM_MAX_CORE_ATTRS + 1)
228c2ecf20Sopenharmony_ci#define HID_CUSTOM_FIFO_SIZE		4096
238c2ecf20Sopenharmony_ci#define HID_CUSTOM_MAX_FEATURE_BYTES	64
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistruct hid_sensor_custom_field {
268c2ecf20Sopenharmony_ci	int report_id;
278c2ecf20Sopenharmony_ci	char group_name[HID_CUSTOM_NAME_LENGTH];
288c2ecf20Sopenharmony_ci	struct hid_sensor_hub_attribute_info attribute;
298c2ecf20Sopenharmony_ci	struct device_attribute sd_attrs[HID_CUSTOM_MAX_CORE_ATTRS];
308c2ecf20Sopenharmony_ci	char attr_name[HID_CUSTOM_TOTAL_ATTRS][HID_CUSTOM_NAME_LENGTH];
318c2ecf20Sopenharmony_ci	struct attribute *attrs[HID_CUSTOM_TOTAL_ATTRS];
328c2ecf20Sopenharmony_ci	struct attribute_group hid_custom_attribute_group;
338c2ecf20Sopenharmony_ci};
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistruct hid_sensor_custom {
368c2ecf20Sopenharmony_ci	struct mutex mutex;
378c2ecf20Sopenharmony_ci	struct platform_device *pdev;
388c2ecf20Sopenharmony_ci	struct hid_sensor_hub_device *hsdev;
398c2ecf20Sopenharmony_ci	struct hid_sensor_hub_callbacks callbacks;
408c2ecf20Sopenharmony_ci	int sensor_field_count;
418c2ecf20Sopenharmony_ci	struct hid_sensor_custom_field *fields;
428c2ecf20Sopenharmony_ci	int input_field_count;
438c2ecf20Sopenharmony_ci	int input_report_size;
448c2ecf20Sopenharmony_ci	int input_report_recd_size;
458c2ecf20Sopenharmony_ci	bool input_skip_sample;
468c2ecf20Sopenharmony_ci	bool enable;
478c2ecf20Sopenharmony_ci	struct hid_sensor_custom_field *power_state;
488c2ecf20Sopenharmony_ci	struct hid_sensor_custom_field *report_state;
498c2ecf20Sopenharmony_ci	struct miscdevice custom_dev;
508c2ecf20Sopenharmony_ci	struct kfifo data_fifo;
518c2ecf20Sopenharmony_ci	unsigned long misc_opened;
528c2ecf20Sopenharmony_ci	wait_queue_head_t wait;
538c2ecf20Sopenharmony_ci};
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/* Header for each sample to user space via dev interface */
568c2ecf20Sopenharmony_cistruct hid_sensor_sample {
578c2ecf20Sopenharmony_ci	u32 usage_id;
588c2ecf20Sopenharmony_ci	u64 timestamp;
598c2ecf20Sopenharmony_ci	u32 raw_len;
608c2ecf20Sopenharmony_ci} __packed;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic struct attribute hid_custom_attrs[HID_CUSTOM_TOTAL_ATTRS] = {
638c2ecf20Sopenharmony_ci	{.name = "name", .mode = S_IRUGO},
648c2ecf20Sopenharmony_ci	{.name = "units", .mode = S_IRUGO},
658c2ecf20Sopenharmony_ci	{.name = "unit-expo", .mode = S_IRUGO},
668c2ecf20Sopenharmony_ci	{.name = "minimum", .mode = S_IRUGO},
678c2ecf20Sopenharmony_ci	{.name = "maximum", .mode = S_IRUGO},
688c2ecf20Sopenharmony_ci	{.name = "size", .mode = S_IRUGO},
698c2ecf20Sopenharmony_ci	{.name = "value", .mode = S_IWUSR | S_IRUGO},
708c2ecf20Sopenharmony_ci	{.name = NULL}
718c2ecf20Sopenharmony_ci};
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic const struct hid_custom_usage_desc {
748c2ecf20Sopenharmony_ci	int usage_id;
758c2ecf20Sopenharmony_ci	char *desc;
768c2ecf20Sopenharmony_ci} hid_custom_usage_desc_table[] = {
778c2ecf20Sopenharmony_ci	{0x200201,	"event-sensor-state"},
788c2ecf20Sopenharmony_ci	{0x200202,	"event-sensor-event"},
798c2ecf20Sopenharmony_ci	{0x200301,	"property-friendly-name"},
808c2ecf20Sopenharmony_ci	{0x200302,	"property-persistent-unique-id"},
818c2ecf20Sopenharmony_ci	{0x200303,	"property-sensor-status"},
828c2ecf20Sopenharmony_ci	{0x200304,	"property-min-report-interval"},
838c2ecf20Sopenharmony_ci	{0x200305,	"property-sensor-manufacturer"},
848c2ecf20Sopenharmony_ci	{0x200306,	"property-sensor-model"},
858c2ecf20Sopenharmony_ci	{0x200307,	"property-sensor-serial-number"},
868c2ecf20Sopenharmony_ci	{0x200308,	"property-sensor-description"},
878c2ecf20Sopenharmony_ci	{0x200309,	"property-sensor-connection-type"},
888c2ecf20Sopenharmony_ci	{0x20030A,	"property-sensor-device-path"},
898c2ecf20Sopenharmony_ci	{0x20030B,	"property-hardware-revision"},
908c2ecf20Sopenharmony_ci	{0x20030C,	"property-firmware-version"},
918c2ecf20Sopenharmony_ci	{0x20030D,	"property-release-date"},
928c2ecf20Sopenharmony_ci	{0x20030E,	"property-report-interval"},
938c2ecf20Sopenharmony_ci	{0x20030F,	"property-change-sensitivity-absolute"},
948c2ecf20Sopenharmony_ci	{0x200310,	"property-change-sensitivity-percent-range"},
958c2ecf20Sopenharmony_ci	{0x200311,	"property-change-sensitivity-percent-relative"},
968c2ecf20Sopenharmony_ci	{0x200312,	"property-accuracy"},
978c2ecf20Sopenharmony_ci	{0x200313,	"property-resolution"},
988c2ecf20Sopenharmony_ci	{0x200314,	"property-maximum"},
998c2ecf20Sopenharmony_ci	{0x200315,	"property-minimum"},
1008c2ecf20Sopenharmony_ci	{0x200316,	"property-reporting-state"},
1018c2ecf20Sopenharmony_ci	{0x200317,	"property-sampling-rate"},
1028c2ecf20Sopenharmony_ci	{0x200318,	"property-response-curve"},
1038c2ecf20Sopenharmony_ci	{0x200319,	"property-power-state"},
1048c2ecf20Sopenharmony_ci	{0x200540,	"data-field-custom"},
1058c2ecf20Sopenharmony_ci	{0x200541,	"data-field-custom-usage"},
1068c2ecf20Sopenharmony_ci	{0x200542,	"data-field-custom-boolean-array"},
1078c2ecf20Sopenharmony_ci	{0x200543,	"data-field-custom-value"},
1088c2ecf20Sopenharmony_ci	{0x200544,	"data-field-custom-value_1"},
1098c2ecf20Sopenharmony_ci	{0x200545,	"data-field-custom-value_2"},
1108c2ecf20Sopenharmony_ci	{0x200546,	"data-field-custom-value_3"},
1118c2ecf20Sopenharmony_ci	{0x200547,	"data-field-custom-value_4"},
1128c2ecf20Sopenharmony_ci	{0x200548,	"data-field-custom-value_5"},
1138c2ecf20Sopenharmony_ci	{0x200549,	"data-field-custom-value_6"},
1148c2ecf20Sopenharmony_ci	{0x20054A,	"data-field-custom-value_7"},
1158c2ecf20Sopenharmony_ci	{0x20054B,	"data-field-custom-value_8"},
1168c2ecf20Sopenharmony_ci	{0x20054C,	"data-field-custom-value_9"},
1178c2ecf20Sopenharmony_ci	{0x20054D,	"data-field-custom-value_10"},
1188c2ecf20Sopenharmony_ci	{0x20054E,	"data-field-custom-value_11"},
1198c2ecf20Sopenharmony_ci	{0x20054F,	"data-field-custom-value_12"},
1208c2ecf20Sopenharmony_ci	{0x200550,	"data-field-custom-value_13"},
1218c2ecf20Sopenharmony_ci	{0x200551,	"data-field-custom-value_14"},
1228c2ecf20Sopenharmony_ci	{0x200552,	"data-field-custom-value_15"},
1238c2ecf20Sopenharmony_ci	{0x200553,	"data-field-custom-value_16"},
1248c2ecf20Sopenharmony_ci	{0x200554,	"data-field-custom-value_17"},
1258c2ecf20Sopenharmony_ci	{0x200555,	"data-field-custom-value_18"},
1268c2ecf20Sopenharmony_ci	{0x200556,	"data-field-custom-value_19"},
1278c2ecf20Sopenharmony_ci	{0x200557,	"data-field-custom-value_20"},
1288c2ecf20Sopenharmony_ci	{0x200558,	"data-field-custom-value_21"},
1298c2ecf20Sopenharmony_ci	{0x200559,	"data-field-custom-value_22"},
1308c2ecf20Sopenharmony_ci	{0x20055A,	"data-field-custom-value_23"},
1318c2ecf20Sopenharmony_ci	{0x20055B,	"data-field-custom-value_24"},
1328c2ecf20Sopenharmony_ci	{0x20055C,	"data-field-custom-value_25"},
1338c2ecf20Sopenharmony_ci	{0x20055D,	"data-field-custom-value_26"},
1348c2ecf20Sopenharmony_ci	{0x20055E,	"data-field-custom-value_27"},
1358c2ecf20Sopenharmony_ci	{0x20055F,	"data-field-custom-value_28"},
1368c2ecf20Sopenharmony_ci};
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic int usage_id_cmp(const void *p1, const void *p2)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	if (*(int *)p1 < *(int *)p2)
1418c2ecf20Sopenharmony_ci		return -1;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	if (*(int *)p1 > *(int *)p2)
1448c2ecf20Sopenharmony_ci		return 1;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	return 0;
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic ssize_t enable_sensor_show(struct device *dev,
1508c2ecf20Sopenharmony_ci				  struct device_attribute *attr, char *buf)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	struct hid_sensor_custom *sensor_inst = dev_get_drvdata(dev);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", sensor_inst->enable);
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic int set_power_report_state(struct hid_sensor_custom *sensor_inst,
1588c2ecf20Sopenharmony_ci				  bool state)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	int power_val = -1;
1618c2ecf20Sopenharmony_ci	int report_val = -1;
1628c2ecf20Sopenharmony_ci	u32 power_state_usage_id;
1638c2ecf20Sopenharmony_ci	u32 report_state_usage_id;
1648c2ecf20Sopenharmony_ci	int ret;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	/*
1678c2ecf20Sopenharmony_ci	 * It is possible that the power/report state ids are not present.
1688c2ecf20Sopenharmony_ci	 * In this case this function will return success. But if the
1698c2ecf20Sopenharmony_ci	 * ids are present, then it will return error if set fails.
1708c2ecf20Sopenharmony_ci	 */
1718c2ecf20Sopenharmony_ci	if (state) {
1728c2ecf20Sopenharmony_ci		power_state_usage_id =
1738c2ecf20Sopenharmony_ci			HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM;
1748c2ecf20Sopenharmony_ci		report_state_usage_id =
1758c2ecf20Sopenharmony_ci			HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM;
1768c2ecf20Sopenharmony_ci	} else {
1778c2ecf20Sopenharmony_ci		power_state_usage_id =
1788c2ecf20Sopenharmony_ci			HID_USAGE_SENSOR_PROP_POWER_STATE_D4_POWER_OFF_ENUM;
1798c2ecf20Sopenharmony_ci		report_state_usage_id =
1808c2ecf20Sopenharmony_ci			HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM;
1818c2ecf20Sopenharmony_ci	}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	if (sensor_inst->power_state)
1848c2ecf20Sopenharmony_ci		power_val = hid_sensor_get_usage_index(sensor_inst->hsdev,
1858c2ecf20Sopenharmony_ci				sensor_inst->power_state->attribute.report_id,
1868c2ecf20Sopenharmony_ci				sensor_inst->power_state->attribute.index,
1878c2ecf20Sopenharmony_ci				power_state_usage_id);
1888c2ecf20Sopenharmony_ci	if (sensor_inst->report_state)
1898c2ecf20Sopenharmony_ci		report_val = hid_sensor_get_usage_index(sensor_inst->hsdev,
1908c2ecf20Sopenharmony_ci				sensor_inst->report_state->attribute.report_id,
1918c2ecf20Sopenharmony_ci				sensor_inst->report_state->attribute.index,
1928c2ecf20Sopenharmony_ci				report_state_usage_id);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	if (power_val >= 0) {
1958c2ecf20Sopenharmony_ci		power_val +=
1968c2ecf20Sopenharmony_ci			sensor_inst->power_state->attribute.logical_minimum;
1978c2ecf20Sopenharmony_ci		ret = sensor_hub_set_feature(sensor_inst->hsdev,
1988c2ecf20Sopenharmony_ci				sensor_inst->power_state->attribute.report_id,
1998c2ecf20Sopenharmony_ci				sensor_inst->power_state->attribute.index,
2008c2ecf20Sopenharmony_ci				sizeof(power_val),
2018c2ecf20Sopenharmony_ci				&power_val);
2028c2ecf20Sopenharmony_ci		if (ret) {
2038c2ecf20Sopenharmony_ci			hid_err(sensor_inst->hsdev->hdev,
2048c2ecf20Sopenharmony_ci				"Set power state failed\n");
2058c2ecf20Sopenharmony_ci			return ret;
2068c2ecf20Sopenharmony_ci		}
2078c2ecf20Sopenharmony_ci	}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	if (report_val >= 0) {
2108c2ecf20Sopenharmony_ci		report_val +=
2118c2ecf20Sopenharmony_ci			sensor_inst->report_state->attribute.logical_minimum;
2128c2ecf20Sopenharmony_ci		ret = sensor_hub_set_feature(sensor_inst->hsdev,
2138c2ecf20Sopenharmony_ci				sensor_inst->report_state->attribute.report_id,
2148c2ecf20Sopenharmony_ci				sensor_inst->report_state->attribute.index,
2158c2ecf20Sopenharmony_ci				sizeof(report_val),
2168c2ecf20Sopenharmony_ci				&report_val);
2178c2ecf20Sopenharmony_ci		if (ret) {
2188c2ecf20Sopenharmony_ci			hid_err(sensor_inst->hsdev->hdev,
2198c2ecf20Sopenharmony_ci				"Set report state failed\n");
2208c2ecf20Sopenharmony_ci			return ret;
2218c2ecf20Sopenharmony_ci		}
2228c2ecf20Sopenharmony_ci	}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	return 0;
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic ssize_t enable_sensor_store(struct device *dev,
2288c2ecf20Sopenharmony_ci				   struct device_attribute *attr,
2298c2ecf20Sopenharmony_ci				   const char *buf, size_t count)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	struct hid_sensor_custom *sensor_inst = dev_get_drvdata(dev);
2328c2ecf20Sopenharmony_ci	int value;
2338c2ecf20Sopenharmony_ci	int ret = -EINVAL;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	if (kstrtoint(buf, 0, &value) != 0)
2368c2ecf20Sopenharmony_ci		return -EINVAL;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	mutex_lock(&sensor_inst->mutex);
2398c2ecf20Sopenharmony_ci	if (value && !sensor_inst->enable) {
2408c2ecf20Sopenharmony_ci		ret = sensor_hub_device_open(sensor_inst->hsdev);
2418c2ecf20Sopenharmony_ci		if (ret)
2428c2ecf20Sopenharmony_ci			goto unlock_state;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci		ret = set_power_report_state(sensor_inst, true);
2458c2ecf20Sopenharmony_ci		if (ret) {
2468c2ecf20Sopenharmony_ci			sensor_hub_device_close(sensor_inst->hsdev);
2478c2ecf20Sopenharmony_ci			goto unlock_state;
2488c2ecf20Sopenharmony_ci		}
2498c2ecf20Sopenharmony_ci		sensor_inst->enable = true;
2508c2ecf20Sopenharmony_ci	} else if (!value && sensor_inst->enable) {
2518c2ecf20Sopenharmony_ci		ret = set_power_report_state(sensor_inst, false);
2528c2ecf20Sopenharmony_ci		sensor_hub_device_close(sensor_inst->hsdev);
2538c2ecf20Sopenharmony_ci		sensor_inst->enable = false;
2548c2ecf20Sopenharmony_ci	}
2558c2ecf20Sopenharmony_ciunlock_state:
2568c2ecf20Sopenharmony_ci	mutex_unlock(&sensor_inst->mutex);
2578c2ecf20Sopenharmony_ci	if (ret < 0)
2588c2ecf20Sopenharmony_ci		return ret;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	return count;
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(enable_sensor);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_cistatic struct attribute *enable_sensor_attrs[] = {
2658c2ecf20Sopenharmony_ci	&dev_attr_enable_sensor.attr,
2668c2ecf20Sopenharmony_ci	NULL,
2678c2ecf20Sopenharmony_ci};
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_cistatic const struct attribute_group enable_sensor_attr_group = {
2708c2ecf20Sopenharmony_ci	.attrs = enable_sensor_attrs,
2718c2ecf20Sopenharmony_ci};
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_cistatic ssize_t show_value(struct device *dev, struct device_attribute *attr,
2748c2ecf20Sopenharmony_ci			  char *buf)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	struct hid_sensor_custom *sensor_inst = dev_get_drvdata(dev);
2778c2ecf20Sopenharmony_ci	struct hid_sensor_hub_attribute_info *attribute;
2788c2ecf20Sopenharmony_ci	int index, usage, field_index;
2798c2ecf20Sopenharmony_ci	char name[HID_CUSTOM_NAME_LENGTH];
2808c2ecf20Sopenharmony_ci	bool feature = false;
2818c2ecf20Sopenharmony_ci	bool input = false;
2828c2ecf20Sopenharmony_ci	int value = 0;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	if (sscanf(attr->attr.name, "feature-%x-%x-%s", &index, &usage,
2858c2ecf20Sopenharmony_ci		   name) == 3) {
2868c2ecf20Sopenharmony_ci		feature = true;
2878c2ecf20Sopenharmony_ci		field_index = index + sensor_inst->input_field_count;
2888c2ecf20Sopenharmony_ci	} else if (sscanf(attr->attr.name, "input-%x-%x-%s", &index, &usage,
2898c2ecf20Sopenharmony_ci		   name) == 3) {
2908c2ecf20Sopenharmony_ci		input = true;
2918c2ecf20Sopenharmony_ci		field_index = index;
2928c2ecf20Sopenharmony_ci	} else
2938c2ecf20Sopenharmony_ci		return -EINVAL;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	if (!strncmp(name, "value", strlen("value"))) {
2968c2ecf20Sopenharmony_ci		u32 report_id;
2978c2ecf20Sopenharmony_ci		int ret;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci		attribute = &sensor_inst->fields[field_index].attribute;
3008c2ecf20Sopenharmony_ci		report_id = attribute->report_id;
3018c2ecf20Sopenharmony_ci		if (feature) {
3028c2ecf20Sopenharmony_ci			u8 values[HID_CUSTOM_MAX_FEATURE_BYTES];
3038c2ecf20Sopenharmony_ci			int len = 0;
3048c2ecf20Sopenharmony_ci			u64 value = 0;
3058c2ecf20Sopenharmony_ci			int i = 0;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci			ret = sensor_hub_get_feature(sensor_inst->hsdev,
3088c2ecf20Sopenharmony_ci						     report_id,
3098c2ecf20Sopenharmony_ci						     index,
3108c2ecf20Sopenharmony_ci						     sizeof(values), values);
3118c2ecf20Sopenharmony_ci			if (ret < 0)
3128c2ecf20Sopenharmony_ci				return ret;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci			while (i < ret) {
3158c2ecf20Sopenharmony_ci				if (i + attribute->size > ret) {
3168c2ecf20Sopenharmony_ci					len += scnprintf(&buf[len],
3178c2ecf20Sopenharmony_ci							PAGE_SIZE - len,
3188c2ecf20Sopenharmony_ci							"%d ", values[i]);
3198c2ecf20Sopenharmony_ci					break;
3208c2ecf20Sopenharmony_ci				}
3218c2ecf20Sopenharmony_ci				switch (attribute->size) {
3228c2ecf20Sopenharmony_ci				case 2:
3238c2ecf20Sopenharmony_ci					value = (u64) *(u16 *)&values[i];
3248c2ecf20Sopenharmony_ci					i += attribute->size;
3258c2ecf20Sopenharmony_ci					break;
3268c2ecf20Sopenharmony_ci				case 4:
3278c2ecf20Sopenharmony_ci					value = (u64) *(u32 *)&values[i];
3288c2ecf20Sopenharmony_ci					i += attribute->size;
3298c2ecf20Sopenharmony_ci					break;
3308c2ecf20Sopenharmony_ci				case 8:
3318c2ecf20Sopenharmony_ci					value = *(u64 *)&values[i];
3328c2ecf20Sopenharmony_ci					i += attribute->size;
3338c2ecf20Sopenharmony_ci					break;
3348c2ecf20Sopenharmony_ci				default:
3358c2ecf20Sopenharmony_ci					value = (u64) values[i];
3368c2ecf20Sopenharmony_ci					++i;
3378c2ecf20Sopenharmony_ci					break;
3388c2ecf20Sopenharmony_ci				}
3398c2ecf20Sopenharmony_ci				len += scnprintf(&buf[len], PAGE_SIZE - len,
3408c2ecf20Sopenharmony_ci						"%lld ", value);
3418c2ecf20Sopenharmony_ci			}
3428c2ecf20Sopenharmony_ci			len += scnprintf(&buf[len], PAGE_SIZE - len, "\n");
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci			return len;
3458c2ecf20Sopenharmony_ci		} else if (input)
3468c2ecf20Sopenharmony_ci			value = sensor_hub_input_attr_get_raw_value(
3478c2ecf20Sopenharmony_ci						sensor_inst->hsdev,
3488c2ecf20Sopenharmony_ci						sensor_inst->hsdev->usage,
3498c2ecf20Sopenharmony_ci						usage, report_id,
3508c2ecf20Sopenharmony_ci						SENSOR_HUB_SYNC, false);
3518c2ecf20Sopenharmony_ci	} else if (!strncmp(name, "units", strlen("units")))
3528c2ecf20Sopenharmony_ci		value = sensor_inst->fields[field_index].attribute.units;
3538c2ecf20Sopenharmony_ci	else if (!strncmp(name, "unit-expo", strlen("unit-expo")))
3548c2ecf20Sopenharmony_ci		value = sensor_inst->fields[field_index].attribute.unit_expo;
3558c2ecf20Sopenharmony_ci	else if (!strncmp(name, "size", strlen("size")))
3568c2ecf20Sopenharmony_ci		value = sensor_inst->fields[field_index].attribute.size;
3578c2ecf20Sopenharmony_ci	else if (!strncmp(name, "minimum", strlen("minimum")))
3588c2ecf20Sopenharmony_ci		value = sensor_inst->fields[field_index].attribute.
3598c2ecf20Sopenharmony_ci							logical_minimum;
3608c2ecf20Sopenharmony_ci	else if (!strncmp(name, "maximum", strlen("maximum")))
3618c2ecf20Sopenharmony_ci		value = sensor_inst->fields[field_index].attribute.
3628c2ecf20Sopenharmony_ci							logical_maximum;
3638c2ecf20Sopenharmony_ci	else if (!strncmp(name, "name", strlen("name"))) {
3648c2ecf20Sopenharmony_ci		struct hid_custom_usage_desc *usage_desc;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci		usage_desc = bsearch(&usage, hid_custom_usage_desc_table,
3678c2ecf20Sopenharmony_ci				     ARRAY_SIZE(hid_custom_usage_desc_table),
3688c2ecf20Sopenharmony_ci				     sizeof(struct hid_custom_usage_desc),
3698c2ecf20Sopenharmony_ci				     usage_id_cmp);
3708c2ecf20Sopenharmony_ci		if (usage_desc)
3718c2ecf20Sopenharmony_ci			return snprintf(buf, PAGE_SIZE, "%s\n",
3728c2ecf20Sopenharmony_ci					usage_desc->desc);
3738c2ecf20Sopenharmony_ci		else
3748c2ecf20Sopenharmony_ci			return sprintf(buf, "not-specified\n");
3758c2ecf20Sopenharmony_ci	 } else
3768c2ecf20Sopenharmony_ci		return -EINVAL;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", value);
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_cistatic ssize_t store_value(struct device *dev, struct device_attribute *attr,
3828c2ecf20Sopenharmony_ci			   const char *buf, size_t count)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	struct hid_sensor_custom *sensor_inst = dev_get_drvdata(dev);
3858c2ecf20Sopenharmony_ci	int index, field_index, usage;
3868c2ecf20Sopenharmony_ci	char name[HID_CUSTOM_NAME_LENGTH];
3878c2ecf20Sopenharmony_ci	int value;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	if (sscanf(attr->attr.name, "feature-%x-%x-%s", &index, &usage,
3908c2ecf20Sopenharmony_ci		   name) == 3) {
3918c2ecf20Sopenharmony_ci		field_index = index + sensor_inst->input_field_count;
3928c2ecf20Sopenharmony_ci	} else
3938c2ecf20Sopenharmony_ci		return -EINVAL;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	if (!strncmp(name, "value", strlen("value"))) {
3968c2ecf20Sopenharmony_ci		u32 report_id;
3978c2ecf20Sopenharmony_ci		int ret;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci		if (kstrtoint(buf, 0, &value) != 0)
4008c2ecf20Sopenharmony_ci			return -EINVAL;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci		report_id = sensor_inst->fields[field_index].attribute.
4038c2ecf20Sopenharmony_ci								report_id;
4048c2ecf20Sopenharmony_ci		ret = sensor_hub_set_feature(sensor_inst->hsdev, report_id,
4058c2ecf20Sopenharmony_ci					     index, sizeof(value), &value);
4068c2ecf20Sopenharmony_ci	} else
4078c2ecf20Sopenharmony_ci		return -EINVAL;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	return count;
4108c2ecf20Sopenharmony_ci}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_cistatic int hid_sensor_capture_sample(struct hid_sensor_hub_device *hsdev,
4138c2ecf20Sopenharmony_ci				  unsigned usage_id, size_t raw_len,
4148c2ecf20Sopenharmony_ci				  char *raw_data, void *priv)
4158c2ecf20Sopenharmony_ci{
4168c2ecf20Sopenharmony_ci	struct hid_sensor_custom *sensor_inst = platform_get_drvdata(priv);
4178c2ecf20Sopenharmony_ci	struct hid_sensor_sample header;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	/* If any error occurs in a sample, rest of the fields are ignored */
4208c2ecf20Sopenharmony_ci	if (sensor_inst->input_skip_sample) {
4218c2ecf20Sopenharmony_ci		hid_err(sensor_inst->hsdev->hdev, "Skipped remaining data\n");
4228c2ecf20Sopenharmony_ci		return 0;
4238c2ecf20Sopenharmony_ci	}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	hid_dbg(sensor_inst->hsdev->hdev, "%s received %d of %d\n", __func__,
4268c2ecf20Sopenharmony_ci		(int) (sensor_inst->input_report_recd_size + raw_len),
4278c2ecf20Sopenharmony_ci		sensor_inst->input_report_size);
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	if (!test_bit(0, &sensor_inst->misc_opened))
4308c2ecf20Sopenharmony_ci		return 0;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	if (!sensor_inst->input_report_recd_size) {
4338c2ecf20Sopenharmony_ci		int required_size = sizeof(struct hid_sensor_sample) +
4348c2ecf20Sopenharmony_ci						sensor_inst->input_report_size;
4358c2ecf20Sopenharmony_ci		header.usage_id = hsdev->usage;
4368c2ecf20Sopenharmony_ci		header.raw_len = sensor_inst->input_report_size;
4378c2ecf20Sopenharmony_ci		header.timestamp = ktime_get_real_ns();
4388c2ecf20Sopenharmony_ci		if (kfifo_avail(&sensor_inst->data_fifo) >= required_size) {
4398c2ecf20Sopenharmony_ci			kfifo_in(&sensor_inst->data_fifo,
4408c2ecf20Sopenharmony_ci				 (unsigned char *)&header,
4418c2ecf20Sopenharmony_ci				 sizeof(header));
4428c2ecf20Sopenharmony_ci		} else
4438c2ecf20Sopenharmony_ci			sensor_inst->input_skip_sample = true;
4448c2ecf20Sopenharmony_ci	}
4458c2ecf20Sopenharmony_ci	if (kfifo_avail(&sensor_inst->data_fifo) >= raw_len)
4468c2ecf20Sopenharmony_ci		kfifo_in(&sensor_inst->data_fifo, (unsigned char *)raw_data,
4478c2ecf20Sopenharmony_ci			 raw_len);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	sensor_inst->input_report_recd_size += raw_len;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	return 0;
4528c2ecf20Sopenharmony_ci}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_cistatic int hid_sensor_send_event(struct hid_sensor_hub_device *hsdev,
4558c2ecf20Sopenharmony_ci				 unsigned usage_id, void *priv)
4568c2ecf20Sopenharmony_ci{
4578c2ecf20Sopenharmony_ci	struct hid_sensor_custom *sensor_inst = platform_get_drvdata(priv);
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	if (!test_bit(0, &sensor_inst->misc_opened))
4608c2ecf20Sopenharmony_ci		return 0;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	sensor_inst->input_report_recd_size = 0;
4638c2ecf20Sopenharmony_ci	sensor_inst->input_skip_sample = false;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	wake_up(&sensor_inst->wait);
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	return 0;
4688c2ecf20Sopenharmony_ci}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_cistatic int hid_sensor_custom_add_field(struct hid_sensor_custom *sensor_inst,
4718c2ecf20Sopenharmony_ci				       int index, int report_type,
4728c2ecf20Sopenharmony_ci				       struct hid_report *report,
4738c2ecf20Sopenharmony_ci				       struct hid_field *field)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	struct hid_sensor_custom_field *sensor_field;
4768c2ecf20Sopenharmony_ci	void *fields;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	fields = krealloc(sensor_inst->fields,
4798c2ecf20Sopenharmony_ci			  (sensor_inst->sensor_field_count + 1) *
4808c2ecf20Sopenharmony_ci			   sizeof(struct hid_sensor_custom_field), GFP_KERNEL);
4818c2ecf20Sopenharmony_ci	if (!fields) {
4828c2ecf20Sopenharmony_ci		kfree(sensor_inst->fields);
4838c2ecf20Sopenharmony_ci		return -ENOMEM;
4848c2ecf20Sopenharmony_ci	}
4858c2ecf20Sopenharmony_ci	sensor_inst->fields = fields;
4868c2ecf20Sopenharmony_ci	sensor_field = &sensor_inst->fields[sensor_inst->sensor_field_count];
4878c2ecf20Sopenharmony_ci	sensor_field->attribute.usage_id = sensor_inst->hsdev->usage;
4888c2ecf20Sopenharmony_ci	if (field->logical)
4898c2ecf20Sopenharmony_ci		sensor_field->attribute.attrib_id = field->logical;
4908c2ecf20Sopenharmony_ci	else
4918c2ecf20Sopenharmony_ci		sensor_field->attribute.attrib_id = field->usage[0].hid;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	sensor_field->attribute.index = index;
4948c2ecf20Sopenharmony_ci	sensor_field->attribute.report_id = report->id;
4958c2ecf20Sopenharmony_ci	sensor_field->attribute.units = field->unit;
4968c2ecf20Sopenharmony_ci	sensor_field->attribute.unit_expo = field->unit_exponent;
4978c2ecf20Sopenharmony_ci	sensor_field->attribute.size = (field->report_size / 8);
4988c2ecf20Sopenharmony_ci	sensor_field->attribute.logical_minimum = field->logical_minimum;
4998c2ecf20Sopenharmony_ci	sensor_field->attribute.logical_maximum = field->logical_maximum;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	if (report_type == HID_FEATURE_REPORT)
5028c2ecf20Sopenharmony_ci		snprintf(sensor_field->group_name,
5038c2ecf20Sopenharmony_ci			 sizeof(sensor_field->group_name), "feature-%x-%x",
5048c2ecf20Sopenharmony_ci			 sensor_field->attribute.index,
5058c2ecf20Sopenharmony_ci			 sensor_field->attribute.attrib_id);
5068c2ecf20Sopenharmony_ci	else if (report_type == HID_INPUT_REPORT) {
5078c2ecf20Sopenharmony_ci		snprintf(sensor_field->group_name,
5088c2ecf20Sopenharmony_ci			 sizeof(sensor_field->group_name),
5098c2ecf20Sopenharmony_ci			 "input-%x-%x", sensor_field->attribute.index,
5108c2ecf20Sopenharmony_ci			 sensor_field->attribute.attrib_id);
5118c2ecf20Sopenharmony_ci		sensor_inst->input_field_count++;
5128c2ecf20Sopenharmony_ci		sensor_inst->input_report_size += (field->report_size *
5138c2ecf20Sopenharmony_ci						   field->report_count) / 8;
5148c2ecf20Sopenharmony_ci	}
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	memset(&sensor_field->hid_custom_attribute_group, 0,
5178c2ecf20Sopenharmony_ci	       sizeof(struct attribute_group));
5188c2ecf20Sopenharmony_ci	sensor_inst->sensor_field_count++;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	return 0;
5218c2ecf20Sopenharmony_ci}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_cistatic int hid_sensor_custom_add_fields(struct hid_sensor_custom *sensor_inst,
5248c2ecf20Sopenharmony_ci					struct hid_report_enum *report_enum,
5258c2ecf20Sopenharmony_ci					int report_type)
5268c2ecf20Sopenharmony_ci{
5278c2ecf20Sopenharmony_ci	int i;
5288c2ecf20Sopenharmony_ci	int ret;
5298c2ecf20Sopenharmony_ci	struct hid_report *report;
5308c2ecf20Sopenharmony_ci	struct hid_field *field;
5318c2ecf20Sopenharmony_ci	struct hid_sensor_hub_device *hsdev = sensor_inst->hsdev;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	list_for_each_entry(report, &report_enum->report_list, list) {
5348c2ecf20Sopenharmony_ci		for (i = 0; i < report->maxfield; ++i) {
5358c2ecf20Sopenharmony_ci			field = report->field[i];
5368c2ecf20Sopenharmony_ci			if (field->maxusage &&
5378c2ecf20Sopenharmony_ci			    ((field->usage[0].collection_index >=
5388c2ecf20Sopenharmony_ci			      hsdev->start_collection_index) &&
5398c2ecf20Sopenharmony_ci			      (field->usage[0].collection_index <
5408c2ecf20Sopenharmony_ci			       hsdev->end_collection_index))) {
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci				ret = hid_sensor_custom_add_field(sensor_inst,
5438c2ecf20Sopenharmony_ci								  i,
5448c2ecf20Sopenharmony_ci								  report_type,
5458c2ecf20Sopenharmony_ci								  report,
5468c2ecf20Sopenharmony_ci								  field);
5478c2ecf20Sopenharmony_ci				if (ret)
5488c2ecf20Sopenharmony_ci					return ret;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci			}
5518c2ecf20Sopenharmony_ci		}
5528c2ecf20Sopenharmony_ci	}
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	return 0;
5558c2ecf20Sopenharmony_ci}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_cistatic int hid_sensor_custom_add_attributes(struct hid_sensor_custom
5588c2ecf20Sopenharmony_ci								*sensor_inst)
5598c2ecf20Sopenharmony_ci{
5608c2ecf20Sopenharmony_ci	struct hid_sensor_hub_device *hsdev = sensor_inst->hsdev;
5618c2ecf20Sopenharmony_ci	struct hid_device *hdev = hsdev->hdev;
5628c2ecf20Sopenharmony_ci	int ret = -1;
5638c2ecf20Sopenharmony_ci	int i, j;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	for (j = 0; j < HID_REPORT_TYPES; ++j) {
5668c2ecf20Sopenharmony_ci		if (j == HID_OUTPUT_REPORT)
5678c2ecf20Sopenharmony_ci			continue;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci		ret = hid_sensor_custom_add_fields(sensor_inst,
5708c2ecf20Sopenharmony_ci						   &hdev->report_enum[j], j);
5718c2ecf20Sopenharmony_ci		if (ret)
5728c2ecf20Sopenharmony_ci			return ret;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	/* Create sysfs attributes */
5778c2ecf20Sopenharmony_ci	for (i = 0; i < sensor_inst->sensor_field_count; ++i) {
5788c2ecf20Sopenharmony_ci		j = 0;
5798c2ecf20Sopenharmony_ci		while (j < HID_CUSTOM_TOTAL_ATTRS &&
5808c2ecf20Sopenharmony_ci		       hid_custom_attrs[j].name) {
5818c2ecf20Sopenharmony_ci			struct device_attribute *device_attr;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci			device_attr = &sensor_inst->fields[i].sd_attrs[j];
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci			snprintf((char *)&sensor_inst->fields[i].attr_name[j],
5868c2ecf20Sopenharmony_ci				 HID_CUSTOM_NAME_LENGTH, "%s-%s",
5878c2ecf20Sopenharmony_ci				 sensor_inst->fields[i].group_name,
5888c2ecf20Sopenharmony_ci				 hid_custom_attrs[j].name);
5898c2ecf20Sopenharmony_ci			sysfs_attr_init(&device_attr->attr);
5908c2ecf20Sopenharmony_ci			device_attr->attr.name =
5918c2ecf20Sopenharmony_ci				(char *)&sensor_inst->fields[i].attr_name[j];
5928c2ecf20Sopenharmony_ci			device_attr->attr.mode = hid_custom_attrs[j].mode;
5938c2ecf20Sopenharmony_ci			device_attr->show = show_value;
5948c2ecf20Sopenharmony_ci			if (hid_custom_attrs[j].mode & S_IWUSR)
5958c2ecf20Sopenharmony_ci				device_attr->store = store_value;
5968c2ecf20Sopenharmony_ci			sensor_inst->fields[i].attrs[j] = &device_attr->attr;
5978c2ecf20Sopenharmony_ci			++j;
5988c2ecf20Sopenharmony_ci		}
5998c2ecf20Sopenharmony_ci		sensor_inst->fields[i].attrs[j] = NULL;
6008c2ecf20Sopenharmony_ci		sensor_inst->fields[i].hid_custom_attribute_group.attrs =
6018c2ecf20Sopenharmony_ci						sensor_inst->fields[i].attrs;
6028c2ecf20Sopenharmony_ci		sensor_inst->fields[i].hid_custom_attribute_group.name =
6038c2ecf20Sopenharmony_ci					sensor_inst->fields[i].group_name;
6048c2ecf20Sopenharmony_ci		ret = sysfs_create_group(&sensor_inst->pdev->dev.kobj,
6058c2ecf20Sopenharmony_ci					 &sensor_inst->fields[i].
6068c2ecf20Sopenharmony_ci					 hid_custom_attribute_group);
6078c2ecf20Sopenharmony_ci		if (ret)
6088c2ecf20Sopenharmony_ci			break;
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci		/* For power or report field store indexes */
6118c2ecf20Sopenharmony_ci		if (sensor_inst->fields[i].attribute.attrib_id ==
6128c2ecf20Sopenharmony_ci					HID_USAGE_SENSOR_PROY_POWER_STATE)
6138c2ecf20Sopenharmony_ci			sensor_inst->power_state = &sensor_inst->fields[i];
6148c2ecf20Sopenharmony_ci		else if (sensor_inst->fields[i].attribute.attrib_id ==
6158c2ecf20Sopenharmony_ci					HID_USAGE_SENSOR_PROP_REPORT_STATE)
6168c2ecf20Sopenharmony_ci			sensor_inst->report_state = &sensor_inst->fields[i];
6178c2ecf20Sopenharmony_ci	}
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	return ret;
6208c2ecf20Sopenharmony_ci}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_cistatic void hid_sensor_custom_remove_attributes(struct hid_sensor_custom *
6238c2ecf20Sopenharmony_ci								sensor_inst)
6248c2ecf20Sopenharmony_ci{
6258c2ecf20Sopenharmony_ci	int i;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	for (i = 0; i < sensor_inst->sensor_field_count; ++i)
6288c2ecf20Sopenharmony_ci		sysfs_remove_group(&sensor_inst->pdev->dev.kobj,
6298c2ecf20Sopenharmony_ci				   &sensor_inst->fields[i].
6308c2ecf20Sopenharmony_ci				   hid_custom_attribute_group);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	kfree(sensor_inst->fields);
6338c2ecf20Sopenharmony_ci}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_cistatic ssize_t hid_sensor_custom_read(struct file *file, char __user *buf,
6368c2ecf20Sopenharmony_ci				      size_t count, loff_t *f_ps)
6378c2ecf20Sopenharmony_ci{
6388c2ecf20Sopenharmony_ci	struct hid_sensor_custom *sensor_inst;
6398c2ecf20Sopenharmony_ci	unsigned int copied;
6408c2ecf20Sopenharmony_ci	int ret;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	sensor_inst = container_of(file->private_data,
6438c2ecf20Sopenharmony_ci				   struct hid_sensor_custom, custom_dev);
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	if (count < sizeof(struct hid_sensor_sample))
6468c2ecf20Sopenharmony_ci		return -EINVAL;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	do {
6498c2ecf20Sopenharmony_ci		if (kfifo_is_empty(&sensor_inst->data_fifo)) {
6508c2ecf20Sopenharmony_ci			if (file->f_flags & O_NONBLOCK)
6518c2ecf20Sopenharmony_ci				return -EAGAIN;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci			ret = wait_event_interruptible(sensor_inst->wait,
6548c2ecf20Sopenharmony_ci				!kfifo_is_empty(&sensor_inst->data_fifo));
6558c2ecf20Sopenharmony_ci			if (ret)
6568c2ecf20Sopenharmony_ci				return ret;
6578c2ecf20Sopenharmony_ci		}
6588c2ecf20Sopenharmony_ci		ret = kfifo_to_user(&sensor_inst->data_fifo, buf, count,
6598c2ecf20Sopenharmony_ci				    &copied);
6608c2ecf20Sopenharmony_ci		if (ret)
6618c2ecf20Sopenharmony_ci			return ret;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	} while (copied == 0);
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	return copied;
6668c2ecf20Sopenharmony_ci}
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_cistatic int hid_sensor_custom_release(struct inode *inode, struct file *file)
6698c2ecf20Sopenharmony_ci{
6708c2ecf20Sopenharmony_ci	struct hid_sensor_custom *sensor_inst;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	sensor_inst = container_of(file->private_data,
6738c2ecf20Sopenharmony_ci				   struct hid_sensor_custom, custom_dev);
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	clear_bit(0, &sensor_inst->misc_opened);
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	return 0;
6788c2ecf20Sopenharmony_ci}
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_cistatic int hid_sensor_custom_open(struct inode *inode, struct file *file)
6818c2ecf20Sopenharmony_ci{
6828c2ecf20Sopenharmony_ci	struct hid_sensor_custom *sensor_inst;
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	sensor_inst = container_of(file->private_data,
6858c2ecf20Sopenharmony_ci				   struct hid_sensor_custom, custom_dev);
6868c2ecf20Sopenharmony_ci	/* We essentially have single reader and writer */
6878c2ecf20Sopenharmony_ci	if (test_and_set_bit(0, &sensor_inst->misc_opened))
6888c2ecf20Sopenharmony_ci		return -EBUSY;
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	return stream_open(inode, file);
6918c2ecf20Sopenharmony_ci}
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_cistatic __poll_t hid_sensor_custom_poll(struct file *file,
6948c2ecf20Sopenharmony_ci					   struct poll_table_struct *wait)
6958c2ecf20Sopenharmony_ci{
6968c2ecf20Sopenharmony_ci	struct hid_sensor_custom *sensor_inst;
6978c2ecf20Sopenharmony_ci	__poll_t mask = 0;
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	sensor_inst = container_of(file->private_data,
7008c2ecf20Sopenharmony_ci				   struct hid_sensor_custom, custom_dev);
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	poll_wait(file, &sensor_inst->wait, wait);
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	if (!kfifo_is_empty(&sensor_inst->data_fifo))
7058c2ecf20Sopenharmony_ci		mask = EPOLLIN | EPOLLRDNORM;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	return mask;
7088c2ecf20Sopenharmony_ci}
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_cistatic const struct file_operations hid_sensor_custom_fops = {
7118c2ecf20Sopenharmony_ci	.open =  hid_sensor_custom_open,
7128c2ecf20Sopenharmony_ci	.read =  hid_sensor_custom_read,
7138c2ecf20Sopenharmony_ci	.release = hid_sensor_custom_release,
7148c2ecf20Sopenharmony_ci	.poll = hid_sensor_custom_poll,
7158c2ecf20Sopenharmony_ci	.llseek = noop_llseek,
7168c2ecf20Sopenharmony_ci};
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_cistatic int hid_sensor_custom_dev_if_add(struct hid_sensor_custom *sensor_inst)
7198c2ecf20Sopenharmony_ci{
7208c2ecf20Sopenharmony_ci	int ret;
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	ret = kfifo_alloc(&sensor_inst->data_fifo, HID_CUSTOM_FIFO_SIZE,
7238c2ecf20Sopenharmony_ci			  GFP_KERNEL);
7248c2ecf20Sopenharmony_ci	if (ret)
7258c2ecf20Sopenharmony_ci		return ret;
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	init_waitqueue_head(&sensor_inst->wait);
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	sensor_inst->custom_dev.minor = MISC_DYNAMIC_MINOR;
7308c2ecf20Sopenharmony_ci	sensor_inst->custom_dev.name = dev_name(&sensor_inst->pdev->dev);
7318c2ecf20Sopenharmony_ci	sensor_inst->custom_dev.fops = &hid_sensor_custom_fops,
7328c2ecf20Sopenharmony_ci	ret = misc_register(&sensor_inst->custom_dev);
7338c2ecf20Sopenharmony_ci	if (ret) {
7348c2ecf20Sopenharmony_ci		kfifo_free(&sensor_inst->data_fifo);
7358c2ecf20Sopenharmony_ci		return ret;
7368c2ecf20Sopenharmony_ci	}
7378c2ecf20Sopenharmony_ci	return 0;
7388c2ecf20Sopenharmony_ci}
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_cistatic void hid_sensor_custom_dev_if_remove(struct hid_sensor_custom
7418c2ecf20Sopenharmony_ci								*sensor_inst)
7428c2ecf20Sopenharmony_ci{
7438c2ecf20Sopenharmony_ci	wake_up(&sensor_inst->wait);
7448c2ecf20Sopenharmony_ci	misc_deregister(&sensor_inst->custom_dev);
7458c2ecf20Sopenharmony_ci	kfifo_free(&sensor_inst->data_fifo);
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_cistatic int hid_sensor_custom_probe(struct platform_device *pdev)
7508c2ecf20Sopenharmony_ci{
7518c2ecf20Sopenharmony_ci	struct hid_sensor_custom *sensor_inst;
7528c2ecf20Sopenharmony_ci	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
7538c2ecf20Sopenharmony_ci	int ret;
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	sensor_inst = devm_kzalloc(&pdev->dev, sizeof(*sensor_inst),
7568c2ecf20Sopenharmony_ci				   GFP_KERNEL);
7578c2ecf20Sopenharmony_ci	if (!sensor_inst)
7588c2ecf20Sopenharmony_ci		return -ENOMEM;
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	sensor_inst->callbacks.capture_sample = hid_sensor_capture_sample;
7618c2ecf20Sopenharmony_ci	sensor_inst->callbacks.send_event = hid_sensor_send_event;
7628c2ecf20Sopenharmony_ci	sensor_inst->callbacks.pdev = pdev;
7638c2ecf20Sopenharmony_ci	sensor_inst->hsdev = hsdev;
7648c2ecf20Sopenharmony_ci	sensor_inst->pdev = pdev;
7658c2ecf20Sopenharmony_ci	mutex_init(&sensor_inst->mutex);
7668c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, sensor_inst);
7678c2ecf20Sopenharmony_ci	ret = sensor_hub_register_callback(hsdev, hsdev->usage,
7688c2ecf20Sopenharmony_ci					   &sensor_inst->callbacks);
7698c2ecf20Sopenharmony_ci	if (ret < 0) {
7708c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "callback reg failed\n");
7718c2ecf20Sopenharmony_ci		return ret;
7728c2ecf20Sopenharmony_ci	}
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	ret = sysfs_create_group(&sensor_inst->pdev->dev.kobj,
7758c2ecf20Sopenharmony_ci				 &enable_sensor_attr_group);
7768c2ecf20Sopenharmony_ci	if (ret)
7778c2ecf20Sopenharmony_ci		goto err_remove_callback;
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	ret = hid_sensor_custom_add_attributes(sensor_inst);
7808c2ecf20Sopenharmony_ci	if (ret)
7818c2ecf20Sopenharmony_ci		goto err_remove_group;
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	ret = hid_sensor_custom_dev_if_add(sensor_inst);
7848c2ecf20Sopenharmony_ci	if (ret)
7858c2ecf20Sopenharmony_ci		goto err_remove_attributes;
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	return 0;
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_cierr_remove_attributes:
7908c2ecf20Sopenharmony_ci	hid_sensor_custom_remove_attributes(sensor_inst);
7918c2ecf20Sopenharmony_cierr_remove_group:
7928c2ecf20Sopenharmony_ci	sysfs_remove_group(&sensor_inst->pdev->dev.kobj,
7938c2ecf20Sopenharmony_ci			   &enable_sensor_attr_group);
7948c2ecf20Sopenharmony_cierr_remove_callback:
7958c2ecf20Sopenharmony_ci	sensor_hub_remove_callback(hsdev, hsdev->usage);
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	return ret;
7988c2ecf20Sopenharmony_ci}
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_cistatic int hid_sensor_custom_remove(struct platform_device *pdev)
8018c2ecf20Sopenharmony_ci{
8028c2ecf20Sopenharmony_ci	struct hid_sensor_custom *sensor_inst = platform_get_drvdata(pdev);
8038c2ecf20Sopenharmony_ci	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	hid_sensor_custom_dev_if_remove(sensor_inst);
8068c2ecf20Sopenharmony_ci	hid_sensor_custom_remove_attributes(sensor_inst);
8078c2ecf20Sopenharmony_ci	sysfs_remove_group(&sensor_inst->pdev->dev.kobj,
8088c2ecf20Sopenharmony_ci			   &enable_sensor_attr_group);
8098c2ecf20Sopenharmony_ci	sensor_hub_remove_callback(hsdev, hsdev->usage);
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	return 0;
8128c2ecf20Sopenharmony_ci}
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_cistatic const struct platform_device_id hid_sensor_custom_ids[] = {
8158c2ecf20Sopenharmony_ci	{
8168c2ecf20Sopenharmony_ci		.name = "HID-SENSOR-2000e1",
8178c2ecf20Sopenharmony_ci	},
8188c2ecf20Sopenharmony_ci	{
8198c2ecf20Sopenharmony_ci		.name = "HID-SENSOR-2000e2",
8208c2ecf20Sopenharmony_ci	},
8218c2ecf20Sopenharmony_ci	{ /* sentinel */ }
8228c2ecf20Sopenharmony_ci};
8238c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(platform, hid_sensor_custom_ids);
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_cistatic struct platform_driver hid_sensor_custom_platform_driver = {
8268c2ecf20Sopenharmony_ci	.id_table = hid_sensor_custom_ids,
8278c2ecf20Sopenharmony_ci	.driver = {
8288c2ecf20Sopenharmony_ci		.name	= KBUILD_MODNAME,
8298c2ecf20Sopenharmony_ci	},
8308c2ecf20Sopenharmony_ci	.probe		= hid_sensor_custom_probe,
8318c2ecf20Sopenharmony_ci	.remove		= hid_sensor_custom_remove,
8328c2ecf20Sopenharmony_ci};
8338c2ecf20Sopenharmony_cimodule_platform_driver(hid_sensor_custom_platform_driver);
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("HID Sensor Custom and Generic sensor Driver");
8368c2ecf20Sopenharmony_ciMODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
8378c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
838