1082 lines · 29.2 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* * hid-sensor-custom.c * Copyright (c) 2015, Intel Corporation. */ #include <linux/ctype.h>#include <linux/dmi.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/miscdevice.h>#include <linux/kfifo.h>#include <linux/sched.h>#include <linux/wait.h>#include <linux/poll.h>#include <linux/bsearch.h>#include <linux/platform_device.h>#include <linux/hid-sensor-hub.h> #define HID_CUSTOM_NAME_LENGTH		64#define HID_CUSTOM_MAX_CORE_ATTRS	10#define HID_CUSTOM_TOTAL_ATTRS		(HID_CUSTOM_MAX_CORE_ATTRS + 1)#define HID_CUSTOM_FIFO_SIZE		4096#define HID_CUSTOM_MAX_FEATURE_BYTES	64#define HID_SENSOR_USAGE_LENGTH (4 + 1) struct hid_sensor_custom_field {	int report_id;	char group_name[HID_CUSTOM_NAME_LENGTH];	struct hid_sensor_hub_attribute_info attribute;	struct device_attribute sd_attrs[HID_CUSTOM_MAX_CORE_ATTRS];	char attr_name[HID_CUSTOM_TOTAL_ATTRS][HID_CUSTOM_NAME_LENGTH];	struct attribute *attrs[HID_CUSTOM_TOTAL_ATTRS];	struct attribute_group hid_custom_attribute_group;}; struct hid_sensor_custom {	struct mutex mutex;	struct platform_device *pdev;	struct hid_sensor_hub_device *hsdev;	struct hid_sensor_hub_callbacks callbacks;	int sensor_field_count;	struct hid_sensor_custom_field *fields;	int input_field_count;	int input_report_size;	int input_report_recd_size;	bool input_skip_sample;	bool enable;	struct hid_sensor_custom_field *power_state;	struct hid_sensor_custom_field *report_state;	struct miscdevice custom_dev;	struct kfifo data_fifo;	unsigned long misc_opened;	wait_queue_head_t wait;	struct platform_device *custom_pdev;}; /* Header for each sample to user space via dev interface */struct hid_sensor_sample {	u32 usage_id;	u64 timestamp;	u32 raw_len;} __packed; static struct attribute hid_custom_attrs[HID_CUSTOM_TOTAL_ATTRS] = {	{.name = "name", .mode = S_IRUGO},	{.name = "units", .mode = S_IRUGO},	{.name = "unit-expo", .mode = S_IRUGO},	{.name = "minimum", .mode = S_IRUGO},	{.name = "maximum", .mode = S_IRUGO},	{.name = "size", .mode = S_IRUGO},	{.name = "value", .mode = S_IWUSR | S_IRUGO},	{.name = NULL}}; static const struct hid_custom_usage_desc {	int usage_id;	char *desc;} hid_custom_usage_desc_table[] = {	{0x200201,	"event-sensor-state"},	{0x200202,	"event-sensor-event"},	{0x200301,	"property-friendly-name"},	{0x200302,	"property-persistent-unique-id"},	{0x200303,	"property-sensor-status"},	{0x200304,	"property-min-report-interval"},	{0x200305,	"property-sensor-manufacturer"},	{0x200306,	"property-sensor-model"},	{0x200307,	"property-sensor-serial-number"},	{0x200308,	"property-sensor-description"},	{0x200309,	"property-sensor-connection-type"},	{0x20030A,	"property-sensor-device-path"},	{0x20030B,	"property-hardware-revision"},	{0x20030C,	"property-firmware-version"},	{0x20030D,	"property-release-date"},	{0x20030E,	"property-report-interval"},	{0x20030F,	"property-change-sensitivity-absolute"},	{0x200310,	"property-change-sensitivity-percent-range"},	{0x200311,	"property-change-sensitivity-percent-relative"},	{0x200312,	"property-accuracy"},	{0x200313,	"property-resolution"},	{0x200314,	"property-maximum"},	{0x200315,	"property-minimum"},	{0x200316,	"property-reporting-state"},	{0x200317,	"property-sampling-rate"},	{0x200318,	"property-response-curve"},	{0x200319,	"property-power-state"},	{0x200540,	"data-field-custom"},	{0x200541,	"data-field-custom-usage"},	{0x200542,	"data-field-custom-boolean-array"},	{0x200543,	"data-field-custom-value"},	{0x200544,	"data-field-custom-value_1"},	{0x200545,	"data-field-custom-value_2"},	{0x200546,	"data-field-custom-value_3"},	{0x200547,	"data-field-custom-value_4"},	{0x200548,	"data-field-custom-value_5"},	{0x200549,	"data-field-custom-value_6"},	{0x20054A,	"data-field-custom-value_7"},	{0x20054B,	"data-field-custom-value_8"},	{0x20054C,	"data-field-custom-value_9"},	{0x20054D,	"data-field-custom-value_10"},	{0x20054E,	"data-field-custom-value_11"},	{0x20054F,	"data-field-custom-value_12"},	{0x200550,	"data-field-custom-value_13"},	{0x200551,	"data-field-custom-value_14"},	{0x200552,	"data-field-custom-value_15"},	{0x200553,	"data-field-custom-value_16"},	{0x200554,	"data-field-custom-value_17"},	{0x200555,	"data-field-custom-value_18"},	{0x200556,	"data-field-custom-value_19"},	{0x200557,	"data-field-custom-value_20"},	{0x200558,	"data-field-custom-value_21"},	{0x200559,	"data-field-custom-value_22"},	{0x20055A,	"data-field-custom-value_23"},	{0x20055B,	"data-field-custom-value_24"},	{0x20055C,	"data-field-custom-value_25"},	{0x20055D,	"data-field-custom-value_26"},	{0x20055E,	"data-field-custom-value_27"},	{0x20055F,	"data-field-custom-value_28"},}; static int usage_id_cmp(const void *p1, const void *p2){	if (*(int *)p1 < *(int *)p2)		return -1; 	if (*(int *)p1 > *(int *)p2)		return 1; 	return 0;} static ssize_t enable_sensor_show(struct device *dev,				  struct device_attribute *attr, char *buf){	struct hid_sensor_custom *sensor_inst = dev_get_drvdata(dev); 	return sysfs_emit(buf, "%d\n", sensor_inst->enable);} static int set_power_report_state(struct hid_sensor_custom *sensor_inst,				  bool state){	int power_val = -1;	int report_val = -1;	u32 power_state_usage_id;	u32 report_state_usage_id;	int ret; 	/*	 * It is possible that the power/report state ids are not present.	 * In this case this function will return success. But if the	 * ids are present, then it will return error if set fails.	 */	if (state) {		power_state_usage_id =			HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM;		report_state_usage_id =			HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM;	} else {		power_state_usage_id =			HID_USAGE_SENSOR_PROP_POWER_STATE_D4_POWER_OFF_ENUM;		report_state_usage_id =			HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM;	} 	if (sensor_inst->power_state)		power_val = hid_sensor_get_usage_index(sensor_inst->hsdev,				sensor_inst->power_state->attribute.report_id,				sensor_inst->power_state->attribute.index,				power_state_usage_id);	if (sensor_inst->report_state)		report_val = hid_sensor_get_usage_index(sensor_inst->hsdev,				sensor_inst->report_state->attribute.report_id,				sensor_inst->report_state->attribute.index,				report_state_usage_id); 	if (power_val >= 0) {		power_val +=			sensor_inst->power_state->attribute.logical_minimum;		ret = sensor_hub_set_feature(sensor_inst->hsdev,				sensor_inst->power_state->attribute.report_id,				sensor_inst->power_state->attribute.index,				sizeof(power_val),				&power_val);		if (ret) {			hid_err(sensor_inst->hsdev->hdev,				"Set power state failed\n");			return ret;		}	} 	if (report_val >= 0) {		report_val +=			sensor_inst->report_state->attribute.logical_minimum;		ret = sensor_hub_set_feature(sensor_inst->hsdev,				sensor_inst->report_state->attribute.report_id,				sensor_inst->report_state->attribute.index,				sizeof(report_val),				&report_val);		if (ret) {			hid_err(sensor_inst->hsdev->hdev,				"Set report state failed\n");			return ret;		}	} 	return 0;} static ssize_t enable_sensor_store(struct device *dev,				   struct device_attribute *attr,				   const char *buf, size_t count){	struct hid_sensor_custom *sensor_inst = dev_get_drvdata(dev);	int value;	int ret = -EINVAL; 	if (kstrtoint(buf, 0, &value) != 0)		return -EINVAL; 	mutex_lock(&sensor_inst->mutex);	if (value && !sensor_inst->enable) {		ret = sensor_hub_device_open(sensor_inst->hsdev);		if (ret)			goto unlock_state; 		ret = set_power_report_state(sensor_inst, true);		if (ret) {			sensor_hub_device_close(sensor_inst->hsdev);			goto unlock_state;		}		sensor_inst->enable = true;	} else if (!value && sensor_inst->enable) {		ret = set_power_report_state(sensor_inst, false);		sensor_hub_device_close(sensor_inst->hsdev);		sensor_inst->enable = false;	}unlock_state:	mutex_unlock(&sensor_inst->mutex);	if (ret < 0)		return ret; 	return count;}static DEVICE_ATTR_RW(enable_sensor); static struct attribute *enable_sensor_attrs[] = {	&dev_attr_enable_sensor.attr,	NULL,}; static const struct attribute_group enable_sensor_attr_group = {	.attrs = enable_sensor_attrs,}; static ssize_t show_value(struct device *dev, struct device_attribute *attr,			  char *buf){	struct hid_sensor_custom *sensor_inst = dev_get_drvdata(dev);	struct hid_sensor_hub_attribute_info *attribute;	int index, usage, field_index;	char name[HID_CUSTOM_NAME_LENGTH];	bool feature = false;	bool input = false;	int value = 0; 	if (sscanf(attr->attr.name, "feature-%x-%x-%s", &index, &usage,		   name) == 3) {		feature = true;		field_index = index + sensor_inst->input_field_count;	} else if (sscanf(attr->attr.name, "input-%x-%x-%s", &index, &usage,		   name) == 3) {		input = true;		field_index = index;	} else		return -EINVAL; 	if (!strncmp(name, "value", strlen("value"))) {		u32 report_id;		int ret; 		attribute = &sensor_inst->fields[field_index].attribute;		report_id = attribute->report_id;		if (feature) {			u8 values[HID_CUSTOM_MAX_FEATURE_BYTES];			int len = 0;			u64 value = 0;			int i = 0; 			ret = sensor_hub_get_feature(sensor_inst->hsdev,						     report_id,						     index,						     sizeof(values), values);			if (ret < 0)				return ret; 			while (i < ret) {				if (i + attribute->size > ret) {					len += scnprintf(&buf[len],							PAGE_SIZE - len,							"%d ", values[i]);					break;				}				switch (attribute->size) {				case 2:					value = (u64) *(u16 *)&values[i];					i += attribute->size;					break;				case 4:					value = (u64) *(u32 *)&values[i];					i += attribute->size;					break;				case 8:					value = *(u64 *)&values[i];					i += attribute->size;					break;				default:					value = (u64) values[i];					++i;					break;				}				len += scnprintf(&buf[len], PAGE_SIZE - len,						"%lld ", value);			}			len += scnprintf(&buf[len], PAGE_SIZE - len, "\n"); 			return len;		} else if (input)			value = sensor_hub_input_attr_get_raw_value(						sensor_inst->hsdev,						sensor_inst->hsdev->usage,						usage, report_id,						SENSOR_HUB_SYNC, false);	} else if (!strncmp(name, "units", strlen("units")))		value = sensor_inst->fields[field_index].attribute.units;	else if (!strncmp(name, "unit-expo", strlen("unit-expo")))		value = sensor_inst->fields[field_index].attribute.unit_expo;	else if (!strncmp(name, "size", strlen("size")))		value = sensor_inst->fields[field_index].attribute.size;	else if (!strncmp(name, "minimum", strlen("minimum")))		value = sensor_inst->fields[field_index].attribute.							logical_minimum;	else if (!strncmp(name, "maximum", strlen("maximum")))		value = sensor_inst->fields[field_index].attribute.							logical_maximum;	else if (!strncmp(name, "name", strlen("name"))) {		struct hid_custom_usage_desc *usage_desc; 		usage_desc = bsearch(&usage, hid_custom_usage_desc_table,				     ARRAY_SIZE(hid_custom_usage_desc_table),				     sizeof(struct hid_custom_usage_desc),				     usage_id_cmp);		if (usage_desc)			return sysfs_emit(buf, "%s\n", usage_desc->desc);		else			return sysfs_emit(buf, "not-specified\n");	 } else		return -EINVAL; 	return sysfs_emit(buf, "%d\n", value);} static ssize_t store_value(struct device *dev, struct device_attribute *attr,			   const char *buf, size_t count){	struct hid_sensor_custom *sensor_inst = dev_get_drvdata(dev);	int index, field_index, usage;	char name[HID_CUSTOM_NAME_LENGTH];	int value, ret; 	if (sscanf(attr->attr.name, "feature-%x-%x-%s", &index, &usage,		   name) == 3) {		field_index = index + sensor_inst->input_field_count;	} else		return -EINVAL; 	if (!strncmp(name, "value", strlen("value"))) {		u32 report_id; 		if (kstrtoint(buf, 0, &value) != 0)			return -EINVAL; 		report_id = sensor_inst->fields[field_index].attribute.								report_id;		ret = sensor_hub_set_feature(sensor_inst->hsdev, report_id,					     index, sizeof(value), &value);		if (ret)			return ret;	} else		return -EINVAL; 	return count;} static int hid_sensor_capture_sample(struct hid_sensor_hub_device *hsdev,				  unsigned usage_id, size_t raw_len,				  char *raw_data, void *priv){	struct hid_sensor_custom *sensor_inst = platform_get_drvdata(priv);	struct hid_sensor_sample header; 	/* If any error occurs in a sample, rest of the fields are ignored */	if (sensor_inst->input_skip_sample) {		hid_err(sensor_inst->hsdev->hdev, "Skipped remaining data\n");		return 0;	} 	hid_dbg(sensor_inst->hsdev->hdev, "%s received %d of %d\n", __func__,		(int) (sensor_inst->input_report_recd_size + raw_len),		sensor_inst->input_report_size); 	if (!test_bit(0, &sensor_inst->misc_opened))		return 0; 	if (!sensor_inst->input_report_recd_size) {		int required_size = sizeof(struct hid_sensor_sample) +						sensor_inst->input_report_size;		header.usage_id = hsdev->usage;		header.raw_len = sensor_inst->input_report_size;		header.timestamp = ktime_get_real_ns();		if (kfifo_avail(&sensor_inst->data_fifo) >= required_size) {			kfifo_in(&sensor_inst->data_fifo,				 (unsigned char *)&header,				 sizeof(header));		} else			sensor_inst->input_skip_sample = true;	}	if (kfifo_avail(&sensor_inst->data_fifo) >= raw_len)		kfifo_in(&sensor_inst->data_fifo, (unsigned char *)raw_data,			 raw_len); 	sensor_inst->input_report_recd_size += raw_len; 	return 0;} static int hid_sensor_send_event(struct hid_sensor_hub_device *hsdev,				 unsigned usage_id, void *priv){	struct hid_sensor_custom *sensor_inst = platform_get_drvdata(priv); 	if (!test_bit(0, &sensor_inst->misc_opened))		return 0; 	sensor_inst->input_report_recd_size = 0;	sensor_inst->input_skip_sample = false; 	wake_up(&sensor_inst->wait); 	return 0;} static int hid_sensor_custom_add_field(struct hid_sensor_custom *sensor_inst,				       int index, int report_type,				       struct hid_report *report,				       struct hid_field *field){	struct hid_sensor_custom_field *sensor_field;	void *fields; 	fields = krealloc(sensor_inst->fields,			  (sensor_inst->sensor_field_count + 1) *			   sizeof(struct hid_sensor_custom_field), GFP_KERNEL);	if (!fields) {		kfree(sensor_inst->fields);		return -ENOMEM;	}	sensor_inst->fields = fields;	sensor_field = &sensor_inst->fields[sensor_inst->sensor_field_count];	sensor_field->attribute.usage_id = sensor_inst->hsdev->usage;	if (field->logical)		sensor_field->attribute.attrib_id = field->logical;	else		sensor_field->attribute.attrib_id = field->usage[0].hid; 	sensor_field->attribute.index = index;	sensor_field->attribute.report_id = report->id;	sensor_field->attribute.units = field->unit;	sensor_field->attribute.unit_expo = field->unit_exponent;

Lines 1–500 of 1082.