You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'for-4.1/sensor-hub' into for-linus
Conflicts: drivers/iio/common/hid-sensors/hid-sensor-trigger.c include/linux/hid-sensor-hub.h
This commit is contained in:
@@ -138,3 +138,87 @@ accelerometer wants to poll X axis value, then it can call this function with
|
||||
the usage id of X axis. HID sensors can provide events, so this is not necessary
|
||||
to poll for any field. If there is some new sample, the core driver will call
|
||||
registered callback function to process the sample.
|
||||
|
||||
|
||||
----------
|
||||
|
||||
HID Custom and generic Sensors
|
||||
|
||||
HID Sensor specification defines two special sensor usage types. Since they
|
||||
don't represent a standard sensor, it is not possible to define using Linux IIO
|
||||
type interfaces.
|
||||
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 application/driver to determine what data is being communicated by the sensor.
|
||||
This allows some differentiating use cases, where vendor can provide applications.
|
||||
Some common use cases are debug other sensors or to provide some events like
|
||||
keyboard attached/detached or lid open/close.
|
||||
|
||||
To allow application to utilize these sensors, here they are exported uses sysfs
|
||||
attribute groups, attributes and misc device interface.
|
||||
|
||||
An example of this representation on sysfs:
|
||||
/sys/devices/pci0000:00/INT33C2:00/i2c-0/i2c-INT33D1:00/0018:8086:09FA.0001/HID-SENSOR-2000e1.6.auto$ tree -R
|
||||
.
|
||||
????????? enable_sensor
|
||||
????????? feature-0-200316
|
||||
??????? ????????? feature-0-200316-maximum
|
||||
??????? ????????? feature-0-200316-minimum
|
||||
??????? ????????? feature-0-200316-name
|
||||
??????? ????????? feature-0-200316-size
|
||||
??????? ????????? feature-0-200316-unit-expo
|
||||
??????? ????????? feature-0-200316-units
|
||||
??????? ????????? feature-0-200316-value
|
||||
????????? feature-1-200201
|
||||
??????? ????????? feature-1-200201-maximum
|
||||
??????? ????????? feature-1-200201-minimum
|
||||
??????? ????????? feature-1-200201-name
|
||||
??????? ????????? feature-1-200201-size
|
||||
??????? ????????? feature-1-200201-unit-expo
|
||||
??????? ????????? feature-1-200201-units
|
||||
??????? ????????? feature-1-200201-value
|
||||
????????? input-0-200201
|
||||
??????? ????????? input-0-200201-maximum
|
||||
??????? ????????? input-0-200201-minimum
|
||||
??????? ????????? input-0-200201-name
|
||||
??????? ????????? input-0-200201-size
|
||||
??????? ????????? input-0-200201-unit-expo
|
||||
??????? ????????? input-0-200201-units
|
||||
??????? ????????? input-0-200201-value
|
||||
????????? input-1-200202
|
||||
??????? ????????? input-1-200202-maximum
|
||||
??????? ????????? input-1-200202-minimum
|
||||
??????? ????????? input-1-200202-name
|
||||
??????? ????????? input-1-200202-size
|
||||
??????? ????????? input-1-200202-unit-expo
|
||||
??????? ????????? input-1-200202-units
|
||||
??????? ????????? input-1-200202-value
|
||||
|
||||
Here there is a custom sensors with four fields, two feature and two inputs.
|
||||
Each field is represented by a set of attributes. All fields except the "value"
|
||||
are read only. The value field is a RW field.
|
||||
Example
|
||||
/sys/bus/platform/devices/HID-SENSOR-2000e1.6.auto/feature-0-200316$ grep -r . *
|
||||
feature-0-200316-maximum:6
|
||||
feature-0-200316-minimum:0
|
||||
feature-0-200316-name:property-reporting-state
|
||||
feature-0-200316-size:1
|
||||
feature-0-200316-unit-expo:0
|
||||
feature-0-200316-units:25
|
||||
feature-0-200316-value:1
|
||||
|
||||
How to enable such sensor?
|
||||
By default sensor can be power gated. To enable sysfs attribute "enable" can be
|
||||
used.
|
||||
$ echo 1 > enable_sensor
|
||||
|
||||
Once enabled and powered on, sensor can report value using HID reports.
|
||||
These reports are pushed using misc device interface in a FIFO order.
|
||||
/dev$ tree | grep HID-SENSOR-2000e1.6.auto
|
||||
??????? ????????? 10:53 -> ../HID-SENSOR-2000e1.6.auto
|
||||
????????? HID-SENSOR-2000e1.6.auto
|
||||
|
||||
Each reports can be of variable length preceded by a header. This header
|
||||
consist of a 32 bit usage id, 64 bit time stamp and 32 bit length field of raw
|
||||
data.
|
||||
|
||||
@@ -878,6 +878,21 @@ config HID_SENSOR_HUB
|
||||
for events and handle data streams. Each sensor driver can format
|
||||
data and present to user mode using input or IIO interface.
|
||||
|
||||
config HID_SENSOR_CUSTOM_SENSOR
|
||||
tristate "HID Sensors hub custom sensor support"
|
||||
depends on HID_SENSOR_HUB
|
||||
default n
|
||||
---help---
|
||||
HID Sensor hub specification allows definition of some custom and
|
||||
generic sensors. Unlike other HID sensors, they can't be exported
|
||||
via Linux IIO because of custom fields. This is up to the manufacturer
|
||||
to decide how to interpret these special sensor ids and process in
|
||||
the user space. Currently some manufacturers are using these ids for
|
||||
sensor calibration and debugging other sensors. Manufacturers
|
||||
should't use these special custom sensor ids to export any of the
|
||||
standard sensors.
|
||||
Select this config option for custom/generic sensor support.
|
||||
|
||||
endmenu
|
||||
|
||||
endif # HID
|
||||
|
||||
@@ -100,6 +100,7 @@ obj-$(CONFIG_HID_WACOM) += wacom.o
|
||||
obj-$(CONFIG_HID_WALTOP) += hid-waltop.o
|
||||
obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o
|
||||
obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o
|
||||
obj-$(CONFIG_HID_SENSOR_CUSTOM_SENSOR) += hid-sensor-custom.o
|
||||
|
||||
obj-$(CONFIG_USB_HID) += usbhid/
|
||||
obj-$(CONFIG_USB_MOUSE) += usbhid/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+123
-73
@@ -28,30 +28,11 @@
|
||||
|
||||
#define HID_SENSOR_HUB_ENUM_QUIRK 0x01
|
||||
|
||||
/**
|
||||
* struct sensor_hub_pending - Synchronous read pending information
|
||||
* @status: Pending status true/false.
|
||||
* @ready: Completion synchronization data.
|
||||
* @usage_id: Usage id for physical device, E.g. Gyro usage id.
|
||||
* @attr_usage_id: Usage Id of a field, E.g. X-AXIS for a gyro.
|
||||
* @raw_size: Response size for a read request.
|
||||
* @raw_data: Place holder for received response.
|
||||
*/
|
||||
struct sensor_hub_pending {
|
||||
bool status;
|
||||
struct completion ready;
|
||||
u32 usage_id;
|
||||
u32 attr_usage_id;
|
||||
int raw_size;
|
||||
u8 *raw_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sensor_hub_data - Hold a instance data for a HID hub device
|
||||
* @hsdev: Stored hid instance for current hub device.
|
||||
* @mutex: Mutex to serialize synchronous request.
|
||||
* @lock: Spin lock to protect pending request structure.
|
||||
* @pending: Holds information of pending sync read request.
|
||||
* @dyn_callback_list: Holds callback function
|
||||
* @dyn_callback_lock: spin lock to protect callback list
|
||||
* @hid_sensor_hub_client_devs: Stores all MFD cells for a hub instance.
|
||||
@@ -61,7 +42,6 @@ struct sensor_hub_pending {
|
||||
struct sensor_hub_data {
|
||||
struct mutex mutex;
|
||||
spinlock_t lock;
|
||||
struct sensor_hub_pending pending;
|
||||
struct list_head dyn_callback_list;
|
||||
spinlock_t dyn_callback_lock;
|
||||
struct mfd_cell *hid_sensor_hub_client_devs;
|
||||
@@ -106,7 +86,8 @@ static int sensor_hub_get_physical_device_count(struct hid_device *hdev)
|
||||
|
||||
for (i = 0; i < hdev->maxcollection; ++i) {
|
||||
struct hid_collection *collection = &hdev->collection[i];
|
||||
if (collection->type == HID_COLLECTION_PHYSICAL)
|
||||
if (collection->type == HID_COLLECTION_PHYSICAL ||
|
||||
collection->type == HID_COLLECTION_APPLICATION)
|
||||
++count;
|
||||
}
|
||||
|
||||
@@ -139,7 +120,8 @@ static struct hid_sensor_hub_callbacks *sensor_hub_get_callback(
|
||||
|
||||
spin_lock_irqsave(&pdata->dyn_callback_lock, flags);
|
||||
list_for_each_entry(callback, &pdata->dyn_callback_list, list)
|
||||
if (callback->usage_id == usage_id &&
|
||||
if ((callback->usage_id == usage_id ||
|
||||
callback->usage_id == HID_USAGE_SENSOR_COLLECTION) &&
|
||||
(collection_index >=
|
||||
callback->hsdev->start_collection_index) &&
|
||||
(collection_index <
|
||||
@@ -179,7 +161,18 @@ int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
|
||||
callback->usage_callback = usage_callback;
|
||||
callback->usage_id = usage_id;
|
||||
callback->priv = NULL;
|
||||
list_add_tail(&callback->list, &pdata->dyn_callback_list);
|
||||
/*
|
||||
* If there is a handler registered for the collection type, then
|
||||
* it will handle all reports for sensors in this collection. If
|
||||
* there is also an individual sensor handler registration, then
|
||||
* we want to make sure that the reports are directed to collection
|
||||
* handler, as this may be a fusion sensor. So add collection handlers
|
||||
* to the beginning of the list, so that they are matched first.
|
||||
*/
|
||||
if (usage_id == HID_USAGE_SENSOR_COLLECTION)
|
||||
list_add(&callback->list, &pdata->dyn_callback_list);
|
||||
else
|
||||
list_add_tail(&callback->list, &pdata->dyn_callback_list);
|
||||
spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags);
|
||||
|
||||
return 0;
|
||||
@@ -208,10 +201,14 @@ int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
|
||||
EXPORT_SYMBOL_GPL(sensor_hub_remove_callback);
|
||||
|
||||
int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
|
||||
u32 field_index, s32 value)
|
||||
u32 field_index, int buffer_size, void *buffer)
|
||||
{
|
||||
struct hid_report *report;
|
||||
struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev);
|
||||
__s32 *buf32 = buffer;
|
||||
int i = 0;
|
||||
int remaining_bytes;
|
||||
__s32 value;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
@@ -220,7 +217,21 @@ int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
|
||||
ret = -EINVAL;
|
||||
goto done_proc;
|
||||
}
|
||||
hid_set_field(report->field[field_index], 0, value);
|
||||
|
||||
remaining_bytes = do_div(buffer_size, sizeof(__s32));
|
||||
if (buffer_size) {
|
||||
for (i = 0; i < buffer_size; ++i) {
|
||||
hid_set_field(report->field[field_index], i,
|
||||
(__force __s32)cpu_to_le32(*buf32));
|
||||
++buf32;
|
||||
}
|
||||
}
|
||||
if (remaining_bytes) {
|
||||
value = 0;
|
||||
memcpy(&value, (u8 *)buf32, remaining_bytes);
|
||||
hid_set_field(report->field[field_index], i,
|
||||
(__force __s32)cpu_to_le32(value));
|
||||
}
|
||||
hid_hw_request(hsdev->hdev, report, HID_REQ_SET_REPORT);
|
||||
hid_hw_wait(hsdev->hdev);
|
||||
|
||||
@@ -232,10 +243,11 @@ done_proc:
|
||||
EXPORT_SYMBOL_GPL(sensor_hub_set_feature);
|
||||
|
||||
int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
|
||||
u32 field_index, s32 *value)
|
||||
u32 field_index, int buffer_size, void *buffer)
|
||||
{
|
||||
struct hid_report *report;
|
||||
struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev);
|
||||
int report_size;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
@@ -247,7 +259,17 @@ int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
|
||||
}
|
||||
hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT);
|
||||
hid_hw_wait(hsdev->hdev);
|
||||
*value = report->field[field_index]->value[0];
|
||||
|
||||
/* calculate number of bytes required to read this field */
|
||||
report_size = DIV_ROUND_UP(report->field[field_index]->report_size,
|
||||
8) *
|
||||
report->field[field_index]->report_count;
|
||||
if (!report_size) {
|
||||
ret = -EINVAL;
|
||||
goto done_proc;
|
||||
}
|
||||
ret = min(report_size, buffer_size);
|
||||
memcpy(buffer, report->field[field_index]->value, ret);
|
||||
|
||||
done_proc:
|
||||
mutex_unlock(&data->mutex);
|
||||
@@ -259,47 +281,54 @@ EXPORT_SYMBOL_GPL(sensor_hub_get_feature);
|
||||
|
||||
int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
|
||||
u32 usage_id,
|
||||
u32 attr_usage_id, u32 report_id)
|
||||
u32 attr_usage_id, u32 report_id,
|
||||
enum sensor_hub_read_flags flag)
|
||||
{
|
||||
struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev);
|
||||
unsigned long flags;
|
||||
struct hid_report *report;
|
||||
int ret_val = 0;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
memset(&data->pending, 0, sizeof(data->pending));
|
||||
init_completion(&data->pending.ready);
|
||||
data->pending.usage_id = usage_id;
|
||||
data->pending.attr_usage_id = attr_usage_id;
|
||||
data->pending.raw_size = 0;
|
||||
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
data->pending.status = true;
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
report = sensor_hub_report(report_id, hsdev->hdev, HID_INPUT_REPORT);
|
||||
report = sensor_hub_report(report_id, hsdev->hdev,
|
||||
HID_INPUT_REPORT);
|
||||
if (!report)
|
||||
goto err_free;
|
||||
return -EINVAL;
|
||||
|
||||
hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT);
|
||||
wait_for_completion_interruptible_timeout(&data->pending.ready, HZ*5);
|
||||
switch (data->pending.raw_size) {
|
||||
case 1:
|
||||
ret_val = *(u8 *)data->pending.raw_data;
|
||||
break;
|
||||
case 2:
|
||||
ret_val = *(u16 *)data->pending.raw_data;
|
||||
break;
|
||||
case 4:
|
||||
ret_val = *(u32 *)data->pending.raw_data;
|
||||
break;
|
||||
default:
|
||||
ret_val = 0;
|
||||
mutex_lock(&hsdev->mutex);
|
||||
if (flag == SENSOR_HUB_SYNC) {
|
||||
memset(&hsdev->pending, 0, sizeof(hsdev->pending));
|
||||
init_completion(&hsdev->pending.ready);
|
||||
hsdev->pending.usage_id = usage_id;
|
||||
hsdev->pending.attr_usage_id = attr_usage_id;
|
||||
hsdev->pending.raw_size = 0;
|
||||
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
hsdev->pending.status = true;
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
}
|
||||
kfree(data->pending.raw_data);
|
||||
|
||||
err_free:
|
||||
data->pending.status = false;
|
||||
mutex_lock(&data->mutex);
|
||||
hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT);
|
||||
mutex_unlock(&data->mutex);
|
||||
if (flag == SENSOR_HUB_SYNC) {
|
||||
wait_for_completion_interruptible_timeout(
|
||||
&hsdev->pending.ready, HZ*5);
|
||||
switch (hsdev->pending.raw_size) {
|
||||
case 1:
|
||||
ret_val = *(u8 *)hsdev->pending.raw_data;
|
||||
break;
|
||||
case 2:
|
||||
ret_val = *(u16 *)hsdev->pending.raw_data;
|
||||
break;
|
||||
case 4:
|
||||
ret_val = *(u32 *)hsdev->pending.raw_data;
|
||||
break;
|
||||
default:
|
||||
ret_val = 0;
|
||||
}
|
||||
kfree(hsdev->pending.raw_data);
|
||||
hsdev->pending.status = false;
|
||||
}
|
||||
mutex_unlock(&hsdev->mutex);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
@@ -455,16 +484,6 @@ static int sensor_hub_raw_event(struct hid_device *hdev,
|
||||
report->field[i]->report_count)/8);
|
||||
sz = (report->field[i]->report_size *
|
||||
report->field[i]->report_count)/8;
|
||||
if (pdata->pending.status && pdata->pending.attr_usage_id ==
|
||||
report->field[i]->usage->hid) {
|
||||
hid_dbg(hdev, "data was pending ...\n");
|
||||
pdata->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC);
|
||||
if (pdata->pending.raw_data)
|
||||
pdata->pending.raw_size = sz;
|
||||
else
|
||||
pdata->pending.raw_size = 0;
|
||||
complete(&pdata->pending.ready);
|
||||
}
|
||||
collection = &hdev->collection[
|
||||
report->field[i]->usage->collection_index];
|
||||
hid_dbg(hdev, "collection->usage %x\n",
|
||||
@@ -474,8 +493,23 @@ static int sensor_hub_raw_event(struct hid_device *hdev,
|
||||
report->field[i]->physical,
|
||||
report->field[i]->usage[0].collection_index,
|
||||
&hsdev, &priv);
|
||||
|
||||
if (callback && callback->capture_sample) {
|
||||
if (!callback) {
|
||||
ptr += sz;
|
||||
continue;
|
||||
}
|
||||
if (hsdev->pending.status && (hsdev->pending.attr_usage_id ==
|
||||
report->field[i]->usage->hid ||
|
||||
hsdev->pending.attr_usage_id ==
|
||||
report->field[i]->logical)) {
|
||||
hid_dbg(hdev, "data was pending ...\n");
|
||||
hsdev->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC);
|
||||
if (hsdev->pending.raw_data)
|
||||
hsdev->pending.raw_size = sz;
|
||||
else
|
||||
hsdev->pending.raw_size = 0;
|
||||
complete(&hsdev->pending.ready);
|
||||
}
|
||||
if (callback->capture_sample) {
|
||||
if (report->field[i]->logical)
|
||||
callback->capture_sample(hsdev,
|
||||
report->field[i]->logical, sz, ptr,
|
||||
@@ -572,6 +606,7 @@ static int sensor_hub_probe(struct hid_device *hdev,
|
||||
int dev_cnt;
|
||||
struct hid_sensor_hub_device *hsdev;
|
||||
struct hid_sensor_hub_device *last_hsdev = NULL;
|
||||
struct hid_sensor_hub_device *collection_hsdev = NULL;
|
||||
|
||||
sd = devm_kzalloc(&hdev->dev, sizeof(*sd), GFP_KERNEL);
|
||||
if (!sd) {
|
||||
@@ -618,7 +653,8 @@ static int sensor_hub_probe(struct hid_device *hdev,
|
||||
for (i = 0; i < hdev->maxcollection; ++i) {
|
||||
struct hid_collection *collection = &hdev->collection[i];
|
||||
|
||||
if (collection->type == HID_COLLECTION_PHYSICAL) {
|
||||
if (collection->type == HID_COLLECTION_PHYSICAL ||
|
||||
collection->type == HID_COLLECTION_APPLICATION) {
|
||||
|
||||
hsdev = devm_kzalloc(&hdev->dev, sizeof(*hsdev),
|
||||
GFP_KERNEL);
|
||||
@@ -630,6 +666,8 @@ static int sensor_hub_probe(struct hid_device *hdev,
|
||||
hsdev->hdev = hdev;
|
||||
hsdev->vendor_id = hdev->vendor;
|
||||
hsdev->product_id = hdev->product;
|
||||
hsdev->usage = collection->usage;
|
||||
mutex_init(&hsdev->mutex);
|
||||
hsdev->start_collection_index = i;
|
||||
if (last_hsdev)
|
||||
last_hsdev->end_collection_index = i;
|
||||
@@ -653,10 +691,17 @@ static int sensor_hub_probe(struct hid_device *hdev,
|
||||
hid_dbg(hdev, "Adding %s:%d\n", name,
|
||||
hsdev->start_collection_index);
|
||||
sd->hid_sensor_client_cnt++;
|
||||
if (collection_hsdev)
|
||||
collection_hsdev->end_collection_index = i;
|
||||
if (collection->type == HID_COLLECTION_APPLICATION &&
|
||||
collection->usage == HID_USAGE_SENSOR_COLLECTION)
|
||||
collection_hsdev = hsdev;
|
||||
}
|
||||
}
|
||||
if (last_hsdev)
|
||||
last_hsdev->end_collection_index = i;
|
||||
if (collection_hsdev)
|
||||
collection_hsdev->end_collection_index = i;
|
||||
|
||||
ret = mfd_add_hotplug_devices(&hdev->dev,
|
||||
sd->hid_sensor_hub_client_devs,
|
||||
@@ -676,13 +721,18 @@ static void sensor_hub_remove(struct hid_device *hdev)
|
||||
{
|
||||
struct sensor_hub_data *data = hid_get_drvdata(hdev);
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
hid_dbg(hdev, " hardware removed\n");
|
||||
hid_hw_close(hdev);
|
||||
hid_hw_stop(hdev);
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
if (data->pending.status)
|
||||
complete(&data->pending.ready);
|
||||
for (i = 0; i < data->hid_sensor_client_cnt; ++i) {
|
||||
struct hid_sensor_hub_device *hsdev =
|
||||
data->hid_sensor_hub_client_devs[i].platform_data;
|
||||
if (hsdev->pending.status)
|
||||
complete(&hsdev->pending.ready);
|
||||
}
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
mfd_remove_devices(&hdev->dev);
|
||||
hid_set_drvdata(hdev, NULL);
|
||||
|
||||
@@ -123,7 +123,8 @@ static int accel_3d_read_raw(struct iio_dev *indio_dev,
|
||||
*val = sensor_hub_input_attr_get_raw_value(
|
||||
accel_state->common_attributes.hsdev,
|
||||
HID_USAGE_SENSOR_ACCEL_3D, address,
|
||||
report_id);
|
||||
report_id,
|
||||
SENSOR_HUB_SYNC);
|
||||
else {
|
||||
*val = 0;
|
||||
hid_sensor_power_state(&accel_state->common_attributes,
|
||||
|
||||
@@ -153,8 +153,8 @@ s32 hid_sensor_read_poll_value(struct hid_sensor_common *st)
|
||||
int ret;
|
||||
|
||||
ret = sensor_hub_get_feature(st->hsdev,
|
||||
st->poll.report_id,
|
||||
st->poll.index, &value);
|
||||
st->poll.report_id,
|
||||
st->poll.index, sizeof(value), &value);
|
||||
|
||||
if (ret < 0 || value < 0) {
|
||||
return -EINVAL;
|
||||
@@ -174,8 +174,8 @@ int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st,
|
||||
int ret;
|
||||
|
||||
ret = sensor_hub_get_feature(st->hsdev,
|
||||
st->poll.report_id,
|
||||
st->poll.index, &value);
|
||||
st->poll.report_id,
|
||||
st->poll.index, sizeof(value), &value);
|
||||
if (ret < 0 || value < 0) {
|
||||
*val1 = *val2 = 0;
|
||||
return -EINVAL;
|
||||
@@ -212,9 +212,8 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st,
|
||||
else
|
||||
value = 0;
|
||||
}
|
||||
ret = sensor_hub_set_feature(st->hsdev,
|
||||
st->poll.report_id,
|
||||
st->poll.index, value);
|
||||
ret = sensor_hub_set_feature(st->hsdev, st->poll.report_id,
|
||||
st->poll.index, sizeof(value), &value);
|
||||
if (ret < 0 || value < 0)
|
||||
ret = -EINVAL;
|
||||
|
||||
@@ -229,8 +228,9 @@ int hid_sensor_read_raw_hyst_value(struct hid_sensor_common *st,
|
||||
int ret;
|
||||
|
||||
ret = sensor_hub_get_feature(st->hsdev,
|
||||
st->sensitivity.report_id,
|
||||
st->sensitivity.index, &value);
|
||||
st->sensitivity.report_id,
|
||||
st->sensitivity.index, sizeof(value),
|
||||
&value);
|
||||
if (ret < 0 || value < 0) {
|
||||
*val1 = *val2 = 0;
|
||||
return -EINVAL;
|
||||
@@ -253,9 +253,9 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st,
|
||||
value = convert_to_vtf_format(st->sensitivity.size,
|
||||
st->sensitivity.unit_expo,
|
||||
val1, val2);
|
||||
ret = sensor_hub_set_feature(st->hsdev,
|
||||
st->sensitivity.report_id,
|
||||
st->sensitivity.index, value);
|
||||
ret = sensor_hub_set_feature(st->hsdev, st->sensitivity.report_id,
|
||||
st->sensitivity.index, sizeof(value),
|
||||
&value);
|
||||
if (ret < 0 || value < 0)
|
||||
ret = -EINVAL;
|
||||
|
||||
|
||||
@@ -68,20 +68,21 @@ static int _hid_sensor_power_state(struct hid_sensor_common *st, bool state)
|
||||
if (state_val >= 0) {
|
||||
state_val += st->power_state.logical_minimum;
|
||||
sensor_hub_set_feature(st->hsdev, st->power_state.report_id,
|
||||
st->power_state.index,
|
||||
(s32)state_val);
|
||||
st->power_state.index, sizeof(state_val),
|
||||
&state_val);
|
||||
}
|
||||
|
||||
if (report_val >= 0) {
|
||||
report_val += st->report_state.logical_minimum;
|
||||
sensor_hub_set_feature(st->hsdev, st->report_state.report_id,
|
||||
st->report_state.index,
|
||||
(s32)report_val);
|
||||
st->report_state.index,
|
||||
sizeof(report_val),
|
||||
&report_val);
|
||||
}
|
||||
|
||||
sensor_hub_get_feature(st->hsdev, st->power_state.report_id,
|
||||
st->power_state.index,
|
||||
&state_val);
|
||||
st->power_state.index,
|
||||
sizeof(state_val), &state_val);
|
||||
if (state && poll_value)
|
||||
msleep_interruptible(poll_value * 2);
|
||||
|
||||
|
||||
@@ -123,7 +123,8 @@ static int gyro_3d_read_raw(struct iio_dev *indio_dev,
|
||||
*val = sensor_hub_input_attr_get_raw_value(
|
||||
gyro_state->common_attributes.hsdev,
|
||||
HID_USAGE_SENSOR_GYRO_3D, address,
|
||||
report_id);
|
||||
report_id,
|
||||
SENSOR_HUB_SYNC);
|
||||
else {
|
||||
*val = 0;
|
||||
hid_sensor_power_state(&gyro_state->common_attributes,
|
||||
|
||||
@@ -101,7 +101,8 @@ static int als_read_raw(struct iio_dev *indio_dev,
|
||||
*val = sensor_hub_input_attr_get_raw_value(
|
||||
als_state->common_attributes.hsdev,
|
||||
HID_USAGE_SENSOR_ALS, address,
|
||||
report_id);
|
||||
report_id,
|
||||
SENSOR_HUB_SYNC);
|
||||
hid_sensor_power_state(&als_state->common_attributes,
|
||||
false);
|
||||
} else {
|
||||
|
||||
@@ -96,7 +96,8 @@ static int prox_read_raw(struct iio_dev *indio_dev,
|
||||
*val = sensor_hub_input_attr_get_raw_value(
|
||||
prox_state->common_attributes.hsdev,
|
||||
HID_USAGE_SENSOR_PROX, address,
|
||||
report_id);
|
||||
report_id,
|
||||
SENSOR_HUB_SYNC);
|
||||
hid_sensor_power_state(&prox_state->common_attributes,
|
||||
false);
|
||||
} else {
|
||||
|
||||
@@ -170,7 +170,8 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev,
|
||||
*val = sensor_hub_input_attr_get_raw_value(
|
||||
magn_state->common_attributes.hsdev,
|
||||
HID_USAGE_SENSOR_COMPASS_3D, address,
|
||||
report_id);
|
||||
report_id,
|
||||
SENSOR_HUB_SYNC);
|
||||
else {
|
||||
*val = 0;
|
||||
hid_sensor_power_state(&magn_state->common_attributes,
|
||||
|
||||
@@ -124,7 +124,8 @@ static int incl_3d_read_raw(struct iio_dev *indio_dev,
|
||||
*val = sensor_hub_input_attr_get_raw_value(
|
||||
incl_state->common_attributes.hsdev,
|
||||
HID_USAGE_SENSOR_INCLINOMETER_3D, address,
|
||||
report_id);
|
||||
report_id,
|
||||
SENSOR_HUB_SYNC);
|
||||
else {
|
||||
hid_sensor_power_state(&incl_state->common_attributes,
|
||||
false);
|
||||
|
||||
@@ -100,7 +100,8 @@ static int press_read_raw(struct iio_dev *indio_dev,
|
||||
*val = sensor_hub_input_attr_get_raw_value(
|
||||
press_state->common_attributes.hsdev,
|
||||
HID_USAGE_SENSOR_PRESSURE, address,
|
||||
report_id);
|
||||
report_id,
|
||||
SENSOR_HUB_SYNC);
|
||||
hid_sensor_power_state(&press_state->common_attributes,
|
||||
false);
|
||||
} else {
|
||||
|
||||
@@ -213,7 +213,7 @@ static int hid_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
/* get a report with all values through requesting one value */
|
||||
sensor_hub_input_attr_get_raw_value(time_state->common_attributes.hsdev,
|
||||
HID_USAGE_SENSOR_TIME, hid_time_addresses[0],
|
||||
time_state->info[0].report_id);
|
||||
time_state->info[0].report_id, SENSOR_HUB_SYNC);
|
||||
/* wait for all values (event) */
|
||||
ret = wait_for_completion_killable_timeout(
|
||||
&time_state->comp_last_time, HZ*6);
|
||||
|
||||
@@ -48,20 +48,44 @@ struct hid_sensor_hub_attribute_info {
|
||||
s32 logical_maximum;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sensor_hub_pending - Synchronous read pending information
|
||||
* @status: Pending status true/false.
|
||||
* @ready: Completion synchronization data.
|
||||
* @usage_id: Usage id for physical device, E.g. Gyro usage id.
|
||||
* @attr_usage_id: Usage Id of a field, E.g. X-AXIS for a gyro.
|
||||
* @raw_size: Response size for a read request.
|
||||
* @raw_data: Place holder for received response.
|
||||
*/
|
||||
struct sensor_hub_pending {
|
||||
bool status;
|
||||
struct completion ready;
|
||||
u32 usage_id;
|
||||
u32 attr_usage_id;
|
||||
int raw_size;
|
||||
u8 *raw_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct hid_sensor_hub_device - Stores the hub instance data
|
||||
* @hdev: Stores the hid instance.
|
||||
* @vendor_id: Vendor id of hub device.
|
||||
* @product_id: Product id of hub device.
|
||||
* @usage: Usage id for this hub device instance.
|
||||
* @start_collection_index: Starting index for a phy type collection
|
||||
* @end_collection_index: Last index for a phy type collection
|
||||
* @mutex: synchronizing mutex.
|
||||
* @pending: Holds information of pending sync read request.
|
||||
*/
|
||||
struct hid_sensor_hub_device {
|
||||
struct hid_device *hdev;
|
||||
u32 vendor_id;
|
||||
u32 product_id;
|
||||
u32 usage;
|
||||
int start_collection_index;
|
||||
int end_collection_index;
|
||||
struct mutex mutex;
|
||||
struct sensor_hub_pending pending;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -152,40 +176,51 @@ int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
|
||||
* @usage_id: Attribute usage id of parent physical device as per spec
|
||||
* @attr_usage_id: Attribute usage id as per spec
|
||||
* @report_id: Report id to look for
|
||||
* @flag: Synchronous or asynchronous read
|
||||
*
|
||||
* Issues a synchronous read request for an input attribute. Returns
|
||||
* data upto 32 bits. Since client can get events, so this call should
|
||||
* not be used for data paths, this will impact performance.
|
||||
* Issues a synchronous or asynchronous read request for an input attribute.
|
||||
* Returns data upto 32 bits.
|
||||
*/
|
||||
|
||||
enum sensor_hub_read_flags {
|
||||
SENSOR_HUB_SYNC,
|
||||
SENSOR_HUB_ASYNC,
|
||||
};
|
||||
|
||||
int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
|
||||
u32 usage_id,
|
||||
u32 attr_usage_id, u32 report_id);
|
||||
u32 usage_id,
|
||||
u32 attr_usage_id, u32 report_id,
|
||||
enum sensor_hub_read_flags flag
|
||||
);
|
||||
|
||||
/**
|
||||
* sensor_hub_set_feature() - Feature set request
|
||||
* @hsdev: Hub device instance.
|
||||
* @report_id: Report id to look for
|
||||
* @field_index: Field index inside a report
|
||||
* @value: Value to set
|
||||
* @buffer_size: size of the buffer
|
||||
* @buffer: buffer to use in the feature set
|
||||
*
|
||||
* Used to set a field in feature report. For example this can set polling
|
||||
* interval, sensitivity, activate/deactivate state.
|
||||
*/
|
||||
int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
|
||||
u32 field_index, s32 value);
|
||||
u32 field_index, int buffer_size, void *buffer);
|
||||
|
||||
/**
|
||||
* sensor_hub_get_feature() - Feature get request
|
||||
* @hsdev: Hub device instance.
|
||||
* @report_id: Report id to look for
|
||||
* @field_index: Field index inside a report
|
||||
* @value: Place holder for return value
|
||||
* @buffer_size: size of the buffer
|
||||
* @buffer: buffer to copy output
|
||||
*
|
||||
* Used to get a field in feature report. For example this can get polling
|
||||
* interval, sensitivity, activate/deactivate state.
|
||||
* interval, sensitivity, activate/deactivate state. On success it returns
|
||||
* number of bytes copied to buffer. On failure, it returns value < 0.
|
||||
*/
|
||||
int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
|
||||
u32 field_index, s32 *value);
|
||||
u32 field_index, int buffer_size, void *buffer);
|
||||
|
||||
/* hid-sensor-attributes */
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
#define HID_MAX_PHY_DEVICES 0xFF
|
||||
|
||||
#define HID_USAGE_SENSOR_COLLECTION 0x200001
|
||||
|
||||
/* Accel 3D (200073) */
|
||||
#define HID_USAGE_SENSOR_ACCEL_3D 0x200073
|
||||
#define HID_USAGE_SENSOR_DATA_ACCELERATION 0x200452
|
||||
|
||||
Reference in New Issue
Block a user