brintos

brintos / linux-shallow public Read only

0
0
Text · 28.9 KiB · 66f0675 Raw
1075 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * hid-sensor-custom.c4 * Copyright (c) 2015, Intel Corporation.5 */6 7#include <linux/ctype.h>8#include <linux/dmi.h>9#include <linux/kernel.h>10#include <linux/module.h>11#include <linux/init.h>12#include <linux/miscdevice.h>13#include <linux/kfifo.h>14#include <linux/sched.h>15#include <linux/wait.h>16#include <linux/poll.h>17#include <linux/bsearch.h>18#include <linux/platform_device.h>19#include <linux/hid-sensor-hub.h>20 21#define HID_CUSTOM_NAME_LENGTH		6422#define HID_CUSTOM_MAX_CORE_ATTRS	1023#define HID_CUSTOM_TOTAL_ATTRS		(HID_CUSTOM_MAX_CORE_ATTRS + 1)24#define HID_CUSTOM_FIFO_SIZE		409625#define HID_CUSTOM_MAX_FEATURE_BYTES	6426#define HID_SENSOR_USAGE_LENGTH (4 + 1)27 28struct hid_sensor_custom_field {29	int report_id;30	char group_name[HID_CUSTOM_NAME_LENGTH];31	struct hid_sensor_hub_attribute_info attribute;32	struct device_attribute sd_attrs[HID_CUSTOM_MAX_CORE_ATTRS];33	char attr_name[HID_CUSTOM_TOTAL_ATTRS][HID_CUSTOM_NAME_LENGTH];34	struct attribute *attrs[HID_CUSTOM_TOTAL_ATTRS];35	struct attribute_group hid_custom_attribute_group;36};37 38struct hid_sensor_custom {39	struct mutex mutex;40	struct platform_device *pdev;41	struct hid_sensor_hub_device *hsdev;42	struct hid_sensor_hub_callbacks callbacks;43	int sensor_field_count;44	struct hid_sensor_custom_field *fields;45	int input_field_count;46	int input_report_size;47	int input_report_recd_size;48	bool input_skip_sample;49	bool enable;50	struct hid_sensor_custom_field *power_state;51	struct hid_sensor_custom_field *report_state;52	struct miscdevice custom_dev;53	struct kfifo data_fifo;54	unsigned long misc_opened;55	wait_queue_head_t wait;56	struct platform_device *custom_pdev;57};58 59/* Header for each sample to user space via dev interface */60struct hid_sensor_sample {61	u32 usage_id;62	u64 timestamp;63	u32 raw_len;64} __packed;65 66static struct attribute hid_custom_attrs[HID_CUSTOM_TOTAL_ATTRS] = {67	{.name = "name", .mode = S_IRUGO},68	{.name = "units", .mode = S_IRUGO},69	{.name = "unit-expo", .mode = S_IRUGO},70	{.name = "minimum", .mode = S_IRUGO},71	{.name = "maximum", .mode = S_IRUGO},72	{.name = "size", .mode = S_IRUGO},73	{.name = "value", .mode = S_IWUSR | S_IRUGO},74	{.name = NULL}75};76 77static const struct hid_custom_usage_desc {78	int usage_id;79	char *desc;80} hid_custom_usage_desc_table[] = {81	{0x200201,	"event-sensor-state"},82	{0x200202,	"event-sensor-event"},83	{0x200301,	"property-friendly-name"},84	{0x200302,	"property-persistent-unique-id"},85	{0x200303,	"property-sensor-status"},86	{0x200304,	"property-min-report-interval"},87	{0x200305,	"property-sensor-manufacturer"},88	{0x200306,	"property-sensor-model"},89	{0x200307,	"property-sensor-serial-number"},90	{0x200308,	"property-sensor-description"},91	{0x200309,	"property-sensor-connection-type"},92	{0x20030A,	"property-sensor-device-path"},93	{0x20030B,	"property-hardware-revision"},94	{0x20030C,	"property-firmware-version"},95	{0x20030D,	"property-release-date"},96	{0x20030E,	"property-report-interval"},97	{0x20030F,	"property-change-sensitivity-absolute"},98	{0x200310,	"property-change-sensitivity-percent-range"},99	{0x200311,	"property-change-sensitivity-percent-relative"},100	{0x200312,	"property-accuracy"},101	{0x200313,	"property-resolution"},102	{0x200314,	"property-maximum"},103	{0x200315,	"property-minimum"},104	{0x200316,	"property-reporting-state"},105	{0x200317,	"property-sampling-rate"},106	{0x200318,	"property-response-curve"},107	{0x200319,	"property-power-state"},108	{0x200540,	"data-field-custom"},109	{0x200541,	"data-field-custom-usage"},110	{0x200542,	"data-field-custom-boolean-array"},111	{0x200543,	"data-field-custom-value"},112	{0x200544,	"data-field-custom-value_1"},113	{0x200545,	"data-field-custom-value_2"},114	{0x200546,	"data-field-custom-value_3"},115	{0x200547,	"data-field-custom-value_4"},116	{0x200548,	"data-field-custom-value_5"},117	{0x200549,	"data-field-custom-value_6"},118	{0x20054A,	"data-field-custom-value_7"},119	{0x20054B,	"data-field-custom-value_8"},120	{0x20054C,	"data-field-custom-value_9"},121	{0x20054D,	"data-field-custom-value_10"},122	{0x20054E,	"data-field-custom-value_11"},123	{0x20054F,	"data-field-custom-value_12"},124	{0x200550,	"data-field-custom-value_13"},125	{0x200551,	"data-field-custom-value_14"},126	{0x200552,	"data-field-custom-value_15"},127	{0x200553,	"data-field-custom-value_16"},128	{0x200554,	"data-field-custom-value_17"},129	{0x200555,	"data-field-custom-value_18"},130	{0x200556,	"data-field-custom-value_19"},131	{0x200557,	"data-field-custom-value_20"},132	{0x200558,	"data-field-custom-value_21"},133	{0x200559,	"data-field-custom-value_22"},134	{0x20055A,	"data-field-custom-value_23"},135	{0x20055B,	"data-field-custom-value_24"},136	{0x20055C,	"data-field-custom-value_25"},137	{0x20055D,	"data-field-custom-value_26"},138	{0x20055E,	"data-field-custom-value_27"},139	{0x20055F,	"data-field-custom-value_28"},140};141 142static int usage_id_cmp(const void *p1, const void *p2)143{144	if (*(int *)p1 < *(int *)p2)145		return -1;146 147	if (*(int *)p1 > *(int *)p2)148		return 1;149 150	return 0;151}152 153static ssize_t enable_sensor_show(struct device *dev,154				  struct device_attribute *attr, char *buf)155{156	struct hid_sensor_custom *sensor_inst = dev_get_drvdata(dev);157 158	return sysfs_emit(buf, "%d\n", sensor_inst->enable);159}160 161static int set_power_report_state(struct hid_sensor_custom *sensor_inst,162				  bool state)163{164	int power_val = -1;165	int report_val = -1;166	u32 power_state_usage_id;167	u32 report_state_usage_id;168	int ret;169 170	/*171	 * It is possible that the power/report state ids are not present.172	 * In this case this function will return success. But if the173	 * ids are present, then it will return error if set fails.174	 */175	if (state) {176		power_state_usage_id =177			HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM;178		report_state_usage_id =179			HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM;180	} else {181		power_state_usage_id =182			HID_USAGE_SENSOR_PROP_POWER_STATE_D4_POWER_OFF_ENUM;183		report_state_usage_id =184			HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM;185	}186 187	if (sensor_inst->power_state)188		power_val = hid_sensor_get_usage_index(sensor_inst->hsdev,189				sensor_inst->power_state->attribute.report_id,190				sensor_inst->power_state->attribute.index,191				power_state_usage_id);192	if (sensor_inst->report_state)193		report_val = hid_sensor_get_usage_index(sensor_inst->hsdev,194				sensor_inst->report_state->attribute.report_id,195				sensor_inst->report_state->attribute.index,196				report_state_usage_id);197 198	if (power_val >= 0) {199		power_val +=200			sensor_inst->power_state->attribute.logical_minimum;201		ret = sensor_hub_set_feature(sensor_inst->hsdev,202				sensor_inst->power_state->attribute.report_id,203				sensor_inst->power_state->attribute.index,204				sizeof(power_val),205				&power_val);206		if (ret) {207			hid_err(sensor_inst->hsdev->hdev,208				"Set power state failed\n");209			return ret;210		}211	}212 213	if (report_val >= 0) {214		report_val +=215			sensor_inst->report_state->attribute.logical_minimum;216		ret = sensor_hub_set_feature(sensor_inst->hsdev,217				sensor_inst->report_state->attribute.report_id,218				sensor_inst->report_state->attribute.index,219				sizeof(report_val),220				&report_val);221		if (ret) {222			hid_err(sensor_inst->hsdev->hdev,223				"Set report state failed\n");224			return ret;225		}226	}227 228	return 0;229}230 231static ssize_t enable_sensor_store(struct device *dev,232				   struct device_attribute *attr,233				   const char *buf, size_t count)234{235	struct hid_sensor_custom *sensor_inst = dev_get_drvdata(dev);236	int value;237	int ret = -EINVAL;238 239	if (kstrtoint(buf, 0, &value) != 0)240		return -EINVAL;241 242	mutex_lock(&sensor_inst->mutex);243	if (value && !sensor_inst->enable) {244		ret = sensor_hub_device_open(sensor_inst->hsdev);245		if (ret)246			goto unlock_state;247 248		ret = set_power_report_state(sensor_inst, true);249		if (ret) {250			sensor_hub_device_close(sensor_inst->hsdev);251			goto unlock_state;252		}253		sensor_inst->enable = true;254	} else if (!value && sensor_inst->enable) {255		ret = set_power_report_state(sensor_inst, false);256		sensor_hub_device_close(sensor_inst->hsdev);257		sensor_inst->enable = false;258	}259unlock_state:260	mutex_unlock(&sensor_inst->mutex);261	if (ret < 0)262		return ret;263 264	return count;265}266static DEVICE_ATTR_RW(enable_sensor);267 268static struct attribute *enable_sensor_attrs[] = {269	&dev_attr_enable_sensor.attr,270	NULL,271};272 273static const struct attribute_group enable_sensor_attr_group = {274	.attrs = enable_sensor_attrs,275};276 277static ssize_t show_value(struct device *dev, struct device_attribute *attr,278			  char *buf)279{280	struct hid_sensor_custom *sensor_inst = dev_get_drvdata(dev);281	struct hid_sensor_hub_attribute_info *attribute;282	int index, usage, field_index;283	char name[HID_CUSTOM_NAME_LENGTH];284	bool feature = false;285	bool input = false;286	int value = 0;287 288	if (sscanf(attr->attr.name, "feature-%x-%x-%s", &index, &usage,289		   name) == 3) {290		feature = true;291		field_index = index + sensor_inst->input_field_count;292	} else if (sscanf(attr->attr.name, "input-%x-%x-%s", &index, &usage,293		   name) == 3) {294		input = true;295		field_index = index;296	} else297		return -EINVAL;298 299	if (!strncmp(name, "value", strlen("value"))) {300		u32 report_id;301		int ret;302 303		attribute = &sensor_inst->fields[field_index].attribute;304		report_id = attribute->report_id;305		if (feature) {306			u8 values[HID_CUSTOM_MAX_FEATURE_BYTES];307			int len = 0;308			u64 value = 0;309			int i = 0;310 311			ret = sensor_hub_get_feature(sensor_inst->hsdev,312						     report_id,313						     index,314						     sizeof(values), values);315			if (ret < 0)316				return ret;317 318			while (i < ret) {319				if (i + attribute->size > ret) {320					len += scnprintf(&buf[len],321							PAGE_SIZE - len,322							"%d ", values[i]);323					break;324				}325				switch (attribute->size) {326				case 2:327					value = (u64) *(u16 *)&values[i];328					i += attribute->size;329					break;330				case 4:331					value = (u64) *(u32 *)&values[i];332					i += attribute->size;333					break;334				case 8:335					value = *(u64 *)&values[i];336					i += attribute->size;337					break;338				default:339					value = (u64) values[i];340					++i;341					break;342				}343				len += scnprintf(&buf[len], PAGE_SIZE - len,344						"%lld ", value);345			}346			len += scnprintf(&buf[len], PAGE_SIZE - len, "\n");347 348			return len;349		} else if (input)350			value = sensor_hub_input_attr_get_raw_value(351						sensor_inst->hsdev,352						sensor_inst->hsdev->usage,353						usage, report_id,354						SENSOR_HUB_SYNC, false);355	} else if (!strncmp(name, "units", strlen("units")))356		value = sensor_inst->fields[field_index].attribute.units;357	else if (!strncmp(name, "unit-expo", strlen("unit-expo")))358		value = sensor_inst->fields[field_index].attribute.unit_expo;359	else if (!strncmp(name, "size", strlen("size")))360		value = sensor_inst->fields[field_index].attribute.size;361	else if (!strncmp(name, "minimum", strlen("minimum")))362		value = sensor_inst->fields[field_index].attribute.363							logical_minimum;364	else if (!strncmp(name, "maximum", strlen("maximum")))365		value = sensor_inst->fields[field_index].attribute.366							logical_maximum;367	else if (!strncmp(name, "name", strlen("name"))) {368		struct hid_custom_usage_desc *usage_desc;369 370		usage_desc = bsearch(&usage, hid_custom_usage_desc_table,371				     ARRAY_SIZE(hid_custom_usage_desc_table),372				     sizeof(struct hid_custom_usage_desc),373				     usage_id_cmp);374		if (usage_desc)375			return sysfs_emit(buf, "%s\n", usage_desc->desc);376		else377			return sysfs_emit(buf, "not-specified\n");378	 } else379		return -EINVAL;380 381	return sysfs_emit(buf, "%d\n", value);382}383 384static ssize_t store_value(struct device *dev, struct device_attribute *attr,385			   const char *buf, size_t count)386{387	struct hid_sensor_custom *sensor_inst = dev_get_drvdata(dev);388	int index, field_index, usage;389	char name[HID_CUSTOM_NAME_LENGTH];390	int value, ret;391 392	if (sscanf(attr->attr.name, "feature-%x-%x-%s", &index, &usage,393		   name) == 3) {394		field_index = index + sensor_inst->input_field_count;395	} else396		return -EINVAL;397 398	if (!strncmp(name, "value", strlen("value"))) {399		u32 report_id;400 401		if (kstrtoint(buf, 0, &value) != 0)402			return -EINVAL;403 404		report_id = sensor_inst->fields[field_index].attribute.405								report_id;406		ret = sensor_hub_set_feature(sensor_inst->hsdev, report_id,407					     index, sizeof(value), &value);408		if (ret)409			return ret;410	} else411		return -EINVAL;412 413	return count;414}415 416static int hid_sensor_capture_sample(struct hid_sensor_hub_device *hsdev,417				  unsigned usage_id, size_t raw_len,418				  char *raw_data, void *priv)419{420	struct hid_sensor_custom *sensor_inst = platform_get_drvdata(priv);421	struct hid_sensor_sample header;422 423	/* If any error occurs in a sample, rest of the fields are ignored */424	if (sensor_inst->input_skip_sample) {425		hid_err(sensor_inst->hsdev->hdev, "Skipped remaining data\n");426		return 0;427	}428 429	hid_dbg(sensor_inst->hsdev->hdev, "%s received %d of %d\n", __func__,430		(int) (sensor_inst->input_report_recd_size + raw_len),431		sensor_inst->input_report_size);432 433	if (!test_bit(0, &sensor_inst->misc_opened))434		return 0;435 436	if (!sensor_inst->input_report_recd_size) {437		int required_size = sizeof(struct hid_sensor_sample) +438						sensor_inst->input_report_size;439		header.usage_id = hsdev->usage;440		header.raw_len = sensor_inst->input_report_size;441		header.timestamp = ktime_get_real_ns();442		if (kfifo_avail(&sensor_inst->data_fifo) >= required_size) {443			kfifo_in(&sensor_inst->data_fifo,444				 (unsigned char *)&header,445				 sizeof(header));446		} else447			sensor_inst->input_skip_sample = true;448	}449	if (kfifo_avail(&sensor_inst->data_fifo) >= raw_len)450		kfifo_in(&sensor_inst->data_fifo, (unsigned char *)raw_data,451			 raw_len);452 453	sensor_inst->input_report_recd_size += raw_len;454 455	return 0;456}457 458static int hid_sensor_send_event(struct hid_sensor_hub_device *hsdev,459				 unsigned usage_id, void *priv)460{461	struct hid_sensor_custom *sensor_inst = platform_get_drvdata(priv);462 463	if (!test_bit(0, &sensor_inst->misc_opened))464		return 0;465 466	sensor_inst->input_report_recd_size = 0;467	sensor_inst->input_skip_sample = false;468 469	wake_up(&sensor_inst->wait);470 471	return 0;472}473 474static int hid_sensor_custom_add_field(struct hid_sensor_custom *sensor_inst,475				       int index, int report_type,476				       struct hid_report *report,477				       struct hid_field *field)478{479	struct hid_sensor_custom_field *sensor_field;480	void *fields;481 482	fields = krealloc(sensor_inst->fields,483			  (sensor_inst->sensor_field_count + 1) *484			   sizeof(struct hid_sensor_custom_field), GFP_KERNEL);485	if (!fields) {486		kfree(sensor_inst->fields);487		return -ENOMEM;488	}489	sensor_inst->fields = fields;490	sensor_field = &sensor_inst->fields[sensor_inst->sensor_field_count];491	sensor_field->attribute.usage_id = sensor_inst->hsdev->usage;492	if (field->logical)493		sensor_field->attribute.attrib_id = field->logical;494	else495		sensor_field->attribute.attrib_id = field->usage[0].hid;496 497	sensor_field->attribute.index = index;498	sensor_field->attribute.report_id = report->id;499	sensor_field->attribute.units = field->unit;500	sensor_field->attribute.unit_expo = field->unit_exponent;501	sensor_field->attribute.size = (field->report_size / 8);502	sensor_field->attribute.logical_minimum = field->logical_minimum;503	sensor_field->attribute.logical_maximum = field->logical_maximum;504 505	if (report_type == HID_FEATURE_REPORT)506		snprintf(sensor_field->group_name,507			 sizeof(sensor_field->group_name), "feature-%x-%x",508			 sensor_field->attribute.index,509			 sensor_field->attribute.attrib_id);510	else if (report_type == HID_INPUT_REPORT) {511		snprintf(sensor_field->group_name,512			 sizeof(sensor_field->group_name),513			 "input-%x-%x", sensor_field->attribute.index,514			 sensor_field->attribute.attrib_id);515		sensor_inst->input_field_count++;516		sensor_inst->input_report_size += (field->report_size *517						   field->report_count) / 8;518	}519 520	memset(&sensor_field->hid_custom_attribute_group, 0,521	       sizeof(struct attribute_group));522	sensor_inst->sensor_field_count++;523 524	return 0;525}526 527static int hid_sensor_custom_add_fields(struct hid_sensor_custom *sensor_inst,528					struct hid_report_enum *report_enum,529					int report_type)530{531	int i;532	int ret;533	struct hid_report *report;534	struct hid_field *field;535	struct hid_sensor_hub_device *hsdev = sensor_inst->hsdev;536 537	list_for_each_entry(report, &report_enum->report_list, list) {538		for (i = 0; i < report->maxfield; ++i) {539			field = report->field[i];540			if (field->maxusage &&541			    ((field->usage[0].collection_index >=542			      hsdev->start_collection_index) &&543			      (field->usage[0].collection_index <544			       hsdev->end_collection_index))) {545 546				ret = hid_sensor_custom_add_field(sensor_inst,547								  i,548								  report_type,549								  report,550								  field);551				if (ret)552					return ret;553 554			}555		}556	}557 558	return 0;559}560 561static int hid_sensor_custom_add_attributes(struct hid_sensor_custom562								*sensor_inst)563{564	struct hid_sensor_hub_device *hsdev = sensor_inst->hsdev;565	struct hid_device *hdev = hsdev->hdev;566	int ret = -1;567	int i, j;568 569	for (j = 0; j < HID_REPORT_TYPES; ++j) {570		if (j == HID_OUTPUT_REPORT)571			continue;572 573		ret = hid_sensor_custom_add_fields(sensor_inst,574						   &hdev->report_enum[j], j);575		if (ret)576			return ret;577 578	}579 580	/* Create sysfs attributes */581	for (i = 0; i < sensor_inst->sensor_field_count; ++i) {582		j = 0;583		while (j < HID_CUSTOM_TOTAL_ATTRS &&584		       hid_custom_attrs[j].name) {585			struct device_attribute *device_attr;586 587			device_attr = &sensor_inst->fields[i].sd_attrs[j];588 589			snprintf((char *)&sensor_inst->fields[i].attr_name[j],590				 HID_CUSTOM_NAME_LENGTH, "%s-%s",591				 sensor_inst->fields[i].group_name,592				 hid_custom_attrs[j].name);593			sysfs_attr_init(&device_attr->attr);594			device_attr->attr.name =595				(char *)&sensor_inst->fields[i].attr_name[j];596			device_attr->attr.mode = hid_custom_attrs[j].mode;597			device_attr->show = show_value;598			if (hid_custom_attrs[j].mode & S_IWUSR)599				device_attr->store = store_value;600			sensor_inst->fields[i].attrs[j] = &device_attr->attr;601			++j;602		}603		sensor_inst->fields[i].attrs[j] = NULL;604		sensor_inst->fields[i].hid_custom_attribute_group.attrs =605						sensor_inst->fields[i].attrs;606		sensor_inst->fields[i].hid_custom_attribute_group.name =607					sensor_inst->fields[i].group_name;608		ret = sysfs_create_group(&sensor_inst->pdev->dev.kobj,609					 &sensor_inst->fields[i].610					 hid_custom_attribute_group);611		if (ret)612			break;613 614		/* For power or report field store indexes */615		if (sensor_inst->fields[i].attribute.attrib_id ==616					HID_USAGE_SENSOR_PROY_POWER_STATE)617			sensor_inst->power_state = &sensor_inst->fields[i];618		else if (sensor_inst->fields[i].attribute.attrib_id ==619					HID_USAGE_SENSOR_PROP_REPORT_STATE)620			sensor_inst->report_state = &sensor_inst->fields[i];621	}622 623	return ret;624}625 626static void hid_sensor_custom_remove_attributes(struct hid_sensor_custom *627								sensor_inst)628{629	int i;630 631	for (i = 0; i < sensor_inst->sensor_field_count; ++i)632		sysfs_remove_group(&sensor_inst->pdev->dev.kobj,633				   &sensor_inst->fields[i].634				   hid_custom_attribute_group);635 636	kfree(sensor_inst->fields);637}638 639static ssize_t hid_sensor_custom_read(struct file *file, char __user *buf,640				      size_t count, loff_t *f_ps)641{642	struct hid_sensor_custom *sensor_inst;643	unsigned int copied;644	int ret;645 646	sensor_inst = container_of(file->private_data,647				   struct hid_sensor_custom, custom_dev);648 649	if (count < sizeof(struct hid_sensor_sample))650		return -EINVAL;651 652	do {653		if (kfifo_is_empty(&sensor_inst->data_fifo)) {654			if (file->f_flags & O_NONBLOCK)655				return -EAGAIN;656 657			ret = wait_event_interruptible(sensor_inst->wait,658				!kfifo_is_empty(&sensor_inst->data_fifo));659			if (ret)660				return ret;661		}662		ret = kfifo_to_user(&sensor_inst->data_fifo, buf, count,663				    &copied);664		if (ret)665			return ret;666 667	} while (copied == 0);668 669	return copied;670}671 672static int hid_sensor_custom_release(struct inode *inode, struct file *file)673{674	struct hid_sensor_custom *sensor_inst;675 676	sensor_inst = container_of(file->private_data,677				   struct hid_sensor_custom, custom_dev);678 679	clear_bit(0, &sensor_inst->misc_opened);680 681	return 0;682}683 684static int hid_sensor_custom_open(struct inode *inode, struct file *file)685{686	struct hid_sensor_custom *sensor_inst;687 688	sensor_inst = container_of(file->private_data,689				   struct hid_sensor_custom, custom_dev);690	/* We essentially have single reader and writer */691	if (test_and_set_bit(0, &sensor_inst->misc_opened))692		return -EBUSY;693 694	return stream_open(inode, file);695}696 697static __poll_t hid_sensor_custom_poll(struct file *file,698					   struct poll_table_struct *wait)699{700	struct hid_sensor_custom *sensor_inst;701	__poll_t mask = 0;702 703	sensor_inst = container_of(file->private_data,704				   struct hid_sensor_custom, custom_dev);705 706	poll_wait(file, &sensor_inst->wait, wait);707 708	if (!kfifo_is_empty(&sensor_inst->data_fifo))709		mask = EPOLLIN | EPOLLRDNORM;710 711	return mask;712}713 714static const struct file_operations hid_sensor_custom_fops = {715	.open =  hid_sensor_custom_open,716	.read =  hid_sensor_custom_read,717	.release = hid_sensor_custom_release,718	.poll = hid_sensor_custom_poll,719	.llseek = noop_llseek,720};721 722static int hid_sensor_custom_dev_if_add(struct hid_sensor_custom *sensor_inst)723{724	int ret;725 726	ret = kfifo_alloc(&sensor_inst->data_fifo, HID_CUSTOM_FIFO_SIZE,727			  GFP_KERNEL);728	if (ret)729		return ret;730 731	init_waitqueue_head(&sensor_inst->wait);732 733	sensor_inst->custom_dev.minor = MISC_DYNAMIC_MINOR;734	sensor_inst->custom_dev.name = dev_name(&sensor_inst->pdev->dev);735	sensor_inst->custom_dev.fops = &hid_sensor_custom_fops;736	ret = misc_register(&sensor_inst->custom_dev);737	if (ret) {738		kfifo_free(&sensor_inst->data_fifo);739		return ret;740	}741	return 0;742}743 744static void hid_sensor_custom_dev_if_remove(struct hid_sensor_custom745								*sensor_inst)746{747	wake_up(&sensor_inst->wait);748	misc_deregister(&sensor_inst->custom_dev);749	kfifo_free(&sensor_inst->data_fifo);750 751}752 753/*754 * Match a known custom sensor.755 * tag and luid is mandatory.756 */757struct hid_sensor_custom_match {758	const char *tag;759	const char *luid;760	const char *model;761	const char *manufacturer;762	bool check_dmi;763	struct dmi_system_id dmi;764};765 766/*767 * Custom sensor properties used for matching.768 */769struct hid_sensor_custom_properties {770	u16 serial_num[HID_CUSTOM_MAX_FEATURE_BYTES];771	u16 model[HID_CUSTOM_MAX_FEATURE_BYTES];772	u16 manufacturer[HID_CUSTOM_MAX_FEATURE_BYTES];773};774 775static const struct hid_sensor_custom_match hid_sensor_custom_known_table[] = {776	/*777	 * Intel Integrated Sensor Hub (ISH)778	 */779	{	/* Intel ISH hinge */780		.tag = "INT",781		.luid = "020B000000000000",782		.manufacturer = "INTEL",783	},784	/*785	 * Lenovo Intelligent Sensing Solution (LISS)786	 */787	{	/* ambient light */788		.tag = "LISS",789		.luid = "0041010200000082",790		.model = "STK3X3X Sensor",791		.manufacturer = "Vendor 258",792		.check_dmi = true,793		.dmi.matches = {794			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),795		}796	},797	{	/* human presence */798		.tag = "LISS",799		.luid = "0226000171AC0081",800		.model = "VL53L1_HOD Sensor",801		.manufacturer = "ST_MICRO",802		.check_dmi = true,803		.dmi.matches = {804			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),805		}806	},807	{}808};809 810static bool hid_sensor_custom_prop_match_str(const u16 *prop, const char *match,811					     size_t count)812{813	while (count-- && *prop && *match) {814		if (*prop != (u16) *match)815			return false;816		prop++;817		match++;818	}819 820	return (count == -1) || *prop == (u16)*match;821}822 823static int hid_sensor_custom_get_prop(struct hid_sensor_hub_device *hsdev,824				      u32 prop_usage_id, size_t prop_size,825				      u16 *prop)826{827	struct hid_sensor_hub_attribute_info prop_attr = { 0 };828	int ret;829 830	memset(prop, 0, prop_size);831 832	ret = sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT,833						  hsdev->usage, prop_usage_id,834						  &prop_attr);835	if (ret < 0)836		return ret;837 838	ret = sensor_hub_get_feature(hsdev, prop_attr.report_id,839				     prop_attr.index, prop_size, prop);840	if (ret < 0) {841		hid_err(hsdev->hdev, "Failed to get sensor property %08x %d\n",842			prop_usage_id, ret);843		return ret;844	}845 846	return 0;847}848 849static bool850hid_sensor_custom_do_match(struct hid_sensor_hub_device *hsdev,851			   const struct hid_sensor_custom_match *match,852			   const struct hid_sensor_custom_properties *prop)853{854	struct dmi_system_id dmi[] = { match->dmi, { 0 } };855 856	if (!hid_sensor_custom_prop_match_str(prop->serial_num, "LUID:", 5) ||857	    !hid_sensor_custom_prop_match_str(prop->serial_num + 5, match->luid,858					      HID_CUSTOM_MAX_FEATURE_BYTES - 5))859		return false;860 861	if (match->model &&862	    !hid_sensor_custom_prop_match_str(prop->model, match->model,863					      HID_CUSTOM_MAX_FEATURE_BYTES))864		return false;865 866	if (match->manufacturer &&867	    !hid_sensor_custom_prop_match_str(prop->manufacturer, match->manufacturer,868					      HID_CUSTOM_MAX_FEATURE_BYTES))869		return false;870 871	if (match->check_dmi && !dmi_check_system(dmi))872		return false;873 874	return true;875}876 877static int878hid_sensor_custom_properties_get(struct hid_sensor_hub_device *hsdev,879				 struct hid_sensor_custom_properties *prop)880{881	int ret;882 883	ret = hid_sensor_custom_get_prop(hsdev,884					 HID_USAGE_SENSOR_PROP_SERIAL_NUM,885					 HID_CUSTOM_MAX_FEATURE_BYTES,886					 prop->serial_num);887	if (ret < 0)888		return ret;889 890	/*891	 * Ignore errors on the following model and manufacturer properties.892	 * Because these are optional, it is not an error if they are missing.893	 */894 895	hid_sensor_custom_get_prop(hsdev, HID_USAGE_SENSOR_PROP_MODEL,896				   HID_CUSTOM_MAX_FEATURE_BYTES,897				   prop->model);898 899	hid_sensor_custom_get_prop(hsdev, HID_USAGE_SENSOR_PROP_MANUFACTURER,900				   HID_CUSTOM_MAX_FEATURE_BYTES,901				   prop->manufacturer);902 903	return 0;904}905 906static int907hid_sensor_custom_get_known(struct hid_sensor_hub_device *hsdev,908			    const struct hid_sensor_custom_match **known)909{910	int ret;911	const struct hid_sensor_custom_match *match =912		hid_sensor_custom_known_table;913	struct hid_sensor_custom_properties *prop;914 915	prop = kmalloc(sizeof(struct hid_sensor_custom_properties), GFP_KERNEL);916	if (!prop)917		return -ENOMEM;918 919	ret = hid_sensor_custom_properties_get(hsdev, prop);920	if (ret < 0)921		goto out;922 923	while (match->tag) {924		if (hid_sensor_custom_do_match(hsdev, match, prop)) {925			*known = match;926			ret = 0;927			goto out;928		}929		match++;930	}931	ret = -ENODATA;932out:933	kfree(prop);934	return ret;935}936 937static struct platform_device *938hid_sensor_register_platform_device(struct platform_device *pdev,939				    struct hid_sensor_hub_device *hsdev,940				    const struct hid_sensor_custom_match *match)941{942	char real_usage[HID_SENSOR_USAGE_LENGTH] = { 0 };943	struct platform_device *custom_pdev;944	const char *dev_name;945	char *c;946 947	memcpy(real_usage, match->luid, 4);948 949	/* usage id are all lowcase */950	for (c = real_usage; *c != '\0'; c++)951		*c = tolower(*c);952 953	/* HID-SENSOR-TAG-REAL_USAGE_ID */954	dev_name = kasprintf(GFP_KERNEL, "HID-SENSOR-%s-%s",955			     match->tag, real_usage);956	if (!dev_name)957		return ERR_PTR(-ENOMEM);958 959	custom_pdev = platform_device_register_data(pdev->dev.parent, dev_name,960						    PLATFORM_DEVID_AUTO, hsdev,961						    sizeof(*hsdev));962	kfree(dev_name);963	return custom_pdev;964}965 966static int hid_sensor_custom_probe(struct platform_device *pdev)967{968	struct hid_sensor_custom *sensor_inst;969	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;970	int ret;971	const struct hid_sensor_custom_match *match;972 973	sensor_inst = devm_kzalloc(&pdev->dev, sizeof(*sensor_inst),974				   GFP_KERNEL);975	if (!sensor_inst)976		return -ENOMEM;977 978	sensor_inst->callbacks.capture_sample = hid_sensor_capture_sample;979	sensor_inst->callbacks.send_event = hid_sensor_send_event;980	sensor_inst->callbacks.pdev = pdev;981	sensor_inst->hsdev = hsdev;982	sensor_inst->pdev = pdev;983	mutex_init(&sensor_inst->mutex);984	platform_set_drvdata(pdev, sensor_inst);985 986	ret = hid_sensor_custom_get_known(hsdev, &match);987	if (!ret) {988		sensor_inst->custom_pdev =989			hid_sensor_register_platform_device(pdev, hsdev, match);990 991		ret = PTR_ERR_OR_ZERO(sensor_inst->custom_pdev);992		if (ret) {993			dev_err(&pdev->dev,994				"register_platform_device failed\n");995			return ret;996		}997 998		return 0;999	}1000 1001	ret = sensor_hub_register_callback(hsdev, hsdev->usage,1002					   &sensor_inst->callbacks);1003	if (ret < 0) {1004		dev_err(&pdev->dev, "callback reg failed\n");1005		return ret;1006	}1007 1008	ret = sysfs_create_group(&sensor_inst->pdev->dev.kobj,1009				 &enable_sensor_attr_group);1010	if (ret)1011		goto err_remove_callback;1012 1013	ret = hid_sensor_custom_add_attributes(sensor_inst);1014	if (ret)1015		goto err_remove_group;1016 1017	ret = hid_sensor_custom_dev_if_add(sensor_inst);1018	if (ret)1019		goto err_remove_attributes;1020 1021	return 0;1022 1023err_remove_attributes:1024	hid_sensor_custom_remove_attributes(sensor_inst);1025err_remove_group:1026	sysfs_remove_group(&sensor_inst->pdev->dev.kobj,1027			   &enable_sensor_attr_group);1028err_remove_callback:1029	sensor_hub_remove_callback(hsdev, hsdev->usage);1030 1031	return ret;1032}1033 1034static void hid_sensor_custom_remove(struct platform_device *pdev)1035{1036	struct hid_sensor_custom *sensor_inst = platform_get_drvdata(pdev);1037	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;1038 1039	if (sensor_inst->custom_pdev) {1040		platform_device_unregister(sensor_inst->custom_pdev);1041		return;1042	}1043 1044	hid_sensor_custom_dev_if_remove(sensor_inst);1045	hid_sensor_custom_remove_attributes(sensor_inst);1046	sysfs_remove_group(&sensor_inst->pdev->dev.kobj,1047			   &enable_sensor_attr_group);1048	sensor_hub_remove_callback(hsdev, hsdev->usage);1049}1050 1051static const struct platform_device_id hid_sensor_custom_ids[] = {1052	{1053		.name = "HID-SENSOR-2000e1",1054	},1055	{1056		.name = "HID-SENSOR-2000e2",1057	},1058	{ /* sentinel */ }1059};1060MODULE_DEVICE_TABLE(platform, hid_sensor_custom_ids);1061 1062static struct platform_driver hid_sensor_custom_platform_driver = {1063	.id_table = hid_sensor_custom_ids,1064	.driver = {1065		.name	= KBUILD_MODNAME,1066	},1067	.probe		= hid_sensor_custom_probe,1068	.remove_new	= hid_sensor_custom_remove,1069};1070module_platform_driver(hid_sensor_custom_platform_driver);1071 1072MODULE_DESCRIPTION("HID Sensor Custom and Generic sensor Driver");1073MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");1074MODULE_LICENSE("GPL");1075