* [PATCH, 1/7] HID-Sensors: Add Intel HID sensor
2012-06-06 15:39 [PATCH, 0/7] HID Sensor Driver srinivas pandruvada
@ 2012-06-06 15:39 ` srinivas pandruvada
2012-06-06 15:39 ` [PATCH, 2/7] HID-Sensors: Sensor framework srinivas pandruvada
` (5 subsequent siblings)
6 siblings, 0 replies; 16+ messages in thread
From: srinivas pandruvada @ 2012-06-06 15:39 UTC (permalink / raw)
To: linux-input; +Cc: linux-iio, srinivas pandruvada
Added Intel vendor id/product id and added in the list
for ignoring Intel vendor id/product id for HID.
Signed-off-by: srinivas pandruvada <srinivas.pandruvada@intel.com>
---
drivers/hid/hid-core.c | 6 ++++++
drivers/hid/hid-ids.h | 5 +++++
2 files changed, 11 insertions(+), 0 deletions(-)
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index f160aab..fad31c5 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1444,6 +1444,12 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6650) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ILITEK, USB_DEVICE_ID_ILITEK_MULTITOUCH) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086,
+ USB_DEVICE_ID_SENSOR_HUB_1020) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087,
+ USB_DEVICE_ID_SENSOR_HUB_09FA) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087,
+ USB_DEVICE_ID_SENSOR_HUB_09FA) },
{ HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 7409750..928fe57 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -401,6 +401,11 @@
#define USB_VENDOR_ID_IMATION 0x0718
#define USB_DEVICE_ID_DISC_STAKKA 0xd000
+#define USB_VENDOR_ID_INTEL_8086 0x8086
+#define USB_VENDOR_ID_INTEL_8087 0x8087
+#define USB_DEVICE_ID_SENSOR_HUB_1020 0x1020
+#define USB_DEVICE_ID_SENSOR_HUB_09FA 0x09FA
+
#define USB_VENDOR_ID_IRTOUCHSYSTEMS 0x6615
#define USB_DEVICE_ID_IRTOUCH_INFRARED_USB 0x0070
--
1.7.7.6
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH, 2/7] HID-Sensors: Sensor framework
2012-06-06 15:39 [PATCH, 0/7] HID Sensor Driver srinivas pandruvada
2012-06-06 15:39 ` [PATCH, 1/7] HID-Sensors: Add Intel HID sensor srinivas pandruvada
@ 2012-06-06 15:39 ` srinivas pandruvada
2012-06-06 15:39 ` [PATCH, 3/7] HID-Sensors: Common attributes and interfaces srinivas pandruvada
` (4 subsequent siblings)
6 siblings, 0 replies; 16+ messages in thread
From: srinivas pandruvada @ 2012-06-06 15:39 UTC (permalink / raw)
To: linux-input; +Cc: linux-iio, srinivas pandruvada
Adding processing for HID Sensor usage table as defined by
HID 1.12, Request #: HUTRR39, dated 05 May, 2011.
This driver uses HID driver framework to register, send and
receive events.
This delegated the actual usage id processing to different
modules, which are registered statically.
Signed-off-by: srinivas pandruvada <srinivas.pandruvada@intel.com>
---
drivers/staging/Kconfig | 2 +
drivers/staging/Makefile | 1 +
drivers/staging/hid-sensors/Kconfig | 19 +
drivers/staging/hid-sensors/Makefile | 9 +
drivers/staging/hid-sensors/hid-sensor-hub.c | 705 ++++++++++++++++++++
drivers/staging/hid-sensors/hid-sensor-ids.h | 117 ++++
drivers/staging/hid-sensors/hid-sensor-interface.h | 75 ++
7 files changed, 928 insertions(+), 0 deletions(-)
create mode 100644 drivers/staging/hid-sensors/Kconfig
create mode 100644 drivers/staging/hid-sensors/Makefile
create mode 100644 drivers/staging/hid-sensors/hid-sensor-hub.c
create mode 100644 drivers/staging/hid-sensors/hid-sensor-ids.h
create mode 100644 drivers/staging/hid-sensors/hid-sensor-interface.h
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 97d412d..562700a 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -80,6 +80,8 @@ source "drivers/staging/sep/Kconfig"
source "drivers/staging/iio/Kconfig"
+source "drivers/staging/hid-sensors/Kconfig"
+
source "drivers/staging/zram/Kconfig"
source "drivers/staging/zcache/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index ffe7d44..f53f0d4 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_VT6656) += vt6656/
obj-$(CONFIG_VME_BUS) += vme/
obj-$(CONFIG_DX_SEP) += sep/
obj-$(CONFIG_IIO) += iio/
+obj-$(CONFIG_HID_SENSORS) += hid-sensors/
obj-$(CONFIG_ZRAM) += zram/
obj-$(CONFIG_ZCACHE) += zcache/
obj-$(CONFIG_ZSMALLOC) += zsmalloc/
diff --git a/drivers/staging/hid-sensors/Kconfig b/drivers/staging/hid-sensors/Kconfig
new file mode 100644
index 0000000..be442f8
--- /dev/null
+++ b/drivers/staging/hid-sensors/Kconfig
@@ -0,0 +1,19 @@
+#
+# Sensor HUB subsytem configuration
+#
+
+menuconfig HID_SENSORS
+ tristate "HID Sensor Core"
+ select USB_HID
+ select IIO
+ select IIO_RING_BUFFER
+ select IIO_SW_RING
+ help
+ Support for HID Sensor hub based on HID 1.12 sensor usage table
+
+menuconfig HID_SENSOR_DEBUG
+ tristate "HID Sensor debug support"
+ depends on HID_SENSORS
+ default n
+ help
+ Debug support for Hid sensors
diff --git a/drivers/staging/hid-sensors/Makefile b/drivers/staging/hid-sensors/Makefile
new file mode 100644
index 0000000..13591b2
--- /dev/null
+++ b/drivers/staging/hid-sensors/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the HID Sensors.
+#
+ccflags-y += -Idrivers/hid
+ccflags-y += -Idrivers/staging
+ccflags-$(CONFIG_HID_SENSOR_DEBUG) += -DDEBUG
+
+hid-sensors-y := hid-sensor-hub.o
+obj-$(CONFIG_HID_SENSORS) += hid-sensors.o
diff --git a/drivers/staging/hid-sensors/hid-sensor-hub.c b/drivers/staging/hid-sensors/hid-sensor-hub.c
new file mode 100644
index 0000000..384e0d0
--- /dev/null
+++ b/drivers/staging/hid-sensors/hid-sensor-hub.c
@@ -0,0 +1,705 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/usb.h>
+#include "usbhid/usbhid.h"
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "hid-ids.h"
+#include "hid-sensor-ids.h"
+#include "hid-sensor-interface.h"
+
+#define RAW_BUFFER_SIZE 128
+#define sensor_hub_in_report(id, dev) sensor_hub_report(id, dev,\
+ HID_INPUT_REPORT)
+#define sensor_hub_out_report(id, dev) sensor_hub_report(id, dev,\
+ HID_OUTPUT_REPORT)
+#define sensor_hub_feature_report(id, dev) sensor_hub_report(id, dev,\
+ HID_FEATURE_REPORT)
+
+/* Description of in-progress IO operation, used for operations
+ * that trigger response from device */
+struct sensor_hub_pending {
+ struct completion ready;
+ u32 usage_id;
+ u32 attr_usage_id;
+ int raw_size;
+ u8 raw_data[RAW_BUFFER_SIZE];
+};
+
+struct sensor_hub_data {
+ struct hid_device *hdev;
+ struct mutex mutex;
+ spinlock_t lock;
+ struct sensor_hub_pending *pending;
+};
+
+struct sensor_hub_callbacks_list {
+ u32 usage_id;
+ struct sensor_hub_callbacks* (*reg_callback)(void);
+ int initialized;
+ void *priv;
+};
+
+static struct sensor_hub_callbacks_list usage_callbacks[] = {
+ {0}
+};
+
+/* Utility functions */
+
+static int sensor_hub_check_for_sensor_page(struct hid_device *hdev)
+{
+ int i;
+ int ret = -1;
+
+ for (i = 0; i < hdev->maxcollection; i++) {
+ struct hid_collection *col = &hdev->collection[i];
+ if (col->type == HID_COLLECTION_PHYSICAL &&
+ (col->usage & HID_USAGE_PAGE) == HID_UP_SENSOR) {
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+
+static struct hid_report *sensor_hub_report(int id, struct hid_device *hdev,
+ int dir)
+{
+ struct list_head *feature_report_list =
+ &hdev->report_enum[dir].report_list;
+ struct hid_report *report = NULL;
+
+ list_for_each_entry(report, feature_report_list, list) {
+ if (report->id == id)
+ return report;
+ }
+ hid_warn(hdev, "No report with id 0x%x found\n", id);
+ return NULL;
+}
+
+static struct sensor_hub_callbacks *sensor_hub_get_callback(u32 usage_id,
+ void **priv)
+{
+ int j;
+ struct sensor_hub_callbacks *callback = NULL;
+
+ j = 0;
+ while (usage_callbacks[j].usage_id != 0) {
+ if (usage_callbacks[j].initialized &&
+ usage_callbacks[j].usage_id == usage_id) {
+ callback = usage_callbacks[j].reg_callback();
+ *priv = usage_callbacks[j].priv;
+ break;
+ }
+ ++j;
+ }
+ return callback;
+}
+
+static int sensor_hub_init_callbacks(struct hid_device *hdev)
+{
+ int i, j;
+ int ret = 0;
+ struct sensor_hub_callbacks *callback;
+
+ for (i = 0; i < hdev->maxcollection; ++i) {
+ struct hid_collection *collection = &hdev->collection[i];
+ hid_dbg(hdev, "c:%d t:0x%x u:0x%x l:0x%x\n",
+ i, collection->type,
+ collection->usage, collection->level);
+ j = 0;
+ while (usage_callbacks[j].usage_id != 0) {
+ if (collection->usage == usage_callbacks[j].usage_id) {
+ callback = usage_callbacks[j].reg_callback();
+ ret = callback->enter(hdev, collection->usage,
+ &usage_callbacks[j].priv);
+ if (ret) {
+ hid_err(hdev, "Failed:usage id:0x%x\n",
+ collection->usage);
+ break;
+ }
+ usage_callbacks[j].initialized = 1;
+ }
+ ++j;
+ }
+ }
+ return ret;
+}
+
+#if (defined CONFIG_HID_SENSOR_DEBUG) || \
+ (defined CONFIG_HID_SENSOR_DEBUG_MODULE)
+static void dump_report(struct hid_device *hdev)
+{
+ int i, j;
+ struct hid_report *report;
+ struct hid_field *field;
+ struct hid_report_enum *report_enum;
+
+ hid_dbg(hdev, "Bus:0x%x Vendor:0x%x Product:0x%x\n", hdev->bus,
+ hdev->vendor, hdev->product);
+ hid_dbg(hdev, "rsize=%d, max_collections:%d\n", hdev->rsize,
+ hdev->maxcollection);
+ for (i = 0; i < hdev->maxcollection; ++i) {
+ struct hid_collection *collection = &hdev->collection[i];
+ hid_dbg(hdev, "c:%d t:0x%x u:0x%x l:0x%x\n",
+ i, collection->type, collection->usage,
+ collection->level);
+ }
+
+ hid_dbg(hdev, "report_enum[HID_INPUT_REPORT]\n");
+ report_enum = &hdev->report_enum[HID_INPUT_REPORT];
+ list_for_each_entry(report, &report_enum->report_list, list) {
+ hid_dbg(hdev, "Report id:%x\n", report->id);
+ for (i = 0; i < report->maxfield; ++i) {
+ field = report->field[i];
+ for (j = 0; j < field->maxusage; ++j) {
+ hid_dbg(hdev, "usage hid:%x c_index:%x\n",
+ field->usage[j].hid,
+ field->usage[j].collection_index);
+ }
+ hid_dbg(hdev, "units:%x expo:%x\n",
+ field->unit,
+ field->unit_exponent);
+ }
+ }
+
+ hid_dbg(hdev, "report_enum[HID_OUTPUT_REPORT]\n");
+ report_enum = &hdev->report_enum[HID_OUTPUT_REPORT];
+ list_for_each_entry(report, &report_enum->report_list, list) {
+ hid_dbg(hdev, "Report id:%x\n", report->id);
+ for (i = 0; i < report->maxfield; ++i) {
+ field = report->field[i];
+ for (j = 0; j < field->maxusage; ++j) {
+ hid_dbg(hdev, "usage hid:%x c_index:%x\n",
+ field->usage[j].hid,
+ field->usage[j].collection_index);
+ }
+ hid_dbg(hdev, "units:%x expo:%x\n",
+ field->unit,
+ field->unit_exponent);
+
+ }
+ }
+
+ hid_dbg(hdev, "report_enum[HID_FEATURE_REPORT]\n");
+ report_enum = &hdev->report_enum[HID_FEATURE_REPORT];
+ list_for_each_entry(report, &report_enum->report_list, list) {
+ hid_dbg(hdev, "Report id:%x\n", report->id);
+ for (i = 0; i < report->maxfield; ++i) {
+ field = report->field[i];
+ for (j = 0; j < field->maxusage; ++j) {
+ hid_dbg(hdev, "u hid:%x c_index:%x\n",
+ field->usage[j].hid,
+ field->usage[j].collection_index);
+ }
+ hid_dbg(hdev, "units:%x expo:%x\n",
+ field->unit,
+ field->unit_exponent);
+ }
+ }
+}
+
+static void dump_raw_data(struct hid_device *hdev, int size, u8 *pdata)
+{
+ int j = 0;
+
+ for (j = 0; j < size; ++j)
+ hid_dbg(hdev, "0x%x\n", *pdata++);
+}
+#endif
+
+int sensor_hub_set_feature(struct hid_device *hdev, u32 report_id,
+ u32 field_index, s32 value)
+{
+ struct hid_report *report;
+ struct sensor_hub_data *data = hid_get_drvdata(hdev);
+ int ret = 0;
+
+ mutex_lock(&data->mutex);
+ report = sensor_hub_feature_report(report_id, hdev);
+ if (!report) {
+ ret = -EINVAL;
+ goto done_proc;
+ }
+ if (field_index >= report->maxfield) {
+ ret = -EINVAL;
+ goto done_proc;
+ }
+ hid_set_field(report->field[field_index], 0, value);
+ usbhid_submit_report(hdev, report, USB_DIR_OUT);
+ usbhid_wait_io(hdev);
+done_proc:
+ mutex_unlock(&data->mutex);
+ return ret;
+}
+
+int sensor_hub_get_feature(struct hid_device *hdev, u32 report_id,
+ u32 field_index, s32 *value)
+{
+ struct hid_report *report;
+ struct sensor_hub_data *data = hid_get_drvdata(hdev);
+ int ret = 0;
+
+ mutex_lock(&data->mutex);
+ report = sensor_hub_feature_report(report_id, hdev);
+ if (!report) {
+ ret = -EINVAL;
+ goto done_proc;
+ }
+ if (field_index >= report->maxfield) {
+ ret = -EINVAL;
+ goto done_proc;
+ }
+ usbhid_submit_report(hdev, report, USB_DIR_IN);
+ usbhid_wait_io(hdev);
+ *value = report->field[field_index]->value[0];
+done_proc:
+ mutex_unlock(&data->mutex);
+ return ret;
+}
+
+static int sensor_hub_get_report_id(struct hid_device *hdev, u8 type,
+ u32 usage_id, u32 field_usage_id,
+ int *index)
+{
+ int ret = -1;
+ int i, j;
+ int collection_index = -1;
+ struct hid_report *report;
+ struct hid_field *field;
+ struct hid_report_enum *report_enum;
+
+ *index = 0;
+ for (i = 0; i < hdev->maxcollection; ++i) {
+ struct hid_collection *collection = &hdev->collection[i];
+ if (usage_id == collection->usage) {
+ collection_index = i;
+ break;
+ }
+ }
+ if (collection_index == -1)
+ goto err_ret;
+
+ report_enum = &hdev->report_enum[type];
+ list_for_each_entry(report, &report_enum->report_list, list) {
+ for (i = 0; i < report->maxfield; ++i) {
+ field = report->field[i];
+ for (j = 0; j < field->maxusage; ++j) {
+ if (field->usage[j].hid == field_usage_id &&
+ field->usage[j].collection_index ==
+ collection_index) {
+ *index = i;
+ ret = report->id;
+ hid_dbg(hdev, "Found usage hid\n");
+ hid_dbg(hdev, "r:%x id:%x c:%x f:%x\n",
+ ret, field->usage[j].hid,
+ field->usage[j].collection_index,
+ *index);
+ break;
+ }
+ }
+ }
+ }
+
+err_ret:
+ return ret;
+}
+
+/* Interface functions for sensor usage id clients */
+int sensor_hub_get_field_usage_index(struct hid_device *hdev, u32 *report_id,
+ u32 usage_id, u32 field_usage_id)
+{
+ int id;
+ int index = -1;
+
+ id = sensor_hub_get_report_id(hdev, HID_INPUT_REPORT, usage_id,
+ field_usage_id, &index);
+ if (id >= 0) {
+ *report_id = id;
+ goto done_proc;
+ }
+
+ id = sensor_hub_get_report_id(hdev, HID_OUTPUT_REPORT, usage_id,
+ field_usage_id, &index);
+ if (id >= 0) {
+ *report_id = id;
+ goto done_proc;
+ }
+
+ id = sensor_hub_get_report_id(hdev, HID_FEATURE_REPORT, usage_id,
+ field_usage_id, &index);
+ if (id >= 0) {
+ *report_id = id;
+ goto done_proc;
+ }
+
+done_proc:
+ return index;
+}
+
+ssize_t sensor_hub_input_attr_get_value(struct hid_device *hdev, u32 usage_id,
+ u32 attr_usage_id, u32 report_id,
+ u32 buf_len, u8 *buf)
+{
+ int len = -1;
+ struct sensor_hub_data *data = hid_get_drvdata(hdev);
+ struct sensor_hub_pending *work;
+ unsigned long flags;
+ struct hid_report *report;
+
+ work = kzalloc(sizeof(*work), GFP_KERNEL);
+ if (!work)
+ return len;
+
+ init_completion(&work->ready);
+ work->usage_id = usage_id;
+ work->attr_usage_id = attr_usage_id;
+ work->raw_size = 0;
+
+ mutex_lock(&data->mutex);
+ spin_lock_irqsave(&data->lock, flags);
+ data->pending = work;
+ report = sensor_hub_in_report(report_id, data->hdev);
+ if (!report)
+ goto err_free;
+ usbhid_submit_report(data->hdev, report, USB_DIR_IN);
+ spin_unlock_irqrestore(&data->lock, flags);
+ wait_for_completion_interruptible_timeout(&work->ready, HZ*5);
+ if (work->raw_size)
+ len = snprintf(buf, buf_len, "%x\n", *(u32 *)work->raw_data);
+
+err_free:
+ data->pending = NULL;
+ mutex_unlock(&data->mutex);
+
+ kfree(work);
+ return len;
+}
+
+
+int sensor_hub_input_get_attribute_info(struct hid_device *hdev , u8 type,
+ u32 usage_id,
+ u32 attr_usage_id,
+ struct hid_sensor_hub_attribute_info *info)
+{
+ int ret = -1;
+ int i, j;
+ int collection_index = -1;
+ struct hid_report *report;
+ struct hid_field *field;
+ struct hid_report_enum *report_enum;
+
+ /* Initialize with defaults */
+ info->usage_id = usage_id;
+ info->attrib_id = attr_usage_id;
+ info->report_id = -1;
+ info->index = -1;
+ info->units = -1;
+ info->unit_expo = -1;
+
+ for (i = 0; i < hdev->maxcollection; ++i) {
+ struct hid_collection *collection = &hdev->collection[i];
+ if (usage_id == collection->usage) {
+ collection_index = i;
+ break;
+ }
+ }
+ if (collection_index == -1)
+ goto err_ret;
+
+ report_enum = &hdev->report_enum[type];
+ list_for_each_entry(report, &report_enum->report_list, list) {
+ for (i = 0; i < report->maxfield; ++i) {
+ field = report->field[i];
+ for (j = 0; j < field->maxusage; ++j) {
+ if (field->usage[j].hid == attr_usage_id &&
+ field->usage[j].collection_index ==
+ collection_index) {
+ info->index = i;
+ info->report_id = report->id;
+ info->units = field->unit;
+ info->unit_expo = field->unit_exponent;
+ break;
+ }
+ }
+ }
+ }
+err_ret:
+ return ret;
+
+}
+
+#ifdef CONFIG_PM
+static int sensor_hub_suspend(struct hid_device *hdev, pm_message_t message)
+{
+ int j;
+ struct sensor_hub_callbacks *callback;
+
+ hid_dbg(hdev, " sensor_hub_suspend\n");
+ j = 0;
+ while (usage_callbacks[j].usage_id != 0) {
+ if (usage_callbacks[j].initialized) {
+ callback = usage_callbacks[j].reg_callback();
+ if (callback->suspend)
+ callback->suspend(hdev,
+ usage_callbacks[j].priv);
+ }
+ ++j;
+ }
+ return 0;
+}
+
+static int sensor_hub_resume(struct hid_device *hdev)
+{
+ int j;
+ struct sensor_hub_callbacks *callback;
+
+ hid_dbg(hdev, " sensor_hub_resume\n");
+ j = 0;
+ while (usage_callbacks[j].usage_id != 0) {
+ if (usage_callbacks[j].initialized) {
+ callback = usage_callbacks[j].reg_callback();
+ if (callback->resume)
+ callback->resume(hdev,
+ usage_callbacks[j].priv);
+ }
+ ++j;
+ }
+ return 0;
+}
+
+static int sensor_hub_reset_resume(struct hid_device *hdev)
+{
+ return 0;
+}
+#endif
+
+/*
+ * Handle raw report as sent by device
+ */
+static int sensor_hub_raw_event(struct hid_device *hdev,
+ struct hid_report *report, u8 *raw_data, int size)
+{
+ int i;
+ u8 *ptr;
+ int sz;
+ struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
+ unsigned long flags;
+ struct sensor_hub_callbacks *callback = NULL;
+ struct hid_collection *collection = NULL;
+ void *priv = NULL;
+
+ hid_dbg(hdev, "sensor_hub_raw_event report id:0x%x size:%d type:%d\n",
+ report->id, size, report->type);
+ hid_dbg(hdev, "maxfield:%d\n", report->maxfield);
+#if (defined CONFIG_HID_SENSOR_DEBUG) || \
+ (defined CONFIG_HID_SENSOR_DEBUG_MODULE)
+ dump_raw_data(hdev, size, raw_data);
+#endif
+ if (report->type != HID_INPUT_REPORT)
+ return 1;
+
+ ptr = raw_data;
+ ptr++; /*Skip report id*/
+
+ if (!report)
+ goto err_report;
+
+ spin_lock_irqsave(&pdata->lock, flags);
+
+ for (i = 0; i < report->maxfield; ++i) {
+
+ hid_dbg(hdev, "%d collection_index:%x hid:%x sz:%x\n",
+ i, report->field[i]->usage->collection_index,
+ report->field[i]->usage->hid,
+ report->field[i]->report_size/8);
+
+ sz = report->field[i]->report_size/8;
+ if (pdata->pending && pdata->pending->attr_usage_id ==
+ report->field[i]->usage->hid) {
+ hid_dbg(hdev, "data was pending ...\n");
+ sz = (sz > RAW_BUFFER_SIZE) ? RAW_BUFFER_SIZE : sz;
+ memcpy(pdata->pending->raw_data, ptr, sz);
+ pdata->pending->raw_size = sz;
+ complete(&pdata->pending->ready);
+ }
+ collection = &hdev->collection[
+ report->field[i]->usage->collection_index];
+ hid_dbg(hdev, "collection->usage %x\n",
+ collection->usage);
+ callback = sensor_hub_get_callback(collection->usage,
+ &priv);
+ if (callback && callback->capture_sample) {
+ callback->capture_sample(hdev,
+ report->field[i]->usage->hid, sz, ptr, priv);
+ }
+ ptr += sz;
+ }
+ if (callback && collection && callback->send_event)
+ callback->send_event(hdev, collection->usage, priv);
+
+ spin_unlock_irqrestore(&pdata->lock, flags);
+
+err_report:
+ return 1;
+}
+
+static int sensor_hub_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ int ret;
+ struct sensor_hub_data *sd;
+
+ sd = kzalloc(sizeof(struct sensor_hub_data), GFP_KERNEL);
+ if (!sd) {
+ hid_err(hdev, "cannot allocate Sensor data\n");
+ return -ENOMEM;
+ }
+ hid_set_drvdata(hdev, sd);
+ sd->hdev = hdev;
+ spin_lock_init(&sd->lock);
+ mutex_init(&sd->mutex);
+ ret = hid_parse(hdev);
+ if (ret) {
+ hid_err(hdev, "parse failed\n");
+ goto err_free;
+ }
+#if (defined CONFIG_HID_SENSOR_DEBUG) || \
+ (defined CONFIG_HID_SENSOR_DEBUG_MODULE)
+ dump_report(hdev);
+#endif
+ if (sensor_hub_check_for_sensor_page(hdev) < 0) {
+ hid_err(hdev, "sensor page not found\n");
+ goto err_free;
+ }
+ INIT_LIST_HEAD(&hdev->inputs);
+
+ hdev->claimed = HID_CLAIMED_INPUT;
+ ret = hid_hw_start(hdev, 0);
+ if (ret) {
+ hid_err(hdev, "hw start failed\n");
+ goto err_free;
+ }
+ ret = hid_hw_open(hdev);
+ if (ret) {
+ hid_hw_stop(hdev);
+ hid_err(hdev, "failed to open input interrupt pipe\n");
+ goto err_close;
+ }
+
+ ret = sensor_hub_init_callbacks(hdev);
+ if (ret < 0)
+ goto err_stop_hw;
+ return ret;
+
+err_close:
+ hid_hw_stop(hdev);
+err_stop_hw:
+ hid_hw_close(hdev);
+err_free:
+ kfree(sd);
+
+ return ret;
+}
+
+static void sensor_hub_remove(struct hid_device *hdev)
+{
+ struct sensor_hub_data *data = hid_get_drvdata(hdev);
+ unsigned long flags;
+ int j, ret;
+ struct sensor_hub_callbacks *callback;
+
+ hid_dbg(hdev, " hardware removed\n");
+
+ hdev->claimed &= ~HID_CLAIMED_INPUT;
+
+ hid_hw_stop(hdev);
+ hid_hw_close(hdev);
+
+ j = 0;
+ while (usage_callbacks[j].usage_id != 0) {
+ if (usage_callbacks[j].initialized) {
+ callback = usage_callbacks[j].reg_callback();
+ ret = callback->exit(hdev, usage_callbacks[j].priv);
+ if (ret) {
+ hid_err(hdev, "callback exit failed\n");
+ break;
+ }
+ }
+ ++j;
+ }
+
+ hid_set_drvdata(hdev, NULL);
+
+ spin_lock_irqsave(&data->lock, flags);
+ if (data->pending)
+ complete(&data->pending->ready);
+ spin_unlock_irqrestore(&data->lock, flags);
+
+ mutex_destroy(&data->mutex);
+ kfree(data);
+}
+
+static const struct hid_device_id sensor_hub_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086,
+ USB_DEVICE_ID_SENSOR_HUB_1020) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087,
+ USB_DEVICE_ID_SENSOR_HUB_09FA) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087,
+ USB_DEVICE_ID_SENSOR_HUB_09FA) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
+ USB_DEVICE_ID_SENSOR_HUB_7014) },
+ { }
+};
+
+static const struct hid_usage_id sensor_hub_grabbed_usages[] = {
+ { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
+ { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1 }
+};
+
+static struct hid_driver sensor_hub_driver = {
+ .name = "hid-sensor-hub",
+ .id_table = sensor_hub_devices,
+ .probe = sensor_hub_probe,
+ .remove = sensor_hub_remove,
+ .raw_event = sensor_hub_raw_event,
+#ifdef CONFIG_PM
+ .suspend = sensor_hub_suspend,
+ .resume = sensor_hub_resume,
+ .reset_resume = sensor_hub_reset_resume,
+#endif
+};
+
+static int __init sensor_hub_init(void)
+{
+ return hid_register_driver(&sensor_hub_driver);
+}
+
+static void __exit sensor_hub_exit(void)
+{
+ hid_unregister_driver(&sensor_hub_driver);
+}
+
+
+module_init(sensor_hub_init);
+module_exit(sensor_hub_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/hid-sensors/hid-sensor-ids.h b/drivers/staging/hid-sensors/hid-sensor-ids.h
new file mode 100644
index 0000000..553f366
--- /dev/null
+++ b/drivers/staging/hid-sensors/hid-sensor-ids.h
@@ -0,0 +1,117 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#ifndef _HID_SENSORS_IDS_H
+#define _HID_SENSORS_IDS_H
+
+#include "hid-ids.h"
+
+#define HID_UP_SENSOR 0x00200000
+#define HID_SENSOR_POLLING 0x0020030E
+#define HID_SENSOR_REPORT_STATE 0x00200316
+
+
+/* Accel 3D (200073) */
+#define HID_USAGE_SENSOR_ACCEL_3D 0x200073
+#define HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS 0x200453
+#define HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS 0x200454
+#define HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS 0x200455
+
+/* ALS (200041) */
+#define HID_USAGE_SENSOR_ALS 0x200041
+#define HID_USAGE_SENSOR_DATA_LIGHT_ILLUMINANCE 0x2004d1
+
+/* Compass 3D: (200083) */
+
+/* Gyro 3D: (200076) */
+#define HID_USAGE_SENSOR_GYRO_3D 0x200076
+#define HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_X_AXIS 0x200457
+#define HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_Y_AXIS 0x200458
+#define HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_Z_AXIS 0x200459
+
+/*ORIENTATION: Compass 3D: (200083) */
+#define HID_USAGE_SENSOR_COMPASS_3D 0x200083
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_HEADING 0x200471
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_HEADING_X 0x200472
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_HEADING_Y 0x200473
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_HEADING_Z 0x200474
+
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_COMPENSATED_MAGNETIC_NORTH 0x200475
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_COMPENSATED_TRUE_NORTH 0x200476
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_NORTH 0x200477
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_TRUE_NORTH 0x200478
+
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_DISTANCE 0x200479
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_DISTANCE_X 0x20047A
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_DISTANCE_Y 0x20047B
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_DISTANCE_Z 0x20047C
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_DISTANCE_OUT_OF_RANGE 0x20047D
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_TILT 0x20047E
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_TILT_X 0x20047F
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_TILT_Y 0x200480
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_TILT_Z 0x200481
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_ROTATION_MATRIX 0x200482
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_QUATERNION 0x200483
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX 0x200484
+
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_X_AXIS 0x200485
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Y_AXIS 0x200486
+#define HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Z_AXIS 0x200487
+
+/* Units */
+#define HID_USAGE_SENSOR_UNITS_NOT_SPECIFIED 0x00
+#define HID_USAGE_SENSOR_UNITS_LUX 0x01
+#define HID_USAGE_SENSOR_UNITS_KELVIN (0x01, 0x00, 0x01, 0x00)
+#define HID_USAGE_SENSOR_UNITS_FAHRENHEIT (0x03, 0x00, 0x01, 0x00)
+#define HID_USAGE_SENSOR_UNITS_PASCAL (0xF1, 0xE1)
+#define HID_USAGE_SENSOR_UNITS_NEWTON (0x11, 0xE1)
+#define HID_USAGE_SENSOR_UNITS_METERS_PER_SECOND (0x11, 0xF0)
+#define HID_USAGE_SENSOR_UNITS_METERS_PER_SEC_SQRD (0x11, 0xE0)
+#define HID_USAGE_SENSOR_UNITS_FARAD (0xE1, 0x4F, 0x20, 0x00)
+#define HID_USAGE_SENSOR_UNITS_AMPERE (0x01, 0x00, 0x10, 0x00)
+#define HID_USAGE_SENSOR_UNITS_WATT (0x21, 0xd1)
+#define HID_USAGE_SENSOR_UNITS_HENRY (0x21, 0xE1, 0xE0, 0x00)
+#define HID_USAGE_SENSOR_UNITS_OHM (0x21, 0xD1, 0xE0, 0x00)
+#define HID_USAGE_SENSOR_UNITS_VOLT (0x21, 0xD1, 0xF0, 0x00)
+#define HID_USAGE_SENSOR_UNITS_HERTZ (0x01, 0xF0)
+#define HID_USAGE_SENSOR_UNITS_DEGREES_PER_SEC_SQRD (0x14, 0xE0)
+#define HID_USAGE_SENSOR_UNITS_RADIANS 0x12
+#define HID_USAGE_SENSOR_UNITS_RADIANS_PER_SECOND (0x12, 0xF0)
+#define HID_USAGE_SENSOR_UNITS_RADIANS_PER_SEC_SQRD (0x12, 0xE0)
+#define HID_USAGE_SENSOR_UNITS_SECOND (0x01, 0x10)
+#define HID_USAGE_SENSOR_UNITS_GAUSS (0x01, 0xE1, 0xF0, 0x00)
+#define HID_USAGE_SENSOR_UNITS_GRAM (0x01, 0x01)
+#define HID_USAGE_SENSOR_UNITS_CENTIMETER 0x11
+#define HID_USAGE_SENSOR_UNITS_G 0x1A
+#define HID_USAGE_SENSOR_UNITS_MILLISECOND 0x19
+#define HID_USAGE_SENSOR_UNITS_PERCENT 0x17
+#define HID_USAGE_SENSOR_UNITS_DEGREES 0x14
+#define HID_USAGE_SENSOR_UNITS_DEGREES_PER_SECOND 0x15
+
+/* Common selectors */
+#define HID_USAGE_SENSOR_PROPERTY_REPORT_INTERVAL 0x20030E
+#define HID_USAGE_SENSOR_PROPERTY_CHANGE_SENSITIVITY_ABS 0x20030F
+#define HID_USAGE_SENSOR_PROPERTY_CHANGE_SENSITIVITY_RANGE_PCT 0x200310
+#define HID_USAGE_SENSOR_PROPERTY_CHANGE_SENSITIVITY_REL_PCT 0x200311
+#define HID_USAGE_SENSOR_PROPERTY_ACCURACY 0x200312
+#define HID_USAGE_SENSOR_PROPERTY_RESOLUTION 0x200313
+#define HID_USAGE_SENSOR_PROPERTY_RANGE_MAXIMUM 0x200314
+#define HID_USAGE_SENSOR_PROPERTY_RANGE_MINIMUM 0x200315
+#define HID_USAGE_SENSOR_PROPERTY_REPORTING_STATE 0x200316
+
+#endif
diff --git a/drivers/staging/hid-sensors/hid-sensor-interface.h b/drivers/staging/hid-sensors/hid-sensor-interface.h
new file mode 100644
index 0000000..18a2e09
--- /dev/null
+++ b/drivers/staging/hid-sensors/hid-sensor-interface.h
@@ -0,0 +1,75 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#ifndef _HID_SENSORS_INTERFACE_H
+#define _HID_SENSORS_INTERFACE_H
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/usb.h>
+#include "usbhid/usbhid.h"
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "iio/iio.h"
+#include "iio/sysfs.h"
+#include "iio/ring_sw.h"
+#include "iio/trigger.h"
+
+struct hid_sensor_hub_attribute_info {
+ u32 usage_id;
+ u32 attrib_id;
+ s32 report_id;
+ s32 index;
+ s32 units;
+ s32 unit_expo;
+};
+
+struct hid_sensor_attributes {
+ struct hid_device *hdev;
+ unsigned usage_id;
+ bool data_ready;
+ struct hid_sensor_hub_attribute_info poll;
+ struct hid_sensor_hub_attribute_info activate;
+ struct hid_sensor_hub_attribute_info sensitivity;
+ void *private;
+};
+
+struct sensor_hub_callbacks {
+ int (*enter)(struct hid_device *hdev, u32 usage_id, void **priv);
+ int (*exit)(struct hid_device *hdev, void *priv);
+ int (*suspend)(struct hid_device *hdev, void *priv);
+ int (*resume)(struct hid_device *hdev, void *priv);
+ int (*capture_sample)(struct hid_device *hdev, u32 usage_id,
+ size_t raw_len, char *raw_data, void *priv);
+ int (*send_event)(struct hid_device *hdev, u32 usage_id, void *priv);
+};
+
+/* Hid sensor hub core interfaces */
+int sensor_hub_input_get_attribute_info(struct hid_device *hdev, u8 type,
+ u32 usage_id, u32 attr_usage_id,
+ struct hid_sensor_hub_attribute_info *info);
+int sensor_hub_set_feature(struct hid_device *dev, u32 report_id,
+ u32 field_index, s32 value);
+int sensor_hub_get_feature(struct hid_device *hdev, u32 report_id,
+ u32 field_index, s32 *value);
+ssize_t sensor_hub_input_attr_get_value(struct hid_device *hdev, u32 usage_id,
+ u32 attr_usage_id, u32 report_id,
+ u32 buf_len, u8 *buf);
+int sensor_hub_input_get_unit_expo(struct hid_device *hdev, u32 field_usage_id,
+ s32 *unit, s32 *unit_expo);
+#endif
--
1.7.7.6
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH, 3/7] HID-Sensors: Common attributes and interfaces
2012-06-06 15:39 [PATCH, 0/7] HID Sensor Driver srinivas pandruvada
2012-06-06 15:39 ` [PATCH, 1/7] HID-Sensors: Add Intel HID sensor srinivas pandruvada
2012-06-06 15:39 ` [PATCH, 2/7] HID-Sensors: Sensor framework srinivas pandruvada
@ 2012-06-06 15:39 ` srinivas pandruvada
2012-06-07 7:54 ` Jonathan Cameron
2012-06-06 15:39 ` [PATCH, 4/7] HID-Sensors: Added accelerometer 3D srinivas pandruvada
` (3 subsequent siblings)
6 siblings, 1 reply; 16+ messages in thread
From: srinivas pandruvada @ 2012-06-06 15:39 UTC (permalink / raw)
To: linux-input; +Cc: linux-iio, Srinivas pandruvada
From: Srinivas pandruvada <srinivas.pandruvada@intel.com>
Added IIO Ring interface and trigger functions, which can be
used by all sensors. In addition a set of interface functions
for setting common attributes for all sensors like polling
interval, sensitivity and activate etc.
Signed-off-by: Srinivas pandruvada <srinivas.pandruvada@intel.com>
---
drivers/staging/hid-sensors/Makefile | 3 +
.../staging/hid-sensors/hid-sensor-attributes.c | 203 ++++++++++++++++++++
.../staging/hid-sensors/hid-sensor-attributes.h | 67 +++++++
drivers/staging/hid-sensors/hid-sensor-interface.h | 12 ++
drivers/staging/hid-sensors/hid-sensor-ring.c | 104 ++++++++++
drivers/staging/hid-sensors/hid-sensor-trigger.c | 81 ++++++++
6 files changed, 470 insertions(+), 0 deletions(-)
create mode 100644 drivers/staging/hid-sensors/hid-sensor-attributes.c
create mode 100644 drivers/staging/hid-sensors/hid-sensor-attributes.h
create mode 100644 drivers/staging/hid-sensors/hid-sensor-ring.c
create mode 100644 drivers/staging/hid-sensors/hid-sensor-trigger.c
diff --git a/drivers/staging/hid-sensors/Makefile b/drivers/staging/hid-sensors/Makefile
index 13591b2..9a03953 100644
--- a/drivers/staging/hid-sensors/Makefile
+++ b/drivers/staging/hid-sensors/Makefile
@@ -6,4 +6,7 @@ ccflags-y += -Idrivers/staging
ccflags-$(CONFIG_HID_SENSOR_DEBUG) += -DDEBUG
hid-sensors-y := hid-sensor-hub.o
+hid-sensors-y += hid-sensor-attributes.o
+hid-sensors-y += hid-sensor-ring.o
+hid-sensors-y += hid-sensor-trigger.o
obj-$(CONFIG_HID_SENSORS) += hid-sensors.o
diff --git a/drivers/staging/hid-sensors/hid-sensor-attributes.c b/drivers/staging/hid-sensors/hid-sensor-attributes.c
new file mode 100644
index 0000000..6f07d50
--- /dev/null
+++ b/drivers/staging/hid-sensors/hid-sensor-attributes.c
@@ -0,0 +1,203 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "iio/iio.h"
+#include "iio/sysfs.h"
+#include "hid-sensor-ids.h"
+#include "hid-sensor-interface.h"
+
+ssize_t hid_sensor_read_poll_interval(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ __s32 value;
+ int len;
+ int ret;
+
+ ret = sensor_hub_get_feature(st->hdev,
+ st->poll.report_id,
+ st->poll.index, &value);
+ if (ret < 0 || value < 0)
+ len = sprintf(buf, "0\n");
+ else
+ len = sprintf(buf, "units:0x%2x,exp:0x%x,value:0x%2x\n",
+ st->poll.units, st->poll.unit_expo, value);
+ return len;
+}
+
+
+ssize_t hid_sensor_write_poll_interval(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ long int value;
+ int ret;
+
+ if (kstrtol(buf, 10, &value) < 0)
+ return -EINVAL;
+
+ if (value <= 0)
+ value = 0;
+
+ ret = sensor_hub_set_feature(st->hdev,
+ st->poll.report_id,
+ st->poll.index,
+ value);
+
+ if (ret < 0)
+ return ret;
+ return strlen(buf);
+
+}
+
+ssize_t hid_sensor_read_report_state(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ long int value;
+ int len;
+ int ret;
+
+ ret = sensor_hub_get_feature(st->hdev,
+ st->activate.report_id,
+ st->activate.index, (s32 *)&value);
+ if (ret < 0 || value < 0)
+ len = sprintf(buf, "0\n");
+ else
+ len = sprintf(buf, "units:0x%2x,exp:0x%x,value:0x%2x\n",
+ st->activate.units, st->activate.unit_expo,
+ (unsigned int)value);
+ return len;
+
+}
+
+ssize_t hid_sensor_write_report_state(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ int ret;
+ long int value;
+
+ if (kstrtol(buf, 10, &value) < 0)
+ return -EINVAL;
+
+ ret = sensor_hub_set_feature(st->hdev, st->activate.report_id,
+ st->activate.index,
+ (s32)value);
+ if (ret < 0)
+ return ret;
+
+ return strlen(buf);
+}
+
+ssize_t hid_sensor_read_sensitivity(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ __s32 value;
+ int len;
+ int ret;
+
+ ret = sensor_hub_get_feature(st->hdev,
+ st->sensitivity.report_id,
+ st->sensitivity.index, &value);
+ if (ret < 0 || value < 0)
+ len = sprintf(buf, "0\n");
+ else
+ len = sprintf(buf, "units:0x%2x,exp:0x%x,value:0x%2x\n",
+ st->sensitivity.units,
+ st->sensitivity.unit_expo, value);
+ return len;
+}
+
+
+ssize_t hid_sensor_write_sensitivity(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ long int value;
+ int ret;
+
+ if (kstrtol(buf, 10, &value) < 0)
+ return -EINVAL;
+
+ if (value <= 0)
+ value = 0;
+
+ ret = sensor_hub_set_feature(st->hdev,
+ st->sensitivity.report_id,
+ st->sensitivity.index,
+ value);
+
+ if (ret < 0)
+ return ret;
+
+ return strlen(buf);
+}
+
+
+
+int hid_sensor_parse_common_attributes(struct hid_device *hdev, u32 usage_id,
+ struct hid_sensor_attributes *st)
+{
+ int ret;
+
+ ret = sensor_hub_input_get_attribute_info(hdev,
+ HID_FEATURE_REPORT, usage_id,
+ HID_SENSOR_POLLING, &st->poll);
+
+ ret = sensor_hub_input_get_attribute_info(hdev,
+ HID_FEATURE_REPORT, usage_id,
+ HID_SENSOR_REPORT_STATE,
+ &st->activate);
+
+ ret = sensor_hub_input_get_attribute_info(hdev,
+ HID_FEATURE_REPORT, usage_id,
+ HID_USAGE_SENSOR_PROPERTY_CHANGE_SENSITIVITY_ABS,
+ &st->sensitivity);
+
+ hid_dbg(hdev, "common attributes: %x:%x, %x:%x, %x:%x\n",
+ st->poll.index, st->poll.report_id,
+ st->activate.index, st->activate.report_id,
+ st->sensitivity.index, st->sensitivity.report_id);
+
+ return 0;
+}
diff --git a/drivers/staging/hid-sensors/hid-sensor-attributes.h b/drivers/staging/hid-sensors/hid-sensor-attributes.h
new file mode 100644
index 0000000..b1f4ac9
--- /dev/null
+++ b/drivers/staging/hid-sensors/hid-sensor-attributes.h
@@ -0,0 +1,67 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#ifndef _HID_SENSORS_ATTRIBUTES_H
+#define _HID_SENSORS_ATTRIBUTES_H
+
+/* Common sysfs attributes for HID sensors */
+
+int hid_sensor_parse_common_attributes(struct hid_device *hdev, u32 usage_id,
+ struct hid_sensor_attributes *st);
+
+ssize_t hid_sensor_read_poll_interval(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+ssize_t hid_sensor_write_poll_interval(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len);
+
+ssize_t hid_sensor_read_report_state(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+ssize_t hid_sensor_write_report_state(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len);
+ssize_t hid_sensor_read_sensitivity(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+ssize_t hid_sensor_write_sensitivity(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len);
+
+
+#define IIO_DEV_ATTR_POLL_INTERVAL(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(poll_interval, _mode, _show, _store, _addr)
+#define IIO_DEV_ATTR_SENSITIVITY(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(sensitivity, _mode, _show, _store, _addr)
+#define IIO_DEV_ATTR_REPORT_STATE(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(activate, _mode, _show, _store, _addr)
+
+static IIO_DEV_ATTR_POLL_INTERVAL(S_IWUSR | S_IRUSR,
+ hid_sensor_read_poll_interval,
+ hid_sensor_write_poll_interval,
+ HID_SENSOR_POLLING);
+static IIO_DEV_ATTR_SENSITIVITY(S_IWUSR | S_IRUSR,
+ hid_sensor_read_sensitivity,
+ hid_sensor_write_sensitivity,
+ HID_USAGE_SENSOR_PROPERTY_CHANGE_SENSITIVITY_ABS);
+static IIO_DEV_ATTR_REPORT_STATE(S_IWUSR | S_IRUSR,
+ hid_sensor_read_report_state,
+ hid_sensor_write_report_state,
+ HID_SENSOR_REPORT_STATE);
+#endif
diff --git a/drivers/staging/hid-sensors/hid-sensor-interface.h b/drivers/staging/hid-sensors/hid-sensor-interface.h
index 18a2e09..477494f 100644
--- a/drivers/staging/hid-sensors/hid-sensor-interface.h
+++ b/drivers/staging/hid-sensors/hid-sensor-interface.h
@@ -72,4 +72,16 @@ ssize_t sensor_hub_input_attr_get_value(struct hid_device *hdev, u32 usage_id,
u32 buf_len, u8 *buf);
int sensor_hub_input_get_unit_expo(struct hid_device *hdev, u32 field_usage_id,
s32 *unit, s32 *unit_expo);
+
+/* Common IIO Ring Processing Functions */
+int hid_sensor_configure_ring(struct iio_dev *indio_dev);
+void hid_sensor_ring_cleanup(struct iio_dev *indio_dev);
+void hid_sensor_ring_set_datum_size(struct iio_dev *indio_dev, int size);
+void hid_sensor_push_data_to_ring(struct iio_dev *indio_dev, u8 *data,
+ int len);
+
+/* Trigger functions */
+int hid_sensor_setup_trigger(struct iio_dev *indio_dev, char *name);
+void hid_sensor_remove_trigger(struct iio_dev *indio_dev);
+
#endif
diff --git a/drivers/staging/hid-sensors/hid-sensor-ring.c b/drivers/staging/hid-sensors/hid-sensor-ring.c
new file mode 100644
index 0000000..c63ff26
--- /dev/null
+++ b/drivers/staging/hid-sensors/hid-sensor-ring.c
@@ -0,0 +1,104 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "iio/iio.h"
+#include "iio/sysfs.h"
+#include "iio/ring_sw.h"
+#include "iio/trigger_consumer.h"
+#include "iio/trigger.h"
+
+static const struct iio_buffer_setup_ops hid_sensors_buffer_setup_ops = {
+ .preenable = &iio_sw_buffer_preenable,
+ .postenable = &iio_triggered_buffer_postenable,
+ .predisable = &iio_triggered_buffer_predisable,
+};
+
+static irqreturn_t hid_sensor_trigger_handler(int irq, void *p)
+{
+ return IRQ_HANDLED;
+}
+
+void hid_sensor_push_data_to_ring(struct iio_dev *indio_dev, u8 *data, int len)
+{
+ struct iio_buffer *ring = indio_dev->buffer;
+ s64 timestamp = iio_get_time_ns();
+ int datum_sz;
+
+ if (!ring)
+ return;
+ datum_sz = ring->access->get_bytes_per_datum(ring);
+ if (len > datum_sz) {
+ dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len,
+ datum_sz);
+ return;
+ } else if (datum_sz > 0 && datum_sz != len) {
+ dev_dbg(&indio_dev->dev, "Updating Datum size%d:%d\n", len,
+ datum_sz);
+ if (ring->access->set_bytes_per_datum)
+ ring->access->set_bytes_per_datum(ring, len);
+ }
+
+
+ ring->access->store_to(ring, (u8 *)data, timestamp);
+}
+
+int hid_sensor_configure_ring(struct iio_dev *indio_dev)
+{
+ struct iio_buffer *ring;
+ int ret = 0;
+
+ ring = iio_sw_rb_allocate(indio_dev);
+ if (!ring)
+ return -ENOMEM;
+
+ ring->scan_timestamp = true;
+ indio_dev->buffer = ring;
+ indio_dev->setup_ops = &hid_sensors_buffer_setup_ops;
+
+ indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
+ &hid_sensor_trigger_handler,
+ IRQF_ONESHOT,
+ indio_dev,
+ "hid_sensor%d",
+ indio_dev->id);
+ if (indio_dev->pollfunc == NULL) {
+ ret = -ENOMEM;
+ goto error_iio_free;
+ }
+
+ indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
+
+ return ret;
+error_iio_free:
+ iio_sw_rb_free(indio_dev->buffer);
+ return ret;
+}
+
+void hid_sensor_ring_cleanup(struct iio_dev *indio_dev)
+{
+ iio_sw_rb_free(indio_dev->buffer);
+}
diff --git a/drivers/staging/hid-sensors/hid-sensor-trigger.c b/drivers/staging/hid-sensors/hid-sensor-trigger.c
new file mode 100644
index 0000000..49d8740
--- /dev/null
+++ b/drivers/staging/hid-sensors/hid-sensor-trigger.c
@@ -0,0 +1,81 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/usb.h>
+#include "usbhid/usbhid.h"
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "iio/iio.h"
+#include "iio/trigger.h"
+#include "hid-sensor-interface.h"
+
+static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
+ bool state)
+{
+ struct iio_dev *indio_dev = trig->private_data;
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+
+
+ st->data_ready = state;
+
+ return 0;
+}
+
+void hid_sensor_remove_trigger(struct iio_dev *indio_dev)
+{
+ if (indio_dev->trig) {
+ iio_trigger_unregister(indio_dev->trig);
+ iio_free_trigger(indio_dev->trig);
+ }
+}
+
+static const struct iio_trigger_ops hid_sensor_trigger_ops = {
+ .owner = THIS_MODULE,
+ .set_trigger_state = &hid_sensor_data_rdy_trigger_set_state,
+};
+
+int hid_sensor_setup_trigger(struct iio_dev *indio_dev, char *name)
+{
+ int ret;
+ struct iio_trigger *trig;
+
+ trig = iio_allocate_trigger("%s-dev%d", name, indio_dev->id);
+ if (trig == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ trig->dev.parent = indio_dev->dev.parent;
+ trig->private_data = (void *)indio_dev;
+ trig->ops = &hid_sensor_trigger_ops;
+ ret = iio_trigger_register(trig);
+
+ /* select default trigger */
+ indio_dev->trig = trig;
+ if (ret)
+ goto error_free_trig;
+
+ return ret;
+
+error_free_trig:
+ iio_free_trigger(trig);
+error_ret:
+ return ret;
+}
--
1.7.7.6
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH, 3/7] HID-Sensors: Common attributes and interfaces
2012-06-06 15:39 ` [PATCH, 3/7] HID-Sensors: Common attributes and interfaces srinivas pandruvada
@ 2012-06-07 7:54 ` Jonathan Cameron
0 siblings, 0 replies; 16+ messages in thread
From: Jonathan Cameron @ 2012-06-07 7:54 UTC (permalink / raw)
To: srinivas pandruvada; +Cc: linux-input, linux-iio
On 6/6/2012 4:39 PM, srinivas pandruvada wrote:
> From: Srinivas pandruvada<srinivas.pandruvada@intel.com>
>
> Added IIO Ring interface and trigger functions, which can be
> used by all sensors. In addition a set of interface functions
> for setting common attributes for all sensors like polling
> interval, sensitivity and activate etc.
Couple of quick points as I'm probably not going to get time to review
this today.
ring_sw is pretty certain to go away - please switch to kfifo. You may
need the poll patch I sent out the other day...
We have a fairly tight abi definition. Now it can be
extended of course, but only with a very good reason. Quite
a few of your elements really don't conform to it.
I'm not yet sure how to handle the fact these devices are outputing
a very unusual form of floating point (actually I suspect almost
none of them them actually use that) Perhaps a useful exercise is
for you to list some examples of the formats that are actually found
in devices? If we have to support true floating point then we will
but it is going to be very painful.
Probably the most important element of IIO (and any other subsystem)
is generality. Hence drivers often need to blugeon data into the formats
that are expected.
Few quick comments inline.
>
> Signed-off-by: Srinivas pandruvada<srinivas.pandruvada@intel.com>
> ---
> drivers/staging/hid-sensors/Makefile | 3 +
> .../staging/hid-sensors/hid-sensor-attributes.c | 203 ++++++++++++++++++++
> .../staging/hid-sensors/hid-sensor-attributes.h | 67 +++++++
> drivers/staging/hid-sensors/hid-sensor-interface.h | 12 ++
> drivers/staging/hid-sensors/hid-sensor-ring.c | 104 ++++++++++
> drivers/staging/hid-sensors/hid-sensor-trigger.c | 81 ++++++++
> 6 files changed, 470 insertions(+), 0 deletions(-)
> create mode 100644 drivers/staging/hid-sensors/hid-sensor-attributes.c
> create mode 100644 drivers/staging/hid-sensors/hid-sensor-attributes.h
> create mode 100644 drivers/staging/hid-sensors/hid-sensor-ring.c
> create mode 100644 drivers/staging/hid-sensors/hid-sensor-trigger.c
>
> diff --git a/drivers/staging/hid-sensors/Makefile b/drivers/staging/hid-sensors/Makefile
> index 13591b2..9a03953 100644
> --- a/drivers/staging/hid-sensors/Makefile
> +++ b/drivers/staging/hid-sensors/Makefile
> @@ -6,4 +6,7 @@ ccflags-y += -Idrivers/staging
> ccflags-$(CONFIG_HID_SENSOR_DEBUG) += -DDEBUG
>
> hid-sensors-y := hid-sensor-hub.o
> +hid-sensors-y += hid-sensor-attributes.o
> +hid-sensors-y += hid-sensor-ring.o
> +hid-sensors-y += hid-sensor-trigger.o
> obj-$(CONFIG_HID_SENSORS) += hid-sensors.o
> diff --git a/drivers/staging/hid-sensors/hid-sensor-attributes.c b/drivers/staging/hid-sensors/hid-sensor-attributes.c
> new file mode 100644
> index 0000000..6f07d50
> --- /dev/null
> +++ b/drivers/staging/hid-sensors/hid-sensor-attributes.c
> @@ -0,0 +1,203 @@
> +/*
> + * HID Sensors Driver
> + * Copyright (c) 2012, Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + */
> +#include<linux/interrupt.h>
> +#include<linux/irq.h>
> +#include<linux/mutex.h>
> +#include<linux/device.h>
> +#include<linux/kernel.h>
> +#include<linux/spi/spi.h>
> +#include<linux/slab.h>
> +#include<linux/sysfs.h>
> +
> +#include "iio/iio.h"
> +#include "iio/sysfs.h"
> +#include "hid-sensor-ids.h"
> +#include "hid-sensor-interface.h"
> +
> +ssize_t hid_sensor_read_poll_interval(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + struct iio_dev *indio_dev = dev_get_drvdata(dev);
> + struct hid_sensor_attributes *st = iio_priv(indio_dev);
> + __s32 value;
> + int len;
> + int ret;
> +
> + ret = sensor_hub_get_feature(st->hdev,
> + st->poll.report_id,
> + st->poll.index,&value);
> + if (ret< 0 || value< 0)
> + len = sprintf(buf, "0\n");
> + else
> + len = sprintf(buf, "units:0x%2x,exp:0x%x,value:0x%2x\n",
> + st->poll.units, st->poll.unit_expo, value);
It's sampling_frequency for iio and it's in hz.
> + return len;
> +}
> +
> +
> +ssize_t hid_sensor_write_poll_interval(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t len)
> +{
> + struct iio_dev *indio_dev = dev_get_drvdata(dev);
> + struct hid_sensor_attributes *st = iio_priv(indio_dev);
> + long int value;
> + int ret;
> +
> + if (kstrtol(buf, 10,&value)< 0)
> + return -EINVAL;
> +
> + if (value<= 0)
> + value = 0;
> +
> + ret = sensor_hub_set_feature(st->hdev,
> + st->poll.report_id,
> + st->poll.index,
> + value);
This implies to my mind that the units are fixed for a given
device? Anyhow you also need to convert from hz here.
> +
> + if (ret< 0)
> + return ret;
> + return strlen(buf);
> +
> +}
> +
> +ssize_t hid_sensor_read_report_state(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + struct iio_dev *indio_dev = dev_get_drvdata(dev);
> + struct hid_sensor_attributes *st = iio_priv(indio_dev);
> + long int value;
> + int len;
> + int ret;
> +
> + ret = sensor_hub_get_feature(st->hdev,
> + st->activate.report_id,
> + st->activate.index, (s32 *)&value);
> + if (ret< 0 || value< 0)
> + len = sprintf(buf, "0\n");
> + else
> + len = sprintf(buf, "units:0x%2x,exp:0x%x,value:0x%2x\n",
> + st->activate.units, st->activate.unit_expo,
> + (unsigned int)value);
> + return len;
> +
> +}
> +
> +ssize_t hid_sensor_write_report_state(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t len)
> +{
> +
> + struct iio_dev *indio_dev = dev_get_drvdata(dev);
> + struct hid_sensor_attributes *st = iio_priv(indio_dev);
> + int ret;
> + long int value;
> +
> + if (kstrtol(buf, 10,&value)< 0)
> + return -EINVAL;
> +
> + ret = sensor_hub_set_feature(st->hdev, st->activate.report_id,
> + st->activate.index,
> + (s32)value);
> + if (ret< 0)
> + return ret;
> +
> + return strlen(buf);
> +}
> +
> +ssize_t hid_sensor_read_sensitivity(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> +
> + struct iio_dev *indio_dev = dev_get_drvdata(dev);
> + struct hid_sensor_attributes *st = iio_priv(indio_dev);
> + __s32 value;
> + int len;
> + int ret;
> +
> + ret = sensor_hub_get_feature(st->hdev,
> + st->sensitivity.report_id,
> + st->sensitivity.index,&value);
> + if (ret< 0 || value< 0)
> + len = sprintf(buf, "0\n");
> + else
> + len = sprintf(buf, "units:0x%2x,exp:0x%x,value:0x%2x\n",
> + st->sensitivity.units,
> + st->sensitivity.unit_expo, value);
> + return len;
> +}
> +
> +
> +ssize_t hid_sensor_write_sensitivity(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t len)
> +{
> + struct iio_dev *indio_dev = dev_get_drvdata(dev);
> + struct hid_sensor_attributes *st = iio_priv(indio_dev);
> + long int value;
> + int ret;
> +
> + if (kstrtol(buf, 10,&value)< 0)
> + return -EINVAL;
> +
> + if (value<= 0)
> + value = 0;
> +
> + ret = sensor_hub_set_feature(st->hdev,
> + st->sensitivity.report_id,
> + st->sensitivity.index,
> + value);
> +
> + if (ret< 0)
> + return ret;
> +
> + return strlen(buf);
> +}
> +
> +
> +
> +int hid_sensor_parse_common_attributes(struct hid_device *hdev, u32 usage_id,
> + struct hid_sensor_attributes *st)
> +{
> + int ret;
> +
> + ret = sensor_hub_input_get_attribute_info(hdev,
> + HID_FEATURE_REPORT, usage_id,
> + HID_SENSOR_POLLING,&st->poll);
> +
> + ret = sensor_hub_input_get_attribute_info(hdev,
> + HID_FEATURE_REPORT, usage_id,
> + HID_SENSOR_REPORT_STATE,
> + &st->activate);
> +
> + ret = sensor_hub_input_get_attribute_info(hdev,
> + HID_FEATURE_REPORT, usage_id,
> + HID_USAGE_SENSOR_PROPERTY_CHANGE_SENSITIVITY_ABS,
> + &st->sensitivity);
> +
> + hid_dbg(hdev, "common attributes: %x:%x, %x:%x, %x:%x\n",
> + st->poll.index, st->poll.report_id,
> + st->activate.index, st->activate.report_id,
> + st->sensitivity.index, st->sensitivity.report_id);
> +
> + return 0;
> +}
> diff --git a/drivers/staging/hid-sensors/hid-sensor-attributes.h b/drivers/staging/hid-sensors/hid-sensor-attributes.h
> new file mode 100644
> index 0000000..b1f4ac9
> --- /dev/null
> +++ b/drivers/staging/hid-sensors/hid-sensor-attributes.h
> @@ -0,0 +1,67 @@
> +/*
> + * HID Sensors Driver
> + * Copyright (c) 2012, Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + */
> +#ifndef _HID_SENSORS_ATTRIBUTES_H
> +#define _HID_SENSORS_ATTRIBUTES_H
> +
> +/* Common sysfs attributes for HID sensors */
> +
> +int hid_sensor_parse_common_attributes(struct hid_device *hdev, u32 usage_id,
> + struct hid_sensor_attributes *st);
> +
> +ssize_t hid_sensor_read_poll_interval(struct device *dev,
> + struct device_attribute *attr,
> + char *buf);
> +ssize_t hid_sensor_write_poll_interval(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t len);
> +
> +ssize_t hid_sensor_read_report_state(struct device *dev,
> + struct device_attribute *attr,
> + char *buf);
> +ssize_t hid_sensor_write_report_state(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t len);
> +ssize_t hid_sensor_read_sensitivity(struct device *dev,
> + struct device_attribute *attr,
> + char *buf);
> +ssize_t hid_sensor_write_sensitivity(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t len);
> +
> +
> +#define IIO_DEV_ATTR_POLL_INTERVAL(_mode, _show, _store, _addr) \
> + IIO_DEVICE_ATTR(poll_interval, _mode, _show, _store, _addr)
sampling_frequency
> +#define IIO_DEV_ATTR_SENSITIVITY(_mode, _show, _store, _addr) \
> + IIO_DEVICE_ATTR(sensitivity, _mode, _show, _store, _addr)
probably maps to hysteresis. Also this one is weird given it's probably
a parameter of the trigger rather than the sensor read out... hmm.
> +#define IIO_DEV_ATTR_REPORT_STATE(_mode, _show, _store, _addr) \
> + IIO_DEVICE_ATTR(activate, _mode, _show, _store, _addr)
This one needs some docs (sorry if I've missed them). I'd almost
guarantee this will map to something more standard....
> +
> +static IIO_DEV_ATTR_POLL_INTERVAL(S_IWUSR | S_IRUSR,
> + hid_sensor_read_poll_interval,
> + hid_sensor_write_poll_interval,
> + HID_SENSOR_POLLING);
> +static IIO_DEV_ATTR_SENSITIVITY(S_IWUSR | S_IRUSR,
> + hid_sensor_read_sensitivity,
> + hid_sensor_write_sensitivity,
> + HID_USAGE_SENSOR_PROPERTY_CHANGE_SENSITIVITY_ABS);
> +static IIO_DEV_ATTR_REPORT_STATE(S_IWUSR | S_IRUSR,
> + hid_sensor_read_report_state,
> + hid_sensor_write_report_state,
> + HID_SENSOR_REPORT_STATE);
> +#endif
> diff --git a/drivers/staging/hid-sensors/hid-sensor-interface.h b/drivers/staging/hid-sensors/hid-sensor-interface.h
> index 18a2e09..477494f 100644
> --- a/drivers/staging/hid-sensors/hid-sensor-interface.h
> +++ b/drivers/staging/hid-sensors/hid-sensor-interface.h
> @@ -72,4 +72,16 @@ ssize_t sensor_hub_input_attr_get_value(struct hid_device *hdev, u32 usage_id,
> u32 buf_len, u8 *buf);
> int sensor_hub_input_get_unit_expo(struct hid_device *hdev, u32 field_usage_id,
> s32 *unit, s32 *unit_expo);
> +
> +/* Common IIO Ring Processing Functions */
> +int hid_sensor_configure_ring(struct iio_dev *indio_dev);
> +void hid_sensor_ring_cleanup(struct iio_dev *indio_dev);
> +void hid_sensor_ring_set_datum_size(struct iio_dev *indio_dev, int size);
> +void hid_sensor_push_data_to_ring(struct iio_dev *indio_dev, u8 *data,
> + int len);
> +
> +/* Trigger functions */
> +int hid_sensor_setup_trigger(struct iio_dev *indio_dev, char *name);
> +void hid_sensor_remove_trigger(struct iio_dev *indio_dev);
> +
> #endif
> diff --git a/drivers/staging/hid-sensors/hid-sensor-ring.c b/drivers/staging/hid-sensors/hid-sensor-ring.c
> new file mode 100644
> index 0000000..c63ff26
> --- /dev/null
> +++ b/drivers/staging/hid-sensors/hid-sensor-ring.c
> @@ -0,0 +1,104 @@
> +/*
> + * HID Sensors Driver
> + * Copyright (c) 2012, Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + */
> +#include<linux/interrupt.h>
> +#include<linux/irq.h>
> +#include<linux/mutex.h>
> +#include<linux/device.h>
> +#include<linux/kernel.h>
> +#include<linux/spi/spi.h>
> +#include<linux/slab.h>
> +#include<linux/sysfs.h>
> +
> +#include "iio/iio.h"
> +#include "iio/sysfs.h"
> +#include "iio/ring_sw.h"
> +#include "iio/trigger_consumer.h"
> +#include "iio/trigger.h"
> +
> +static const struct iio_buffer_setup_ops hid_sensors_buffer_setup_ops = {
> + .preenable =&iio_sw_buffer_preenable,
> + .postenable =&iio_triggered_buffer_postenable,
> + .predisable =&iio_triggered_buffer_predisable,
> +};
Not that I've reviews them yet, but a lot of this looks similar to the
patch series Lars-Peter sent out the other day.
[PATCH 0/9] iio: Add helper function for initializing triggered buffers
> +
> +static irqreturn_t hid_sensor_trigger_handler(int irq, void *p)
> +{
> + return IRQ_HANDLED;
That's novel...
> +}
> +
> +void hid_sensor_push_data_to_ring(struct iio_dev *indio_dev, u8 *data, int len)
> +{
> + struct iio_buffer *ring = indio_dev->buffer;
> + s64 timestamp = iio_get_time_ns();
> + int datum_sz;
> +
> + if (!ring)
> + return;
> + datum_sz = ring->access->get_bytes_per_datum(ring);
> + if (len> datum_sz) {
> + dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len,
> + datum_sz);
> + return;
> + } else if (datum_sz> 0&& datum_sz != len) {
> + dev_dbg(&indio_dev->dev, "Updating Datum size%d:%d\n", len,
> + datum_sz);
> + if (ring->access->set_bytes_per_datum)
> + ring->access->set_bytes_per_datum(ring, len);
You don't want to do this (and my gut feeling is it won't work). Buffer
size should be set up during the bring up of the buffer not on
an element read.
> + }
Do a read through and clean up white space. One blank line is almost
always enough and certainly is here!
> +
> +
> + ring->access->store_to(ring, (u8 *)data, timestamp);
> +}
> +
This one maps directly to one of Lars-Peter's suggestions. As they
say - great minds think alike!
> +int hid_sensor_configure_ring(struct iio_dev *indio_dev)
> +{
> + struct iio_buffer *ring;
> + int ret = 0;
> +
> + ring = iio_sw_rb_allocate(indio_dev);
> + if (!ring)
> + return -ENOMEM;
> +
> + ring->scan_timestamp = true;
> + indio_dev->buffer = ring;
> + indio_dev->setup_ops =&hid_sensors_buffer_setup_ops;
> +
> + indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
> + &hid_sensor_trigger_handler,
> + IRQF_ONESHOT,
> + indio_dev,
> + "hid_sensor%d",
> + indio_dev->id);
> + if (indio_dev->pollfunc == NULL) {
> + ret = -ENOMEM;
> + goto error_iio_free;
> + }
> +
> + indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
> +
> + return ret;
> +error_iio_free:
> + iio_sw_rb_free(indio_dev->buffer);
> + return ret;
> +}
> +
> +void hid_sensor_ring_cleanup(struct iio_dev *indio_dev)
> +{
> + iio_sw_rb_free(indio_dev->buffer);
> +}
> diff --git a/drivers/staging/hid-sensors/hid-sensor-trigger.c b/drivers/staging/hid-sensors/hid-sensor-trigger.c
> new file mode 100644
> index 0000000..49d8740
> --- /dev/null
> +++ b/drivers/staging/hid-sensors/hid-sensor-trigger.c
> @@ -0,0 +1,81 @@
> +/*
> + * HID Sensors Driver
> + * Copyright (c) 2012, Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> + *
> + */
> +#include<linux/device.h>
> +#include<linux/hid.h>
> +#include<linux/usb.h>
> +#include "usbhid/usbhid.h"
> +#include<linux/module.h>
> +#include<linux/slab.h>
> +#include "iio/iio.h"
> +#include "iio/trigger.h"
> +#include "hid-sensor-interface.h"
> +
> +static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
> + bool state)
> +{
> + struct iio_dev *indio_dev = trig->private_data;
> + struct hid_sensor_attributes *st = iio_priv(indio_dev);
> +
again 1 blank line is plenty. I'm fussy about this one ;)
> +
> + st->data_ready = state;
> +
> + return 0;
> +}
> +
> +void hid_sensor_remove_trigger(struct iio_dev *indio_dev)
> +{
Hmm. The need for this check smells bad... I'd expect the driver
to have a higher level knowledge of whether this exists...
> + if (indio_dev->trig) {
> + iio_trigger_unregister(indio_dev->trig);
> + iio_free_trigger(indio_dev->trig);
> + }
> +}
> +
> +static const struct iio_trigger_ops hid_sensor_trigger_ops = {
> + .owner = THIS_MODULE,
> + .set_trigger_state =&hid_sensor_data_rdy_trigger_set_state,
> +};
> +
> +int hid_sensor_setup_trigger(struct iio_dev *indio_dev, char *name)
> +{
> + int ret;
> + struct iio_trigger *trig;
> +
> + trig = iio_allocate_trigger("%s-dev%d", name, indio_dev->id);
> + if (trig == NULL) {
> + ret = -ENOMEM;
> + goto error_ret;
> + }
> +
> + trig->dev.parent = indio_dev->dev.parent;
> + trig->private_data = (void *)indio_dev;
> + trig->ops =&hid_sensor_trigger_ops;
> + ret = iio_trigger_register(trig);
> +
> + /* select default trigger */
> + indio_dev->trig = trig;
> + if (ret)
> + goto error_free_trig;
> +
> + return ret;
> +
> +error_free_trig:
> + iio_free_trigger(trig);
> +error_ret:
> + return ret;
> +}
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH, 4/7] HID-Sensors: Added accelerometer 3D
2012-06-06 15:39 [PATCH, 0/7] HID Sensor Driver srinivas pandruvada
` (2 preceding siblings ...)
2012-06-06 15:39 ` [PATCH, 3/7] HID-Sensors: Common attributes and interfaces srinivas pandruvada
@ 2012-06-06 15:39 ` srinivas pandruvada
2012-06-06 16:28 ` Jonathan Cameron
2012-06-06 15:39 ` [PATCH, 5/7] HID-Sensors: Added Gyro 3D srinivas pandruvada
` (2 subsequent siblings)
6 siblings, 1 reply; 16+ messages in thread
From: srinivas pandruvada @ 2012-06-06 15:39 UTC (permalink / raw)
To: linux-input; +Cc: linux-iio, Srinivas pandruvada
From: Srinivas pandruvada <srinivas.pandruvada@intel.com>
Added usage id processing for Accelrometer 3D. This uses IIO
interfaces "ring/buffer and trigger interface" to present
data to user mode.
Signed-off-by: Srinivas pandruvada <srinivas.pandruvada@intel.com>
---
drivers/staging/hid-sensors/Makefile | 1 +
drivers/staging/hid-sensors/hid-sensor-accel-3d.c | 387 ++++++++++++++++++++
drivers/staging/hid-sensors/hid-sensor-hub.c | 1 +
drivers/staging/hid-sensors/hid-sensor-interface.h | 3 +
4 files changed, 392 insertions(+), 0 deletions(-)
create mode 100644 drivers/staging/hid-sensors/hid-sensor-accel-3d.c
diff --git a/drivers/staging/hid-sensors/Makefile b/drivers/staging/hid-sensors/Makefile
index 9a03953..4412079 100644
--- a/drivers/staging/hid-sensors/Makefile
+++ b/drivers/staging/hid-sensors/Makefile
@@ -9,4 +9,5 @@ hid-sensors-y := hid-sensor-hub.o
hid-sensors-y += hid-sensor-attributes.o
hid-sensors-y += hid-sensor-ring.o
hid-sensors-y += hid-sensor-trigger.o
+hid-sensors-y += hid-sensor-accel-3d.o
obj-$(CONFIG_HID_SENSORS) += hid-sensors.o
diff --git a/drivers/staging/hid-sensors/hid-sensor-accel-3d.c b/drivers/staging/hid-sensors/hid-sensor-accel-3d.c
new file mode 100644
index 0000000..ffe2639
--- /dev/null
+++ b/drivers/staging/hid-sensors/hid-sensor-accel-3d.c
@@ -0,0 +1,387 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/usb.h>
+#include "usbhid/usbhid.h"
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "iio/iio.h"
+#include "iio/sysfs.h"
+#include "iio/ring_sw.h"
+#include "iio/trigger.h"
+#include "hid-sensor-ids.h"
+#include "hid-sensor-interface.h"
+#include "hid-sensor-attributes.h"
+
+
+struct accel_3d_sample {
+ u16 x_sz;
+ u32 accel_x;
+ u16 y_sz;
+ u32 accel_y;
+ u16 z_sz;
+ u32 accel_z;
+} __packed;
+
+struct accel_3d_state {
+ struct hid_sensor_hub_attribute_info accel_x;
+ struct hid_sensor_hub_attribute_info accel_y;
+ struct hid_sensor_hub_attribute_info accel_z;
+ struct accel_3d_sample accel_sample_data;
+};
+
+
+enum accel_3d_chan {
+ ACCEL_X_Y_Z,
+};
+
+enum accel_3d_scan {
+ ACCEL_3D_SCAN_ACC_X_Y_Z,
+};
+
+static struct iio_chan_spec accel_3d_channels[] = {
+ IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X_AND_Y_AND_Z,
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
+ ACCEL_X_Y_Z, ACCEL_3D_SCAN_ACC_X_Y_Z,
+ IIO_ST('u', sizeof(struct accel_3d_sample) * 8,
+ sizeof(struct accel_3d_sample) * 8, 0), 0),
+};
+
+static ssize_t accel_3d_read_accel(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ struct accel_3d_state *accel_state =
+ (struct accel_3d_state *)st->private;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int report_id = -1;
+
+ switch (this_attr->address) {
+ case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS:
+ report_id = accel_state->accel_x.report_id;
+ break;
+ case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS:
+ report_id = accel_state->accel_y.report_id;
+ break;
+ case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS:
+ report_id = accel_state->accel_z.report_id;
+ break;
+ default:
+ break;
+ }
+ if (report_id < 0)
+ return -EINVAL;
+
+ return sensor_hub_input_attr_get_value(st->hdev,
+ HID_USAGE_SENSOR_ACCEL_3D, this_attr->address,
+ report_id, 4, buf);
+}
+
+static int accel_3d_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2,
+ long mask)
+{
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ struct accel_3d_state *accel_state =
+ (struct accel_3d_state *)st->private;
+ *val = 0;
+ *val2 = 0;
+
+ switch (mask) {
+ case 0:
+ break;
+ case IIO_CHAN_INFO_SCALE:
+ *val = accel_state->accel_x.units;
+ break;
+ case IIO_CHAN_INFO_OFFSET:
+ *val = accel_state->accel_x.unit_expo;
+ break;
+ default:
+ break;
+
+ }
+ return IIO_VAL_INT;
+}
+
+static int accel_3d_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long mask)
+{
+ printk(KERN_ERR "%s\n", __func__);
+
+ return 0;
+}
+
+/* Usage specific attributes */
+#define IIO_DEV_ATTR_ACCEL_OFFSET(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(accel_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_ACCEL_X_OFFSET(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(accel_x_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_ACCEL_Y_OFFSET(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(accel_y_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_ACCEL_Z_OFFSET(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(accel_z_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_ACCEL_SENSITIVITY(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(accel_sensitivity, _mode, _show, _store, _addr)
+
+static IIO_DEV_ATTR_ACCEL_X_OFFSET(S_IWUSR | S_IRUGO, accel_3d_read_accel,
+ NULL, HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS);
+static IIO_DEV_ATTR_ACCEL_Y_OFFSET(S_IWUSR | S_IRUGO, accel_3d_read_accel,
+ NULL, HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS);
+static IIO_DEV_ATTR_ACCEL_Z_OFFSET(S_IWUSR | S_IRUGO, accel_3d_read_accel,
+ NULL, HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS);
+
+static struct attribute *accel_3d_attributes[] = {
+ /* common attributes */
+ &iio_dev_attr_poll_interval.dev_attr.attr,
+ &iio_dev_attr_sensitivity.dev_attr.attr,
+ &iio_dev_attr_activate.dev_attr.attr,
+ /* Usage specific attributes */
+ &iio_dev_attr_accel_x_offset.dev_attr.attr,
+ &iio_dev_attr_accel_y_offset.dev_attr.attr,
+ &iio_dev_attr_accel_z_offset.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group accel_3d_attribute_group = {
+ .attrs = accel_3d_attributes,
+};
+
+static const struct iio_info accel_3d_info = {
+ .attrs = &accel_3d_attribute_group,
+ .driver_module = THIS_MODULE,
+ .read_raw = &accel_3d_read_raw,
+ .write_raw = &accel_3d_write_raw,
+};
+
+
+/* Function to push data to IIO ring */
+int accel_3d_proc_event(struct hid_device *hdev, unsigned usage_id, void *priv)
+{
+ struct iio_dev *indio_dev = (struct iio_dev *)priv;
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ struct accel_3d_state *accel_state =
+ (struct accel_3d_state *)st->private;
+
+ hid_dbg(hdev, "accel_3d_proc_event\n");
+ if (st->data_ready)
+ hid_sensor_push_data_to_ring(indio_dev,
+ (u8 *)&accel_state->accel_sample_data,
+ sizeof(struct accel_3d_sample));
+ else
+ hid_dbg(hdev, "accel_3d_proc_event data not ready\n");
+ return 0;
+}
+
+/* Capture samples in local storage */
+int accel_3d_capture_sample(struct hid_device *hdev, unsigned usage_id,
+ size_t raw_len, char *raw_data, void *priv)
+{
+ struct iio_dev *indio_dev = (struct iio_dev *)priv;
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ struct accel_3d_state *accel_state =
+ (struct accel_3d_state *)st->private;
+
+ switch (usage_id) {
+ case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS:
+ accel_state->accel_sample_data.x_sz = raw_len;
+ accel_state->accel_sample_data.accel_x =
+ *(u32 *)raw_data;
+ break;
+ case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS:
+ accel_state->accel_sample_data.y_sz = raw_len;
+ accel_state->accel_sample_data.accel_y =
+ *(u32 *)raw_data;
+ break;
+ case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS:
+ accel_state->accel_sample_data.z_sz = raw_len;
+ accel_state->accel_sample_data.accel_z =
+ *(u32 *)raw_data;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+/* Parse report which is specific to an usage id*/
+static int accel_3d_parse_report(struct hid_device *hdev, unsigned usage_id,
+ struct accel_3d_state *st)
+{
+ int ret;
+
+ ret = sensor_hub_input_get_attribute_info(hdev, HID_INPUT_REPORT,
+ usage_id,
+ HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS,
+ &st->accel_x);
+ if (!ret)
+ hid_dbg(hdev, "No Accel X attribute\n");
+
+
+ ret = sensor_hub_input_get_attribute_info(hdev, HID_INPUT_REPORT,
+ usage_id,
+ HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS,
+ &st->accel_y);
+ if (!ret)
+ hid_dbg(hdev, "No Accel Y attribute\n");
+
+
+ ret = sensor_hub_input_get_attribute_info(hdev, HID_INPUT_REPORT,
+ usage_id,
+ HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS,
+ &st->accel_z);
+ if (!ret)
+ hid_dbg(hdev, "No Accel Z attribute\n");
+
+ hid_dbg(hdev, "accel_3d %x:%x, %x:%x, %x:%x\n", st->accel_x.index,
+ st->accel_x.report_id,
+ st->accel_y.index, st->accel_y.report_id,
+ st->accel_z.index, st->accel_z.report_id);
+
+ return 0;
+}
+
+/* Entry function to initialize the processing for usage id */
+static int accel_3d_enter(struct hid_device *hdev, unsigned usage_id,
+ void **priv)
+{
+ int ret = 0;
+ static char *name = "accel_3d";
+ struct iio_dev *indio_dev;
+ struct accel_3d_state *accel_state;
+ struct hid_sensor_attributes *st;
+
+ accel_state = kzalloc(sizeof(struct accel_3d_state), GFP_KERNEL);
+ if (accel_state == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ indio_dev = iio_allocate_device(sizeof(struct hid_sensor_attributes));
+ if (indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_state;
+ }
+ st = iio_priv(indio_dev);
+ st->usage_id = usage_id;
+ st->hdev = hdev;
+ st->private = (void *)accel_state;
+
+ ret = hid_sensor_parse_common_attributes(hdev, usage_id, st);
+ if (ret) {
+ hid_err(hdev, "failed to setup common attributes\n");
+ goto error_free_dev;
+ }
+ ret = accel_3d_parse_report(hdev, usage_id, accel_state);
+ if (ret) {
+ hid_err(hdev, "failed to setup attributes\n");
+ goto error_free_dev;
+ }
+
+ indio_dev->channels = accel_3d_channels;
+ indio_dev->num_channels =
+ ARRAY_SIZE(accel_3d_channels);
+ indio_dev->dev.parent = &hdev->dev;
+ indio_dev->info = &accel_3d_info;
+ indio_dev->name = name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = hid_sensor_configure_ring(indio_dev);
+ if (ret) {
+ hid_err(hdev, "failed to initialize the ring\n");
+ goto error_free_dev;
+ }
+
+ ret = iio_buffer_register(indio_dev,
+ accel_3d_channels,
+ ARRAY_SIZE(accel_3d_channels));
+ if (ret) {
+ hid_err(hdev, "failed to initialize the ring\n");
+ goto error_unreg_ring_funcs;
+ }
+ st->data_ready = true;
+ ret = hid_sensor_setup_trigger(indio_dev, name);
+ if (ret < 0) {
+ hid_err(hdev, "trigger setup failed\n");
+ goto error_uninit_ring;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ hid_err(hdev, "device register failed\n");
+ goto error_remove_trigger;
+ }
+ *priv = (void *)indio_dev;
+ return ret;
+
+error_remove_trigger:
+ hid_sensor_remove_trigger(indio_dev);
+error_uninit_ring:
+ iio_buffer_unregister(indio_dev);
+error_unreg_ring_funcs:
+ hid_sensor_ring_cleanup(indio_dev);
+error_free_dev:
+ iio_free_device(indio_dev);
+error_free_state:
+ kfree(accel_state);
+error_ret:
+ return ret;
+}
+
+static int accel_3d_exit(struct hid_device *hdev, void *priv)
+{
+ int ret = 0;
+ struct iio_dev *indio_dev = (struct iio_dev *)priv;
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ struct accel_3d_state *accel_state =
+ (struct accel_3d_state *)st->private;
+
+ iio_device_unregister(indio_dev);
+ hid_sensor_remove_trigger(indio_dev);
+ iio_buffer_unregister(indio_dev);
+ hid_sensor_ring_cleanup(indio_dev);
+ iio_free_device(indio_dev);
+
+ kfree(accel_state);
+ return ret;
+}
+
+static struct sensor_hub_callbacks accel_3d_callbacks = {
+ .enter = accel_3d_enter,
+ .exit = accel_3d_exit,
+ .send_event = accel_3d_proc_event,
+ .capture_sample = accel_3d_capture_sample,
+};
+
+struct sensor_hub_callbacks *accel_3d_register_callbacks(void)
+{
+ return &accel_3d_callbacks;
+}
diff --git a/drivers/staging/hid-sensors/hid-sensor-hub.c b/drivers/staging/hid-sensors/hid-sensor-hub.c
index 384e0d0..55ae562 100644
--- a/drivers/staging/hid-sensors/hid-sensor-hub.c
+++ b/drivers/staging/hid-sensors/hid-sensor-hub.c
@@ -60,6 +60,7 @@ struct sensor_hub_callbacks_list {
};
static struct sensor_hub_callbacks_list usage_callbacks[] = {
+ {HID_USAGE_SENSOR_ACCEL_3D, accel_3d_register_callbacks},
{0}
};
diff --git a/drivers/staging/hid-sensors/hid-sensor-interface.h b/drivers/staging/hid-sensors/hid-sensor-interface.h
index 477494f..3f4fe57 100644
--- a/drivers/staging/hid-sensors/hid-sensor-interface.h
+++ b/drivers/staging/hid-sensors/hid-sensor-interface.h
@@ -84,4 +84,7 @@ void hid_sensor_push_data_to_ring(struct iio_dev *indio_dev, u8 *data,
int hid_sensor_setup_trigger(struct iio_dev *indio_dev, char *name);
void hid_sensor_remove_trigger(struct iio_dev *indio_dev);
+/* Sensor usage id processing callbacks */
+struct sensor_hub_callbacks *accel_3d_register_callbacks(void);
+
#endif
--
1.7.7.6
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH, 4/7] HID-Sensors: Added accelerometer 3D
2012-06-06 15:39 ` [PATCH, 4/7] HID-Sensors: Added accelerometer 3D srinivas pandruvada
@ 2012-06-06 16:28 ` Jonathan Cameron
2012-06-06 16:57 ` Pandruvada, Srinivas
0 siblings, 1 reply; 16+ messages in thread
From: Jonathan Cameron @ 2012-06-06 16:28 UTC (permalink / raw)
To: srinivas pandruvada, linux-input; +Cc: linux-iio
srinivas pandruvada <srinivas.pandruvada@intel.com> wrote:
>From: Srinivas pandruvada <srinivas.pandruvada@intel.com>
>
>Added usage id processing for Accelrometer 3D. This uses IIO
>interfaces "ring/buffer and trigger interface" to present
>data to user mode.
I do not understand the data format. The way iio describes the format is done through sysfs attrs built from the iio_Chan spec... that way a scan is made up of a number of channel readings each taken at roughly the same time. However each is separately described. Perhaps the description needs extending. Please describe the format.
>
>Signed-off-by: Srinivas pandruvada <srinivas.pandruvada@intel.com>
>---
> drivers/staging/hid-sensors/Makefile | 1 +
>drivers/staging/hid-sensors/hid-sensor-accel-3d.c | 387
>++++++++++++++++++++
> drivers/staging/hid-sensors/hid-sensor-hub.c | 1 +
> drivers/staging/hid-sensors/hid-sensor-interface.h | 3 +
> 4 files changed, 392 insertions(+), 0 deletions(-)
> create mode 100644 drivers/staging/hid-sensors/hid-sensor-accel-3d.c
>
>diff --git a/drivers/staging/hid-sensors/Makefile
>b/drivers/staging/hid-sensors/Makefile
>index 9a03953..4412079 100644
>--- a/drivers/staging/hid-sensors/Makefile
>+++ b/drivers/staging/hid-sensors/Makefile
>@@ -9,4 +9,5 @@ hid-sensors-y := hid-sensor-hub.o
> hid-sensors-y += hid-sensor-attributes.o
> hid-sensors-y += hid-sensor-ring.o
> hid-sensors-y += hid-sensor-trigger.o
>+hid-sensors-y += hid-sensor-accel-3d.o
> obj-$(CONFIG_HID_SENSORS) += hid-sensors.o
>diff --git a/drivers/staging/hid-sensors/hid-sensor-accel-3d.c
>b/drivers/staging/hid-sensors/hid-sensor-accel-3d.c
>new file mode 100644
>index 0000000..ffe2639
>--- /dev/null
>+++ b/drivers/staging/hid-sensors/hid-sensor-accel-3d.c
>@@ -0,0 +1,387 @@
>+/*
>+ * HID Sensors Driver
>+ * Copyright (c) 2012, Intel Corporation.
>+ *
>+ * This program is free software; you can redistribute it and/or
>modify it
>+ * under the terms and conditions of the GNU General Public License,
>+ * version 2, as published by the Free Software Foundation.
>+ *
>+ * This program is distributed in the hope it will be useful, but
>WITHOUT
>+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
>or
>+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
>License for
>+ * more details.
>+ *
>+ * You should have received a copy of the GNU General Public License
>along with
>+ * this program; if not, write to the Free Software Foundation, Inc.,
>+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
>+ *
>+ */
>+#include <linux/device.h>
>+#include <linux/hid.h>
>+#include <linux/usb.h>
>+#include "usbhid/usbhid.h"
>+#include <linux/module.h>
>+#include <linux/slab.h>
>+#include "iio/iio.h"
>+#include "iio/sysfs.h"
>+#include "iio/ring_sw.h"
>+#include "iio/trigger.h"
>+#include "hid-sensor-ids.h"
>+#include "hid-sensor-interface.h"
>+#include "hid-sensor-attributes.h"
>+
>+
>+struct accel_3d_sample {
>+ u16 x_sz;
>+ u32 accel_x;
>+ u16 y_sz;
>+ u32 accel_y;
>+ u16 z_sz;
>+ u32 accel_z;
>+} __packed;
>+
>+struct accel_3d_state {
>+ struct hid_sensor_hub_attribute_info accel_x;
>+ struct hid_sensor_hub_attribute_info accel_y;
>+ struct hid_sensor_hub_attribute_info accel_z;
>+ struct accel_3d_sample accel_sample_data;
>+};
>+
>+
>+enum accel_3d_chan {
>+ ACCEL_X_Y_Z,
>+};
>+
>+enum accel_3d_scan {
>+ ACCEL_3D_SCAN_ACC_X_Y_Z,
>+};
>+
>+static struct iio_chan_spec accel_3d_channels[] = {
>+ IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X_AND_Y_AND_Z,
>+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
>+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
>+ ACCEL_X_Y_Z, ACCEL_3D_SCAN_ACC_X_Y_Z,
>+ IIO_ST('u', sizeof(struct accel_3d_sample) * 8,
>+ sizeof(struct accel_3d_sample) * 8, 0), 0),
>+};
>+
>+static ssize_t accel_3d_read_accel(struct device *dev,
>+ struct device_attribute *attr,
>+ char *buf)
>+{
>+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
>+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
>+ struct accel_3d_state *accel_state =
>+ (struct accel_3d_state *)st->private;
>+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
>+ int report_id = -1;
>+
>+ switch (this_attr->address) {
>+ case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS:
>+ report_id = accel_state->accel_x.report_id;
>+ break;
>+ case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS:
>+ report_id = accel_state->accel_y.report_id;
>+ break;
>+ case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS:
>+ report_id = accel_state->accel_z.report_id;
>+ break;
>+ default:
>+ break;
>+ }
>+ if (report_id < 0)
>+ return -EINVAL;
>+
>+ return sensor_hub_input_attr_get_value(st->hdev,
>+ HID_USAGE_SENSOR_ACCEL_3D, this_attr->address,
>+ report_id, 4, buf);
>+}
>+
>+static int accel_3d_read_raw(struct iio_dev *indio_dev,
>+ struct iio_chan_spec const *chan,
>+ int *val, int *val2,
>+ long mask)
>+{
>+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
>+ struct accel_3d_state *accel_state =
>+ (struct accel_3d_state *)st->private;
>+ *val = 0;
>+ *val2 = 0;
>+
>+ switch (mask) {
>+ case 0:
>+ break;
>+ case IIO_CHAN_INFO_SCALE:
>+ *val = accel_state->accel_x.units;
>+ break;
>+ case IIO_CHAN_INFO_OFFSET:
>+ *val = accel_state->accel_x.unit_expo;
>+ break;
>+ default:
>+ break;
>+
>+ }
>+ return IIO_VAL_INT;
>+}
>+
>+static int accel_3d_write_raw(struct iio_dev *indio_dev,
>+ struct iio_chan_spec const *chan,
>+ int val,
>+ int val2,
>+ long mask)
>+{
>+ printk(KERN_ERR "%s\n", __func__);
>+
>+ return 0;
>+}
>+
>+/* Usage specific attributes */
>+#define IIO_DEV_ATTR_ACCEL_OFFSET(_mode, _show, _store, _addr) \
>+ IIO_DEVICE_ATTR(accel_offset, _mode, _show, _store, _addr)
>+
>+#define IIO_DEV_ATTR_ACCEL_X_OFFSET(_mode, _show, _store, _addr)
> \
>+ IIO_DEVICE_ATTR(accel_x_offset, _mode, _show, _store, _addr)
>+
>+#define IIO_DEV_ATTR_ACCEL_Y_OFFSET(_mode, _show, _store, _addr)
> \
>+ IIO_DEVICE_ATTR(accel_y_offset, _mode, _show, _store, _addr)
>+
>+#define IIO_DEV_ATTR_ACCEL_Z_OFFSET(_mode, _show, _store, _addr)
> \
>+ IIO_DEVICE_ATTR(accel_z_offset, _mode, _show, _store, _addr)
>+
>+#define IIO_DEV_ATTR_ACCEL_SENSITIVITY(_mode, _show, _store, _addr)
> \
>+ IIO_DEVICE_ATTR(accel_sensitivity, _mode, _show, _store, _addr)
>+
>+static IIO_DEV_ATTR_ACCEL_X_OFFSET(S_IWUSR | S_IRUGO,
>accel_3d_read_accel,
>+ NULL, HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS);
>+static IIO_DEV_ATTR_ACCEL_Y_OFFSET(S_IWUSR | S_IRUGO,
>accel_3d_read_accel,
>+ NULL, HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS);
>+static IIO_DEV_ATTR_ACCEL_Z_OFFSET(S_IWUSR | S_IRUGO,
>accel_3d_read_accel,
>+ NULL, HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS);
>+
>+static struct attribute *accel_3d_attributes[] = {
>+ /* common attributes */
>+ &iio_dev_attr_poll_interval.dev_attr.attr,
>+ &iio_dev_attr_sensitivity.dev_attr.attr,
>+ &iio_dev_attr_activate.dev_attr.attr,
>+ /* Usage specific attributes */
>+ &iio_dev_attr_accel_x_offset.dev_attr.attr,
>+ &iio_dev_attr_accel_y_offset.dev_attr.attr,
>+ &iio_dev_attr_accel_z_offset.dev_attr.attr,
>+ NULL,
>+};
>+
>+static const struct attribute_group accel_3d_attribute_group = {
>+ .attrs = accel_3d_attributes,
>+};
>+
>+static const struct iio_info accel_3d_info = {
>+ .attrs = &accel_3d_attribute_group,
>+ .driver_module = THIS_MODULE,
>+ .read_raw = &accel_3d_read_raw,
>+ .write_raw = &accel_3d_write_raw,
>+};
>+
>+
>+/* Function to push data to IIO ring */
>+int accel_3d_proc_event(struct hid_device *hdev, unsigned usage_id,
>void *priv)
>+{
>+ struct iio_dev *indio_dev = (struct iio_dev *)priv;
>+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
>+ struct accel_3d_state *accel_state =
>+ (struct accel_3d_state *)st->private;
>+
>+ hid_dbg(hdev, "accel_3d_proc_event\n");
>+ if (st->data_ready)
>+ hid_sensor_push_data_to_ring(indio_dev,
>+ (u8 *)&accel_state->accel_sample_data,
>+ sizeof(struct accel_3d_sample));
>+ else
>+ hid_dbg(hdev, "accel_3d_proc_event data not ready\n");
>+ return 0;
>+}
>+
>+/* Capture samples in local storage */
>+int accel_3d_capture_sample(struct hid_device *hdev, unsigned
>usage_id,
>+ size_t raw_len, char *raw_data, void *priv)
>+{
>+ struct iio_dev *indio_dev = (struct iio_dev *)priv;
>+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
>+ struct accel_3d_state *accel_state =
>+ (struct accel_3d_state *)st->private;
>+
>+ switch (usage_id) {
>+ case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS:
>+ accel_state->accel_sample_data.x_sz = raw_len;
>+ accel_state->accel_sample_data.accel_x =
>+ *(u32 *)raw_data;
>+ break;
>+ case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS:
>+ accel_state->accel_sample_data.y_sz = raw_len;
>+ accel_state->accel_sample_data.accel_y =
>+ *(u32 *)raw_data;
>+ break;
>+ case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS:
>+ accel_state->accel_sample_data.z_sz = raw_len;
>+ accel_state->accel_sample_data.accel_z =
>+ *(u32 *)raw_data;
>+ break;
>+ default:
>+ break;
>+ }
>+ return 0;
>+}
>+
>+
>+/* Parse report which is specific to an usage id*/
>+static int accel_3d_parse_report(struct hid_device *hdev, unsigned
>usage_id,
>+ struct accel_3d_state *st)
>+{
>+ int ret;
>+
>+ ret = sensor_hub_input_get_attribute_info(hdev, HID_INPUT_REPORT,
>+ usage_id,
>+ HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS,
>+ &st->accel_x);
>+ if (!ret)
>+ hid_dbg(hdev, "No Accel X attribute\n");
>+
>+
>+ ret = sensor_hub_input_get_attribute_info(hdev, HID_INPUT_REPORT,
>+ usage_id,
>+ HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS,
>+ &st->accel_y);
>+ if (!ret)
>+ hid_dbg(hdev, "No Accel Y attribute\n");
>+
>+
>+ ret = sensor_hub_input_get_attribute_info(hdev, HID_INPUT_REPORT,
>+ usage_id,
>+ HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS,
>+ &st->accel_z);
>+ if (!ret)
>+ hid_dbg(hdev, "No Accel Z attribute\n");
>+
>+ hid_dbg(hdev, "accel_3d %x:%x, %x:%x, %x:%x\n", st->accel_x.index,
>+ st->accel_x.report_id,
>+ st->accel_y.index, st->accel_y.report_id,
>+ st->accel_z.index, st->accel_z.report_id);
>+
>+ return 0;
>+}
>+
>+/* Entry function to initialize the processing for usage id */
>+static int accel_3d_enter(struct hid_device *hdev, unsigned usage_id,
>+ void **priv)
>+{
>+ int ret = 0;
>+ static char *name = "accel_3d";
>+ struct iio_dev *indio_dev;
>+ struct accel_3d_state *accel_state;
>+ struct hid_sensor_attributes *st;
>+
>+ accel_state = kzalloc(sizeof(struct accel_3d_state), GFP_KERNEL);
>+ if (accel_state == NULL) {
>+ ret = -ENOMEM;
>+ goto error_ret;
>+ }
>+
>+ indio_dev = iio_allocate_device(sizeof(struct
>hid_sensor_attributes));
>+ if (indio_dev == NULL) {
>+ ret = -ENOMEM;
>+ goto error_free_state;
>+ }
>+ st = iio_priv(indio_dev);
>+ st->usage_id = usage_id;
>+ st->hdev = hdev;
>+ st->private = (void *)accel_state;
>+
>+ ret = hid_sensor_parse_common_attributes(hdev, usage_id, st);
>+ if (ret) {
>+ hid_err(hdev, "failed to setup common attributes\n");
>+ goto error_free_dev;
>+ }
>+ ret = accel_3d_parse_report(hdev, usage_id, accel_state);
>+ if (ret) {
>+ hid_err(hdev, "failed to setup attributes\n");
>+ goto error_free_dev;
>+ }
>+
>+ indio_dev->channels = accel_3d_channels;
>+ indio_dev->num_channels =
>+ ARRAY_SIZE(accel_3d_channels);
>+ indio_dev->dev.parent = &hdev->dev;
>+ indio_dev->info = &accel_3d_info;
>+ indio_dev->name = name;
>+ indio_dev->modes = INDIO_DIRECT_MODE;
>+
>+ ret = hid_sensor_configure_ring(indio_dev);
>+ if (ret) {
>+ hid_err(hdev, "failed to initialize the ring\n");
>+ goto error_free_dev;
>+ }
>+
>+ ret = iio_buffer_register(indio_dev,
>+ accel_3d_channels,
>+ ARRAY_SIZE(accel_3d_channels));
>+ if (ret) {
>+ hid_err(hdev, "failed to initialize the ring\n");
>+ goto error_unreg_ring_funcs;
>+ }
>+ st->data_ready = true;
>+ ret = hid_sensor_setup_trigger(indio_dev, name);
>+ if (ret < 0) {
>+ hid_err(hdev, "trigger setup failed\n");
>+ goto error_uninit_ring;
>+ }
>+
>+ ret = iio_device_register(indio_dev);
>+ if (ret) {
>+ hid_err(hdev, "device register failed\n");
>+ goto error_remove_trigger;
>+ }
>+ *priv = (void *)indio_dev;
>+ return ret;
>+
>+error_remove_trigger:
>+ hid_sensor_remove_trigger(indio_dev);
>+error_uninit_ring:
>+ iio_buffer_unregister(indio_dev);
>+error_unreg_ring_funcs:
>+ hid_sensor_ring_cleanup(indio_dev);
>+error_free_dev:
>+ iio_free_device(indio_dev);
>+error_free_state:
>+ kfree(accel_state);
>+error_ret:
>+ return ret;
>+}
>+
>+static int accel_3d_exit(struct hid_device *hdev, void *priv)
>+{
>+ int ret = 0;
>+ struct iio_dev *indio_dev = (struct iio_dev *)priv;
>+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
>+ struct accel_3d_state *accel_state =
>+ (struct accel_3d_state *)st->private;
>+
>+ iio_device_unregister(indio_dev);
>+ hid_sensor_remove_trigger(indio_dev);
>+ iio_buffer_unregister(indio_dev);
>+ hid_sensor_ring_cleanup(indio_dev);
>+ iio_free_device(indio_dev);
>+
>+ kfree(accel_state);
>+ return ret;
>+}
>+
>+static struct sensor_hub_callbacks accel_3d_callbacks = {
>+ .enter = accel_3d_enter,
>+ .exit = accel_3d_exit,
>+ .send_event = accel_3d_proc_event,
>+ .capture_sample = accel_3d_capture_sample,
>+};
>+
>+struct sensor_hub_callbacks *accel_3d_register_callbacks(void)
>+{
>+ return &accel_3d_callbacks;
>+}
>diff --git a/drivers/staging/hid-sensors/hid-sensor-hub.c
>b/drivers/staging/hid-sensors/hid-sensor-hub.c
>index 384e0d0..55ae562 100644
>--- a/drivers/staging/hid-sensors/hid-sensor-hub.c
>+++ b/drivers/staging/hid-sensors/hid-sensor-hub.c
>@@ -60,6 +60,7 @@ struct sensor_hub_callbacks_list {
> };
>
> static struct sensor_hub_callbacks_list usage_callbacks[] = {
>+ {HID_USAGE_SENSOR_ACCEL_3D, accel_3d_register_callbacks},
> {0}
> };
>
>diff --git a/drivers/staging/hid-sensors/hid-sensor-interface.h
>b/drivers/staging/hid-sensors/hid-sensor-interface.h
>index 477494f..3f4fe57 100644
>--- a/drivers/staging/hid-sensors/hid-sensor-interface.h
>+++ b/drivers/staging/hid-sensors/hid-sensor-interface.h
>@@ -84,4 +84,7 @@ void hid_sensor_push_data_to_ring(struct iio_dev
>*indio_dev, u8 *data,
> int hid_sensor_setup_trigger(struct iio_dev *indio_dev, char *name);
> void hid_sensor_remove_trigger(struct iio_dev *indio_dev);
>
>+/* Sensor usage id processing callbacks */
>+struct sensor_hub_callbacks *accel_3d_register_callbacks(void);
>+
> #endif
>--
>1.7.7.6
>
>--
>To unsubscribe from this list: send the line "unsubscribe linux-iio" in
>the body of a message to majordomo@vger.kernel.org
>More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Sent from my Android phone with K-9 Mail. Please excuse my brevity.
^ permalink raw reply [flat|nested] 16+ messages in thread* RE: [PATCH, 4/7] HID-Sensors: Added accelerometer 3D
2012-06-06 16:28 ` Jonathan Cameron
@ 2012-06-06 16:57 ` Pandruvada, Srinivas
2012-06-06 17:07 ` Lars-Peter Clausen
2012-06-07 8:10 ` Jonathan Cameron
0 siblings, 2 replies; 16+ messages in thread
From: Pandruvada, Srinivas @ 2012-06-06 16:57 UTC (permalink / raw)
To: Jonathan Cameron, linux-input@vger.kernel.org; +Cc: linux-iio@vger.kernel.org
VGhlIFVTQiBzZW5zb3Igc3BlYyBoYXMgYSByZXBvcnQgc3RydWN0dXJlIHdoaWNoIGl0IHNlbmRz
IGFzIHBhcnQgb2YgcmVwb3J0IGRlc2NyaXB0b3Igd2UgZ2V0IGR1cmluZyBpbml0aWFsIHBsdWcg
aW4uIFRoaXMgcmVwb3J0IHN0cnVjdHVyZSBkZXNjcmliZXMgZWxlbWVudHMgYW5kIHRoZWlyIHNp
emVzLiBGb3IgZXhhbXBsZSwgaXQgbWF5IHNheSB0aGF0IGFuIEFjY2VsZXJvbWV0ZXIgWCBheGlz
IHZhbHVlIGFzIDQgYnl0ZXMgbG9uZyBhbmQgd2hhdCBpcyB0aGUgZXhwb25lbnQgYW5kIHVuaXQu
IEFsc28gaXQgc2VuZHMgd2hhdCBjb250cm9sIGVsZW1lbnRzIGl0IGhhcy4NClRoZSBzZXF1ZW5j
ZSBpcw0KLSBTZXQgc2Vuc2l0aXZpdHksIGludGVydmFsLCBhY3RpdmF0ZSBzeXMtZnMgaW50ZXJm
YWNlLiBUaGUgVVNCIHNlbnNvciB3aWxsIHNlbmQgYW4gZXZlbnQgYnkgVVNCLUlOIHJlcG9ydCB3
aGVuIHRoZSBjYXB0dXJlZCBzYW1wbGUgaXMgY2hhbmdlZCBieSBzZW5zaXRpdml0eSB2YWx1ZSBh
bmQgc3RhYmxlIGZvciBhdCBsZWFzdCBpbnRlcnZhbC4gQWxzbyB5b3UgbmVlZCB0byBhY3RpdmF0
ZSB0aGUgc2Vuc29yIHNvIHRoYXQgdGhlIHVzYiB3aWxsIHN0YXJ0IHNlbmRpbmcgZXZlbnRzLg0K
DQotIE9uY2UgVVNCIHJlcG9ydCB3aXRoIHRoZSBjYXB0dXJlZCBzYW1wbGUgYXJyaXZlcywgSSBm
b3JtYXQgdGhlIGRhdGEgYXMgZGVmaW5lZCBpbiAiIHN0cnVjdCBhY2NlbF8zZF9zYW1wbGUiIGJl
bG93IGFuZCBwdXNoIHRvIElJTyByaW5nIGJ1ZmZlci4NCkkgZGVmaW5lIGEgc2luZ2xlIGNoYW5u
ZWwNCglJSU9fQ0hBTihJSU9fQUNDRUwsIDEsIDAsIDAsIE5VTEwsIDAsIElJT19NT0RfWF9BTkRf
WV9BTkRfWiwNCglJSU9fQ0hBTl9JTkZPX1NDQUxFX1NFUEFSQVRFX0JJVCB8DQoJSUlPX0NIQU5f
SU5GT19PRkZTRVRfU0VQQVJBVEVfQklULA0KCUFDQ0VMX1hfWV9aLCBBQ0NFTF8zRF9TQ0FOX0FD
Q19YX1lfWiwNCgkJIElJT19TVCgndScsIHNpemVvZihzdHJ1Y3QgYWNjZWxfM2Rfc2FtcGxlKSAq
IDgsDQoJCXNpemVvZihzdHJ1Y3QgYWNjZWxfM2Rfc2FtcGxlKSAqIDgsIDApLCAwKSwgfTsNCg0K
UGxlYXNlIHN1Z2dlc3QgbWUgaWYgdGhpcyBpcyBub3QgdGhlIHdheSBJSU8gY2hhbm5lbCB1c2Vk
LiANCg0KVGhhbmtzLA0KU3Jpbml2YXMNCg0KDQoNCi0tLS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0t
DQpGcm9tOiBKb25hdGhhbiBDYW1lcm9uIFttYWlsdG86amljMjNAY2FtLmFjLnVrXSANClNlbnQ6
IFdlZG5lc2RheSwgSnVuZSAwNiwgMjAxMiA5OjI5IEFNDQpUbzogUGFuZHJ1dmFkYSwgU3Jpbml2
YXM7IGxpbnV4LWlucHV0QHZnZXIua2VybmVsLm9yZw0KQ2M6IGxpbnV4LWlpb0B2Z2VyLmtlcm5l
bC5vcmcNClN1YmplY3Q6IFJlOiBbUEFUQ0gsIDQvN10gSElELVNlbnNvcnM6IEFkZGVkIGFjY2Vs
ZXJvbWV0ZXIgM0QNCg0KDQoNCnNyaW5pdmFzIHBhbmRydXZhZGEgPHNyaW5pdmFzLnBhbmRydXZh
ZGFAaW50ZWwuY29tPiB3cm90ZToNCg0KPkZyb206IFNyaW5pdmFzIHBhbmRydXZhZGEgPHNyaW5p
dmFzLnBhbmRydXZhZGFAaW50ZWwuY29tPg0KPg0KPkFkZGVkIHVzYWdlIGlkIHByb2Nlc3Npbmcg
Zm9yIEFjY2Vscm9tZXRlciAzRC4gVGhpcyB1c2VzIElJTyBpbnRlcmZhY2VzIA0KPiJyaW5nL2J1
ZmZlciBhbmQgdHJpZ2dlciBpbnRlcmZhY2UiIHRvIHByZXNlbnQgZGF0YSB0byB1c2VyIG1vZGUu
DQoNCkkgZG8gbm90IHVuZGVyc3RhbmQgdGhlIGRhdGEgZm9ybWF0LiAgVGhlIHdheSBpaW8gZGVz
Y3JpYmVzIHRoZSBmb3JtYXQgaXMgZG9uZSB0aHJvdWdoIHN5c2ZzIGF0dHJzIGJ1aWx0IGZyb20g
dGhlIGlpb19DaGFuIHNwZWMuLi4gdGhhdCB3YXkgYSBzY2FuIGlzIG1hZGUgdXAgb2YgYSBudW1i
ZXIgb2YgY2hhbm5lbCByZWFkaW5ncyBlYWNoIHRha2VuIGF0IHJvdWdobHkgdGhlIHNhbWUgdGlt
ZS4gIEhvd2V2ZXIgZWFjaCBpcyBzZXBhcmF0ZWx5IGRlc2NyaWJlZC4gIFBlcmhhcHMgdGhlIGRl
c2NyaXB0aW9uIG5lZWRzIGV4dGVuZGluZy4gIFBsZWFzZSBkZXNjcmliZSB0aGUgZm9ybWF0Lg0K
Pg0KPlNpZ25lZC1vZmYtYnk6IFNyaW5pdmFzIHBhbmRydXZhZGEgPHNyaW5pdmFzLnBhbmRydXZh
ZGFAaW50ZWwuY29tPg0KPi0tLQ0KPiBkcml2ZXJzL3N0YWdpbmcvaGlkLXNlbnNvcnMvTWFrZWZp
bGUgICAgICAgICAgICAgICB8ICAgIDEgKw0KPmRyaXZlcnMvc3RhZ2luZy9oaWQtc2Vuc29ycy9o
aWQtc2Vuc29yLWFjY2VsLTNkLmMgIHwgIDM4Nw0KPisrKysrKysrKysrKysrKysrKysrDQo+IGRy
aXZlcnMvc3RhZ2luZy9oaWQtc2Vuc29ycy9oaWQtc2Vuc29yLWh1Yi5jICAgICAgIHwgICAgMSAr
DQo+IGRyaXZlcnMvc3RhZ2luZy9oaWQtc2Vuc29ycy9oaWQtc2Vuc29yLWludGVyZmFjZS5oIHwg
ICAgMyArDQo+IDQgZmlsZXMgY2hhbmdlZCwgMzkyIGluc2VydGlvbnMoKyksIDAgZGVsZXRpb25z
KC0pIGNyZWF0ZSBtb2RlIDEwMDY0NCANCj4gZHJpdmVycy9zdGFnaW5nL2hpZC1zZW5zb3JzL2hp
ZC1zZW5zb3ItYWNjZWwtM2QuYw0KPg0KPmRpZmYgLS1naXQgYS9kcml2ZXJzL3N0YWdpbmcvaGlk
LXNlbnNvcnMvTWFrZWZpbGUNCj5iL2RyaXZlcnMvc3RhZ2luZy9oaWQtc2Vuc29ycy9NYWtlZmls
ZQ0KPmluZGV4IDlhMDM5NTMuLjQ0MTIwNzkgMTAwNjQ0DQo+LS0tIGEvZHJpdmVycy9zdGFnaW5n
L2hpZC1zZW5zb3JzL01ha2VmaWxlDQo+KysrIGIvZHJpdmVycy9zdGFnaW5nL2hpZC1zZW5zb3Jz
L01ha2VmaWxlDQo+QEAgLTksNCArOSw1IEBAIGhpZC1zZW5zb3JzLXkgOj0gaGlkLXNlbnNvci1o
dWIubyAgaGlkLXNlbnNvcnMteSArPSANCj5oaWQtc2Vuc29yLWF0dHJpYnV0ZXMubyAgaGlkLXNl
bnNvcnMteSArPSBoaWQtc2Vuc29yLXJpbmcubyAgDQo+aGlkLXNlbnNvcnMteSArPSBoaWQtc2Vu
c29yLXRyaWdnZXIubw0KPitoaWQtc2Vuc29ycy15ICs9IGhpZC1zZW5zb3ItYWNjZWwtM2Qubw0K
PiBvYmotJChDT05GSUdfSElEX1NFTlNPUlMpICs9IGhpZC1zZW5zb3JzLm8gZGlmZiAtLWdpdCAN
Cj5hL2RyaXZlcnMvc3RhZ2luZy9oaWQtc2Vuc29ycy9oaWQtc2Vuc29yLWFjY2VsLTNkLmMNCj5i
L2RyaXZlcnMvc3RhZ2luZy9oaWQtc2Vuc29ycy9oaWQtc2Vuc29yLWFjY2VsLTNkLmMNCj5uZXcg
ZmlsZSBtb2RlIDEwMDY0NA0KPmluZGV4IDAwMDAwMDAuLmZmZTI2MzkNCj4tLS0gL2Rldi9udWxs
DQo+KysrIGIvZHJpdmVycy9zdGFnaW5nL2hpZC1zZW5zb3JzL2hpZC1zZW5zb3ItYWNjZWwtM2Qu
Yw0KPkBAIC0wLDAgKzEsMzg3IEBADQo+Ky8qDQo+KyAqIEhJRCBTZW5zb3JzIERyaXZlcg0KPisg
KiBDb3B5cmlnaHQgKGMpIDIwMTIsIEludGVsIENvcnBvcmF0aW9uLg0KPisgKg0KPisgKiBUaGlz
IHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29y
DQo+bW9kaWZ5IGl0DQo+KyAqIHVuZGVyIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB0aGUg
R05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UsDQo+KyAqIHZlcnNpb24gMiwgYXMgcHVibGlzaGVk
IGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24uDQo+KyAqDQo+KyAqIFRoaXMgcHJvZ3Jh
bSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSBpdCB3aWxsIGJlIHVzZWZ1bCwgYnV0DQo+V0lU
SE9VVA0KPisgKiBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50
eSBvZiBNRVJDSEFOVEFCSUxJVFkNCj5vcg0KPisgKiBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIg
UFVSUE9TRS4gIFNlZSB0aGUgR05VIEdlbmVyYWwgUHVibGljDQo+TGljZW5zZSBmb3INCj4rICog
bW9yZSBkZXRhaWxzLg0KPisgKg0KPisgKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5
IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZQ0KPmFsb25nIHdpdGgNCj4rICogdGhp
cyBwcm9ncmFtOyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24s
IEluYy4sDQo+KyAqIDUxIEZyYW5rbGluIFN0IC0gRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgMDIx
MTAtMTMwMSBVU0EuDQo+KyAqDQo+KyAqLw0KPisjaW5jbHVkZSA8bGludXgvZGV2aWNlLmg+DQo+
KyNpbmNsdWRlIDxsaW51eC9oaWQuaD4NCj4rI2luY2x1ZGUgPGxpbnV4L3VzYi5oPg0KPisjaW5j
bHVkZSAidXNiaGlkL3VzYmhpZC5oIg0KPisjaW5jbHVkZSA8bGludXgvbW9kdWxlLmg+DQo+KyNp
bmNsdWRlIDxsaW51eC9zbGFiLmg+DQo+KyNpbmNsdWRlICJpaW8vaWlvLmgiDQo+KyNpbmNsdWRl
ICJpaW8vc3lzZnMuaCINCj4rI2luY2x1ZGUgImlpby9yaW5nX3N3LmgiDQo+KyNpbmNsdWRlICJp
aW8vdHJpZ2dlci5oIg0KPisjaW5jbHVkZSAiaGlkLXNlbnNvci1pZHMuaCINCj4rI2luY2x1ZGUg
ImhpZC1zZW5zb3ItaW50ZXJmYWNlLmgiDQo+KyNpbmNsdWRlICJoaWQtc2Vuc29yLWF0dHJpYnV0
ZXMuaCINCj4rDQo+Kw0KPitzdHJ1Y3QgYWNjZWxfM2Rfc2FtcGxlIHsNCj4rCXUxNiB4X3N6Ow0K
PisJdTMyIGFjY2VsX3g7DQo+Kwl1MTYgeV9zejsNCj4rCXUzMiBhY2NlbF95Ow0KPisJdTE2IHpf
c3o7DQo+Kwl1MzIgYWNjZWxfejsNCj4rfSBfX3BhY2tlZDsNCj4rDQo+K3N0cnVjdCBhY2NlbF8z
ZF9zdGF0ZSB7DQo+KwlzdHJ1Y3QgaGlkX3NlbnNvcl9odWJfYXR0cmlidXRlX2luZm8gYWNjZWxf
eDsNCj4rCXN0cnVjdCBoaWRfc2Vuc29yX2h1Yl9hdHRyaWJ1dGVfaW5mbyBhY2NlbF95Ow0KPisJ
c3RydWN0IGhpZF9zZW5zb3JfaHViX2F0dHJpYnV0ZV9pbmZvIGFjY2VsX3o7DQo+KwlzdHJ1Y3Qg
YWNjZWxfM2Rfc2FtcGxlIGFjY2VsX3NhbXBsZV9kYXRhOyB9Ow0KPisNCj4rDQo+K2VudW0gYWNj
ZWxfM2RfY2hhbiB7DQo+KwlBQ0NFTF9YX1lfWiwNCj4rfTsNCj4rDQo+K2VudW0gYWNjZWxfM2Rf
c2NhbiB7DQo+KwlBQ0NFTF8zRF9TQ0FOX0FDQ19YX1lfWiwNCj4rfTsNCj4rDQo+K3N0YXRpYyBz
dHJ1Y3QgaWlvX2NoYW5fc3BlYyBhY2NlbF8zZF9jaGFubmVsc1tdID0gew0KPisJSUlPX0NIQU4o
SUlPX0FDQ0VMLCAxLCAwLCAwLCBOVUxMLCAwLCBJSU9fTU9EX1hfQU5EX1lfQU5EX1osDQo+KwlJ
SU9fQ0hBTl9JTkZPX1NDQUxFX1NFUEFSQVRFX0JJVCB8DQo+KwlJSU9fQ0hBTl9JTkZPX09GRlNF
VF9TRVBBUkFURV9CSVQsDQo+KwlBQ0NFTF9YX1lfWiwgQUNDRUxfM0RfU0NBTl9BQ0NfWF9ZX1os
DQo+KwkJIElJT19TVCgndScsIHNpemVvZihzdHJ1Y3QgYWNjZWxfM2Rfc2FtcGxlKSAqIDgsDQo+
KwkJc2l6ZW9mKHN0cnVjdCBhY2NlbF8zZF9zYW1wbGUpICogOCwgMCksIDApLCB9Ow0KPisNCj4r
c3RhdGljIHNzaXplX3QgYWNjZWxfM2RfcmVhZF9hY2NlbChzdHJ1Y3QgZGV2aWNlICpkZXYsDQo+
KwkJCQlzdHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciwNCj4rCQkJCWNoYXIgKmJ1ZikNCj4r
ew0KPisJc3RydWN0IGlpb19kZXYgKmluZGlvX2RldiA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOw0K
PisJc3RydWN0IGhpZF9zZW5zb3JfYXR0cmlidXRlcyAqc3QgPSBpaW9fcHJpdihpbmRpb19kZXYp
Ow0KPisJc3RydWN0IGFjY2VsXzNkX3N0YXRlICphY2NlbF9zdGF0ZSA9DQo+KwkJCShzdHJ1Y3Qg
YWNjZWxfM2Rfc3RhdGUgKilzdC0+cHJpdmF0ZTsNCj4rCXN0cnVjdCBpaW9fZGV2X2F0dHIgKnRo
aXNfYXR0ciA9IHRvX2lpb19kZXZfYXR0cihhdHRyKTsNCj4rCWludCByZXBvcnRfaWQgPSAtMTsN
Cj4rDQo+Kwlzd2l0Y2ggKHRoaXNfYXR0ci0+YWRkcmVzcykgew0KPisJY2FzZSBISURfVVNBR0Vf
U0VOU09SX0RBVEFfTU9USU9OX0FDQ0VMRVJBVElPTl9YX0FYSVM6DQo+KwkJcmVwb3J0X2lkID0g
YWNjZWxfc3RhdGUtPmFjY2VsX3gucmVwb3J0X2lkOw0KPisJCWJyZWFrOw0KPisJY2FzZSBISURf
VVNBR0VfU0VOU09SX0RBVEFfTU9USU9OX0FDQ0VMRVJBVElPTl9ZX0FYSVM6DQo+KwkJcmVwb3J0
X2lkID0gYWNjZWxfc3RhdGUtPmFjY2VsX3kucmVwb3J0X2lkOw0KPisJCWJyZWFrOw0KPisJY2Fz
ZSBISURfVVNBR0VfU0VOU09SX0RBVEFfTU9USU9OX0FDQ0VMRVJBVElPTl9aX0FYSVM6DQo+KwkJ
cmVwb3J0X2lkID0gYWNjZWxfc3RhdGUtPmFjY2VsX3oucmVwb3J0X2lkOw0KPisJCWJyZWFrOw0K
PisJZGVmYXVsdDoNCj4rCQlicmVhazsNCj4rCX0NCj4rCWlmIChyZXBvcnRfaWQgPCAwKQ0KPisJ
CXJldHVybiAtRUlOVkFMOw0KPisNCj4rCXJldHVybiBzZW5zb3JfaHViX2lucHV0X2F0dHJfZ2V0
X3ZhbHVlKHN0LT5oZGV2LA0KPisJCQlISURfVVNBR0VfU0VOU09SX0FDQ0VMXzNELCB0aGlzX2F0
dHItPmFkZHJlc3MsDQo+KwkJCXJlcG9ydF9pZCwgNCwgYnVmKTsNCj4rfQ0KPisNCj4rc3RhdGlj
IGludCBhY2NlbF8zZF9yZWFkX3JhdyhzdHJ1Y3QgaWlvX2RldiAqaW5kaW9fZGV2LA0KPisJCQkg
ICAgICBzdHJ1Y3QgaWlvX2NoYW5fc3BlYyBjb25zdCAqY2hhbiwNCj4rCQkJICAgICAgaW50ICp2
YWwsIGludCAqdmFsMiwNCj4rCQkJICAgICAgbG9uZyBtYXNrKQ0KPit7DQo+KwlzdHJ1Y3QgaGlk
X3NlbnNvcl9hdHRyaWJ1dGVzICpzdCA9IGlpb19wcml2KGluZGlvX2Rldik7DQo+KwlzdHJ1Y3Qg
YWNjZWxfM2Rfc3RhdGUgKmFjY2VsX3N0YXRlID0NCj4rCQkJKHN0cnVjdCBhY2NlbF8zZF9zdGF0
ZSAqKXN0LT5wcml2YXRlOw0KPisJKnZhbCA9IDA7DQo+KwkqdmFsMiA9IDA7DQo+Kw0KPisJc3dp
dGNoIChtYXNrKSB7DQo+KwljYXNlIDA6DQo+KwkJYnJlYWs7DQo+KwljYXNlIElJT19DSEFOX0lO
Rk9fU0NBTEU6DQo+KwkJKnZhbCA9IGFjY2VsX3N0YXRlLT5hY2NlbF94LnVuaXRzOw0KPisJCWJy
ZWFrOw0KPisJY2FzZSBJSU9fQ0hBTl9JTkZPX09GRlNFVDoNCj4rCQkqdmFsID0gYWNjZWxfc3Rh
dGUtPmFjY2VsX3gudW5pdF9leHBvOw0KPisJCWJyZWFrOw0KPisJZGVmYXVsdDoNCj4rCQlicmVh
azsNCj4rDQo+Kwl9DQo+KwlyZXR1cm4gSUlPX1ZBTF9JTlQ7DQo+K30NCj4rDQo+K3N0YXRpYyBp
bnQgYWNjZWxfM2Rfd3JpdGVfcmF3KHN0cnVjdCBpaW9fZGV2ICppbmRpb19kZXYsDQo+KwkJCSAg
ICAgICBzdHJ1Y3QgaWlvX2NoYW5fc3BlYyBjb25zdCAqY2hhbiwNCj4rCQkJICAgICAgIGludCB2
YWwsDQo+KwkJCSAgICAgICBpbnQgdmFsMiwNCj4rCQkJICAgICAgIGxvbmcgbWFzaykNCj4rew0K
PisJcHJpbnRrKEtFUk5fRVJSICIlc1xuIiwgX19mdW5jX18pOw0KPisNCj4rCXJldHVybiAwOw0K
Pit9DQo+Kw0KPisvKiBVc2FnZSBzcGVjaWZpYyBhdHRyaWJ1dGVzICovDQo+KyNkZWZpbmUgSUlP
X0RFVl9BVFRSX0FDQ0VMX09GRlNFVChfbW9kZSwgX3Nob3csIF9zdG9yZSwgX2FkZHIpICBcDQo+
KwlJSU9fREVWSUNFX0FUVFIoYWNjZWxfb2Zmc2V0LCBfbW9kZSwgX3Nob3csIF9zdG9yZSwgX2Fk
ZHIpDQo+Kw0KPisjZGVmaW5lIElJT19ERVZfQVRUUl9BQ0NFTF9YX09GRlNFVChfbW9kZSwgX3No
b3csIF9zdG9yZSwgX2FkZHIpICAgICAgDQo+IFwNCj4rCUlJT19ERVZJQ0VfQVRUUihhY2NlbF94
X29mZnNldCwgX21vZGUsIF9zaG93LCBfc3RvcmUsIF9hZGRyKQ0KPisNCj4rI2RlZmluZSBJSU9f
REVWX0FUVFJfQUNDRUxfWV9PRkZTRVQoX21vZGUsIF9zaG93LCBfc3RvcmUsIF9hZGRyKSAgICAg
IA0KPiBcDQo+KwlJSU9fREVWSUNFX0FUVFIoYWNjZWxfeV9vZmZzZXQsIF9tb2RlLCBfc2hvdywg
X3N0b3JlLCBfYWRkcikNCj4rDQo+KyNkZWZpbmUgSUlPX0RFVl9BVFRSX0FDQ0VMX1pfT0ZGU0VU
KF9tb2RlLCBfc2hvdywgX3N0b3JlLCBfYWRkcikgICAgICANCj4gXA0KPisJSUlPX0RFVklDRV9B
VFRSKGFjY2VsX3pfb2Zmc2V0LCBfbW9kZSwgX3Nob3csIF9zdG9yZSwgX2FkZHIpDQo+Kw0KPisj
ZGVmaW5lIElJT19ERVZfQVRUUl9BQ0NFTF9TRU5TSVRJVklUWShfbW9kZSwgX3Nob3csIF9zdG9y
ZSwgX2FkZHIpICAgDQo+ICAgIFwNCj4rCUlJT19ERVZJQ0VfQVRUUihhY2NlbF9zZW5zaXRpdml0
eSwgX21vZGUsIF9zaG93LCBfc3RvcmUsIF9hZGRyKQ0KPisNCj4rc3RhdGljIElJT19ERVZfQVRU
Ul9BQ0NFTF9YX09GRlNFVChTX0lXVVNSIHwgU19JUlVHTywNCj5hY2NlbF8zZF9yZWFkX2FjY2Vs
LA0KPisJCSBOVUxMLCBISURfVVNBR0VfU0VOU09SX0RBVEFfTU9USU9OX0FDQ0VMRVJBVElPTl9Y
X0FYSVMpOw0KPitzdGF0aWMgSUlPX0RFVl9BVFRSX0FDQ0VMX1lfT0ZGU0VUKFNfSVdVU1IgfCBT
X0lSVUdPLA0KPmFjY2VsXzNkX3JlYWRfYWNjZWwsDQo+KwkJIE5VTEwsIEhJRF9VU0FHRV9TRU5T
T1JfREFUQV9NT1RJT05fQUNDRUxFUkFUSU9OX1lfQVhJUyk7DQo+K3N0YXRpYyBJSU9fREVWX0FU
VFJfQUNDRUxfWl9PRkZTRVQoU19JV1VTUiB8IFNfSVJVR08sDQo+YWNjZWxfM2RfcmVhZF9hY2Nl
bCwNCj4rCQkgTlVMTCwgSElEX1VTQUdFX1NFTlNPUl9EQVRBX01PVElPTl9BQ0NFTEVSQVRJT05f
Wl9BWElTKTsNCj4rDQo+K3N0YXRpYyBzdHJ1Y3QgYXR0cmlidXRlICphY2NlbF8zZF9hdHRyaWJ1
dGVzW10gPSB7DQo+KwkvKiBjb21tb24gYXR0cmlidXRlcyAqLw0KPisJJmlpb19kZXZfYXR0cl9w
b2xsX2ludGVydmFsLmRldl9hdHRyLmF0dHIsDQo+KwkmaWlvX2Rldl9hdHRyX3NlbnNpdGl2aXR5
LmRldl9hdHRyLmF0dHIsDQo+KwkmaWlvX2Rldl9hdHRyX2FjdGl2YXRlLmRldl9hdHRyLmF0dHIs
DQo+KwkvKiBVc2FnZSBzcGVjaWZpYyBhdHRyaWJ1dGVzICovDQo+KwkmaWlvX2Rldl9hdHRyX2Fj
Y2VsX3hfb2Zmc2V0LmRldl9hdHRyLmF0dHIsDQo+KwkmaWlvX2Rldl9hdHRyX2FjY2VsX3lfb2Zm
c2V0LmRldl9hdHRyLmF0dHIsDQo+KwkmaWlvX2Rldl9hdHRyX2FjY2VsX3pfb2Zmc2V0LmRldl9h
dHRyLmF0dHIsDQo+KwlOVUxMLA0KPit9Ow0KPisNCj4rc3RhdGljIGNvbnN0IHN0cnVjdCBhdHRy
aWJ1dGVfZ3JvdXAgYWNjZWxfM2RfYXR0cmlidXRlX2dyb3VwID0gew0KPisJLmF0dHJzID0gYWNj
ZWxfM2RfYXR0cmlidXRlcywNCj4rfTsNCj4rDQo+K3N0YXRpYyBjb25zdCBzdHJ1Y3QgaWlvX2lu
Zm8gYWNjZWxfM2RfaW5mbyA9IHsNCj4rCS5hdHRycyA9ICZhY2NlbF8zZF9hdHRyaWJ1dGVfZ3Jv
dXAsDQo+KwkuZHJpdmVyX21vZHVsZSA9IFRISVNfTU9EVUxFLA0KPisJLnJlYWRfcmF3ID0gJmFj
Y2VsXzNkX3JlYWRfcmF3LA0KPisJLndyaXRlX3JhdyA9ICZhY2NlbF8zZF93cml0ZV9yYXcsDQo+
K307DQo+Kw0KPisNCj4rLyogRnVuY3Rpb24gdG8gcHVzaCBkYXRhIHRvIElJTyByaW5nICovIGlu
dCBhY2NlbF8zZF9wcm9jX2V2ZW50KHN0cnVjdCANCj4raGlkX2RldmljZSAqaGRldiwgdW5zaWdu
ZWQgdXNhZ2VfaWQsDQo+dm9pZCAqcHJpdikNCj4rew0KPisJc3RydWN0IGlpb19kZXYgKmluZGlv
X2RldiA9IChzdHJ1Y3QgaWlvX2RldiAqKXByaXY7DQo+KwlzdHJ1Y3QgaGlkX3NlbnNvcl9hdHRy
aWJ1dGVzICpzdCA9IGlpb19wcml2KGluZGlvX2Rldik7DQo+KwlzdHJ1Y3QgYWNjZWxfM2Rfc3Rh
dGUgKmFjY2VsX3N0YXRlID0NCj4rCQkJKHN0cnVjdCBhY2NlbF8zZF9zdGF0ZSAqKXN0LT5wcml2
YXRlOw0KPisNCj4rCWhpZF9kYmcoaGRldiwgImFjY2VsXzNkX3Byb2NfZXZlbnRcbiIpOw0KPisJ
aWYgKHN0LT5kYXRhX3JlYWR5KQ0KPisJCWhpZF9zZW5zb3JfcHVzaF9kYXRhX3RvX3JpbmcoaW5k
aW9fZGV2LA0KPisJCQkJKHU4ICopJmFjY2VsX3N0YXRlLT5hY2NlbF9zYW1wbGVfZGF0YSwNCj4r
CQkJCXNpemVvZihzdHJ1Y3QgYWNjZWxfM2Rfc2FtcGxlKSk7DQo+KwllbHNlDQo+KwkJaGlkX2Ri
ZyhoZGV2LCAiYWNjZWxfM2RfcHJvY19ldmVudCBkYXRhIG5vdCByZWFkeVxuIik7DQo+KwlyZXR1
cm4gMDsNCj4rfQ0KPisNCj4rLyogQ2FwdHVyZSBzYW1wbGVzIGluIGxvY2FsIHN0b3JhZ2UgKi8g
aW50IA0KPithY2NlbF8zZF9jYXB0dXJlX3NhbXBsZShzdHJ1Y3QgaGlkX2RldmljZSAqaGRldiwg
dW5zaWduZWQNCj51c2FnZV9pZCwNCj4rCQkJCSBzaXplX3QgcmF3X2xlbiwgY2hhciAqcmF3X2Rh
dGEsIHZvaWQgKnByaXYpIHsNCj4rCXN0cnVjdCBpaW9fZGV2ICppbmRpb19kZXYgPSAoc3RydWN0
IGlpb19kZXYgKilwcml2Ow0KPisJc3RydWN0IGhpZF9zZW5zb3JfYXR0cmlidXRlcyAqc3QgPSBp
aW9fcHJpdihpbmRpb19kZXYpOw0KPisJc3RydWN0IGFjY2VsXzNkX3N0YXRlICphY2NlbF9zdGF0
ZSA9DQo+KwkJCShzdHJ1Y3QgYWNjZWxfM2Rfc3RhdGUgKilzdC0+cHJpdmF0ZTsNCj4rDQo+Kwlz
d2l0Y2ggKHVzYWdlX2lkKSB7DQo+KwljYXNlIEhJRF9VU0FHRV9TRU5TT1JfREFUQV9NT1RJT05f
QUNDRUxFUkFUSU9OX1hfQVhJUzoNCj4rCQlhY2NlbF9zdGF0ZS0+YWNjZWxfc2FtcGxlX2RhdGEu
eF9zeiA9IHJhd19sZW47DQo+KwkJYWNjZWxfc3RhdGUtPmFjY2VsX3NhbXBsZV9kYXRhLmFjY2Vs
X3ggPQ0KPisJCSoodTMyICopcmF3X2RhdGE7DQo+KwkJYnJlYWs7DQo+KwljYXNlIEhJRF9VU0FH
RV9TRU5TT1JfREFUQV9NT1RJT05fQUNDRUxFUkFUSU9OX1lfQVhJUzoNCj4rCQlhY2NlbF9zdGF0
ZS0+YWNjZWxfc2FtcGxlX2RhdGEueV9zeiA9IHJhd19sZW47DQo+KwkJYWNjZWxfc3RhdGUtPmFj
Y2VsX3NhbXBsZV9kYXRhLmFjY2VsX3kgPQ0KPisJCSoodTMyICopcmF3X2RhdGE7DQo+KwkJYnJl
YWs7DQo+KwljYXNlIEhJRF9VU0FHRV9TRU5TT1JfREFUQV9NT1RJT05fQUNDRUxFUkFUSU9OX1pf
QVhJUzoNCj4rCQlhY2NlbF9zdGF0ZS0+YWNjZWxfc2FtcGxlX2RhdGEuel9zeiA9IHJhd19sZW47
DQo+KwkJYWNjZWxfc3RhdGUtPmFjY2VsX3NhbXBsZV9kYXRhLmFjY2VsX3ogPQ0KPisJCSoodTMy
ICopcmF3X2RhdGE7DQo+KwkJYnJlYWs7DQo+KwlkZWZhdWx0Og0KPisJCWJyZWFrOw0KPisJfQ0K
PisJcmV0dXJuIDA7DQo+K30NCj4rDQo+Kw0KPisvKiBQYXJzZSByZXBvcnQgd2hpY2ggaXMgc3Bl
Y2lmaWMgdG8gYW4gdXNhZ2UgaWQqLyBzdGF0aWMgaW50IA0KPithY2NlbF8zZF9wYXJzZV9yZXBv
cnQoc3RydWN0IGhpZF9kZXZpY2UgKmhkZXYsIHVuc2lnbmVkDQo+dXNhZ2VfaWQsDQo+KwkJCQlz
dHJ1Y3QgYWNjZWxfM2Rfc3RhdGUgKnN0KQ0KPit7DQo+KwlpbnQgcmV0Ow0KPisNCj4rCXJldCA9
IHNlbnNvcl9odWJfaW5wdXRfZ2V0X2F0dHJpYnV0ZV9pbmZvKGhkZXYsIEhJRF9JTlBVVF9SRVBP
UlQsDQo+KwkJCXVzYWdlX2lkLA0KPisJCQlISURfVVNBR0VfU0VOU09SX0RBVEFfTU9USU9OX0FD
Q0VMRVJBVElPTl9YX0FYSVMsDQo+KwkJCSZzdC0+YWNjZWxfeCk7DQo+KwlpZiAoIXJldCkNCj4r
CQloaWRfZGJnKGhkZXYsICJObyBBY2NlbCBYIGF0dHJpYnV0ZVxuIik7DQo+Kw0KPisNCj4rCXJl
dCA9IHNlbnNvcl9odWJfaW5wdXRfZ2V0X2F0dHJpYnV0ZV9pbmZvKGhkZXYsIEhJRF9JTlBVVF9S
RVBPUlQsDQo+KwkJCXVzYWdlX2lkLA0KPisJCQlISURfVVNBR0VfU0VOU09SX0RBVEFfTU9USU9O
X0FDQ0VMRVJBVElPTl9ZX0FYSVMsDQo+KwkJCSZzdC0+YWNjZWxfeSk7DQo+KwlpZiAoIXJldCkN
Cj4rCQloaWRfZGJnKGhkZXYsICJObyBBY2NlbCBZIGF0dHJpYnV0ZVxuIik7DQo+Kw0KPisNCj4r
CXJldCA9IHNlbnNvcl9odWJfaW5wdXRfZ2V0X2F0dHJpYnV0ZV9pbmZvKGhkZXYsIEhJRF9JTlBV
VF9SRVBPUlQsDQo+KwkJCXVzYWdlX2lkLA0KPisJCQlISURfVVNBR0VfU0VOU09SX0RBVEFfTU9U
SU9OX0FDQ0VMRVJBVElPTl9aX0FYSVMsDQo+KwkJCSZzdC0+YWNjZWxfeik7DQo+KwlpZiAoIXJl
dCkNCj4rCQloaWRfZGJnKGhkZXYsICJObyBBY2NlbCBaIGF0dHJpYnV0ZVxuIik7DQo+Kw0KPisJ
aGlkX2RiZyhoZGV2LCAiYWNjZWxfM2QgJXg6JXgsICV4OiV4LCAleDoleFxuIiwgc3QtPmFjY2Vs
X3guaW5kZXgsDQo+KwkJCXN0LT5hY2NlbF94LnJlcG9ydF9pZCwNCj4rCQkJc3QtPmFjY2VsX3ku
aW5kZXgsIHN0LT5hY2NlbF95LnJlcG9ydF9pZCwNCj4rCQkJc3QtPmFjY2VsX3ouaW5kZXgsIHN0
LT5hY2NlbF96LnJlcG9ydF9pZCk7DQo+Kw0KPisJcmV0dXJuIDA7DQo+K30NCj4rDQo+Ky8qIEVu
dHJ5IGZ1bmN0aW9uIHRvIGluaXRpYWxpemUgdGhlIHByb2Nlc3NpbmcgZm9yIHVzYWdlIGlkICov
IHN0YXRpYyANCj4raW50IGFjY2VsXzNkX2VudGVyKHN0cnVjdCBoaWRfZGV2aWNlICpoZGV2LCB1
bnNpZ25lZCB1c2FnZV9pZCwNCj4rCQkJCXZvaWQgKipwcml2KQ0KPit7DQo+KwlpbnQgcmV0ID0g
MDsNCj4rCXN0YXRpYyBjaGFyICpuYW1lID0gImFjY2VsXzNkIjsNCj4rCXN0cnVjdCBpaW9fZGV2
ICppbmRpb19kZXY7DQo+KwlzdHJ1Y3QgYWNjZWxfM2Rfc3RhdGUgKmFjY2VsX3N0YXRlOw0KPisJ
c3RydWN0IGhpZF9zZW5zb3JfYXR0cmlidXRlcyAqc3Q7DQo+Kw0KPisJYWNjZWxfc3RhdGUgPSBr
emFsbG9jKHNpemVvZihzdHJ1Y3QgYWNjZWxfM2Rfc3RhdGUpLCBHRlBfS0VSTkVMKTsNCj4rCWlm
IChhY2NlbF9zdGF0ZSA9PSBOVUxMKSB7DQo+KwkJcmV0ID0gLUVOT01FTTsNCj4rCQlnb3RvIGVy
cm9yX3JldDsNCj4rCX0NCj4rDQo+KwlpbmRpb19kZXYgPSBpaW9fYWxsb2NhdGVfZGV2aWNlKHNp
emVvZihzdHJ1Y3QNCj5oaWRfc2Vuc29yX2F0dHJpYnV0ZXMpKTsNCj4rCWlmIChpbmRpb19kZXYg
PT0gTlVMTCkgew0KPisJCXJldCA9IC1FTk9NRU07DQo+KwkJZ290byBlcnJvcl9mcmVlX3N0YXRl
Ow0KPisJfQ0KPisJc3QgPSBpaW9fcHJpdihpbmRpb19kZXYpOw0KPisJc3QtPnVzYWdlX2lkID0g
dXNhZ2VfaWQ7DQo+KwlzdC0+aGRldiA9IGhkZXY7DQo+KwlzdC0+cHJpdmF0ZSA9ICh2b2lkICop
YWNjZWxfc3RhdGU7DQo+Kw0KPisJcmV0ID0gaGlkX3NlbnNvcl9wYXJzZV9jb21tb25fYXR0cmli
dXRlcyhoZGV2LCB1c2FnZV9pZCwgc3QpOw0KPisJaWYgKHJldCkgew0KPisJCWhpZF9lcnIoaGRl
diwgImZhaWxlZCB0byBzZXR1cCBjb21tb24gYXR0cmlidXRlc1xuIik7DQo+KwkJZ290byBlcnJv
cl9mcmVlX2RldjsNCj4rCX0NCj4rCXJldCA9IGFjY2VsXzNkX3BhcnNlX3JlcG9ydChoZGV2LCB1
c2FnZV9pZCwgYWNjZWxfc3RhdGUpOw0KPisJaWYgKHJldCkgew0KPisJCWhpZF9lcnIoaGRldiwg
ImZhaWxlZCB0byBzZXR1cCBhdHRyaWJ1dGVzXG4iKTsNCj4rCQlnb3RvIGVycm9yX2ZyZWVfZGV2
Ow0KPisJfQ0KPisNCj4rCWluZGlvX2Rldi0+Y2hhbm5lbHMgPSBhY2NlbF8zZF9jaGFubmVsczsN
Cj4rCWluZGlvX2Rldi0+bnVtX2NoYW5uZWxzID0NCj4rCQkJCUFSUkFZX1NJWkUoYWNjZWxfM2Rf
Y2hhbm5lbHMpOw0KPisJaW5kaW9fZGV2LT5kZXYucGFyZW50ID0gJmhkZXYtPmRldjsNCj4rCWlu
ZGlvX2Rldi0+aW5mbyA9ICZhY2NlbF8zZF9pbmZvOw0KPisJaW5kaW9fZGV2LT5uYW1lID0gbmFt
ZTsNCj4rCWluZGlvX2Rldi0+bW9kZXMgPSBJTkRJT19ESVJFQ1RfTU9ERTsNCj4rDQo+KwlyZXQg
PSBoaWRfc2Vuc29yX2NvbmZpZ3VyZV9yaW5nKGluZGlvX2Rldik7DQo+KwlpZiAocmV0KSB7DQo+
KwkJaGlkX2VycihoZGV2LCAiZmFpbGVkIHRvIGluaXRpYWxpemUgdGhlIHJpbmdcbiIpOw0KPisJ
CWdvdG8gZXJyb3JfZnJlZV9kZXY7DQo+Kwl9DQo+Kw0KPisJcmV0ID0gaWlvX2J1ZmZlcl9yZWdp
c3RlcihpbmRpb19kZXYsDQo+KwkJCQkJYWNjZWxfM2RfY2hhbm5lbHMsDQo+KwkJCQkJQVJSQVlf
U0laRShhY2NlbF8zZF9jaGFubmVscykpOw0KPisJaWYgKHJldCkgew0KPisJCWhpZF9lcnIoaGRl
diwgImZhaWxlZCB0byBpbml0aWFsaXplIHRoZSByaW5nXG4iKTsNCj4rCQlnb3RvIGVycm9yX3Vu
cmVnX3JpbmdfZnVuY3M7DQo+Kwl9DQo+KwlzdC0+ZGF0YV9yZWFkeSA9IHRydWU7DQo+KwlyZXQg
PSBoaWRfc2Vuc29yX3NldHVwX3RyaWdnZXIoaW5kaW9fZGV2LCBuYW1lKTsNCj4rCWlmIChyZXQg
PCAwKSB7DQo+KwkJaGlkX2VycihoZGV2LCAidHJpZ2dlciBzZXR1cCBmYWlsZWRcbiIpOw0KPisJ
CWdvdG8gZXJyb3JfdW5pbml0X3Jpbmc7DQo+Kwl9DQo+Kw0KPisJcmV0ID0gaWlvX2RldmljZV9y
ZWdpc3RlcihpbmRpb19kZXYpOw0KPisJaWYgKHJldCkgew0KPisJCWhpZF9lcnIoaGRldiwgImRl
dmljZSByZWdpc3RlciBmYWlsZWRcbiIpOw0KPisJCWdvdG8gZXJyb3JfcmVtb3ZlX3RyaWdnZXI7
DQo+Kwl9DQo+KwkqcHJpdiA9ICh2b2lkICopaW5kaW9fZGV2Ow0KPisJcmV0dXJuIHJldDsNCj4r
DQo+K2Vycm9yX3JlbW92ZV90cmlnZ2VyOg0KPisJCWhpZF9zZW5zb3JfcmVtb3ZlX3RyaWdnZXIo
aW5kaW9fZGV2KTsNCj4rZXJyb3JfdW5pbml0X3Jpbmc6DQo+KwkJaWlvX2J1ZmZlcl91bnJlZ2lz
dGVyKGluZGlvX2Rldik7DQo+K2Vycm9yX3VucmVnX3JpbmdfZnVuY3M6DQo+KwkJaGlkX3NlbnNv
cl9yaW5nX2NsZWFudXAoaW5kaW9fZGV2KTsNCj4rZXJyb3JfZnJlZV9kZXY6DQo+KwkJaWlvX2Zy
ZWVfZGV2aWNlKGluZGlvX2Rldik7DQo+K2Vycm9yX2ZyZWVfc3RhdGU6DQo+KwkJa2ZyZWUoYWNj
ZWxfc3RhdGUpOw0KPitlcnJvcl9yZXQ6DQo+KwkJcmV0dXJuIHJldDsNCj4rfQ0KPisNCj4rc3Rh
dGljIGludCBhY2NlbF8zZF9leGl0KHN0cnVjdCBoaWRfZGV2aWNlICpoZGV2LCB2b2lkICpwcml2
KSB7DQo+KwlpbnQgcmV0ID0gMDsNCj4rCXN0cnVjdCBpaW9fZGV2ICppbmRpb19kZXYgPSAoc3Ry
dWN0IGlpb19kZXYgKilwcml2Ow0KPisJc3RydWN0IGhpZF9zZW5zb3JfYXR0cmlidXRlcyAqc3Qg
PSBpaW9fcHJpdihpbmRpb19kZXYpOw0KPisJc3RydWN0IGFjY2VsXzNkX3N0YXRlICphY2NlbF9z
dGF0ZSA9DQo+KwkJCShzdHJ1Y3QgYWNjZWxfM2Rfc3RhdGUgKilzdC0+cHJpdmF0ZTsNCj4rDQo+
KwlpaW9fZGV2aWNlX3VucmVnaXN0ZXIoaW5kaW9fZGV2KTsNCj4rCWhpZF9zZW5zb3JfcmVtb3Zl
X3RyaWdnZXIoaW5kaW9fZGV2KTsNCj4rCWlpb19idWZmZXJfdW5yZWdpc3RlcihpbmRpb19kZXYp
Ow0KPisJaGlkX3NlbnNvcl9yaW5nX2NsZWFudXAoaW5kaW9fZGV2KTsNCj4rCWlpb19mcmVlX2Rl
dmljZShpbmRpb19kZXYpOw0KPisNCj4rCWtmcmVlKGFjY2VsX3N0YXRlKTsNCj4rCXJldHVybiBy
ZXQ7DQo+K30NCj4rDQo+K3N0YXRpYyBzdHJ1Y3Qgc2Vuc29yX2h1Yl9jYWxsYmFja3MgYWNjZWxf
M2RfY2FsbGJhY2tzID0gew0KPisJLmVudGVyID0gYWNjZWxfM2RfZW50ZXIsDQo+KwkuZXhpdCA9
IGFjY2VsXzNkX2V4aXQsDQo+Kwkuc2VuZF9ldmVudCA9IGFjY2VsXzNkX3Byb2NfZXZlbnQsDQo+
KwkuY2FwdHVyZV9zYW1wbGUgPSBhY2NlbF8zZF9jYXB0dXJlX3NhbXBsZSwgfTsNCj4rDQo+K3N0
cnVjdCBzZW5zb3JfaHViX2NhbGxiYWNrcyAgKmFjY2VsXzNkX3JlZ2lzdGVyX2NhbGxiYWNrcyh2
b2lkKQ0KPit7DQo+KwlyZXR1cm4gJmFjY2VsXzNkX2NhbGxiYWNrczsNCj4rfQ0KPmRpZmYgLS1n
aXQgYS9kcml2ZXJzL3N0YWdpbmcvaGlkLXNlbnNvcnMvaGlkLXNlbnNvci1odWIuYw0KPmIvZHJp
dmVycy9zdGFnaW5nL2hpZC1zZW5zb3JzL2hpZC1zZW5zb3ItaHViLmMNCj5pbmRleCAzODRlMGQw
Li41NWFlNTYyIDEwMDY0NA0KPi0tLSBhL2RyaXZlcnMvc3RhZ2luZy9oaWQtc2Vuc29ycy9oaWQt
c2Vuc29yLWh1Yi5jDQo+KysrIGIvZHJpdmVycy9zdGFnaW5nL2hpZC1zZW5zb3JzL2hpZC1zZW5z
b3ItaHViLmMNCj5AQCAtNjAsNiArNjAsNyBAQCBzdHJ1Y3Qgc2Vuc29yX2h1Yl9jYWxsYmFja3Nf
bGlzdCB7ICB9Ow0KPiANCj4gc3RhdGljIHN0cnVjdCBzZW5zb3JfaHViX2NhbGxiYWNrc19saXN0
IHVzYWdlX2NhbGxiYWNrc1tdID0gew0KPisJe0hJRF9VU0FHRV9TRU5TT1JfQUNDRUxfM0QsIGFj
Y2VsXzNkX3JlZ2lzdGVyX2NhbGxiYWNrc30sDQo+IAl7MH0NCj4gfTsNCj4gDQo+ZGlmZiAtLWdp
dCBhL2RyaXZlcnMvc3RhZ2luZy9oaWQtc2Vuc29ycy9oaWQtc2Vuc29yLWludGVyZmFjZS5oDQo+
Yi9kcml2ZXJzL3N0YWdpbmcvaGlkLXNlbnNvcnMvaGlkLXNlbnNvci1pbnRlcmZhY2UuaA0KPmlu
ZGV4IDQ3NzQ5NGYuLjNmNGZlNTcgMTAwNjQ0DQo+LS0tIGEvZHJpdmVycy9zdGFnaW5nL2hpZC1z
ZW5zb3JzL2hpZC1zZW5zb3ItaW50ZXJmYWNlLmgNCj4rKysgYi9kcml2ZXJzL3N0YWdpbmcvaGlk
LXNlbnNvcnMvaGlkLXNlbnNvci1pbnRlcmZhY2UuaA0KPkBAIC04NCw0ICs4NCw3IEBAIHZvaWQg
aGlkX3NlbnNvcl9wdXNoX2RhdGFfdG9fcmluZyhzdHJ1Y3QgaWlvX2RldiANCj4qaW5kaW9fZGV2
LCB1OCAqZGF0YSwgIGludCBoaWRfc2Vuc29yX3NldHVwX3RyaWdnZXIoc3RydWN0IGlpb19kZXYg
DQo+KmluZGlvX2RldiwgY2hhciAqbmFtZSk7ICB2b2lkIGhpZF9zZW5zb3JfcmVtb3ZlX3RyaWdn
ZXIoc3RydWN0IGlpb19kZXYgDQo+KmluZGlvX2Rldik7DQo+IA0KPisvKiBTZW5zb3IgdXNhZ2Ug
aWQgcHJvY2Vzc2luZyBjYWxsYmFja3MgKi8gc3RydWN0IHNlbnNvcl9odWJfY2FsbGJhY2tzICAN
Cj4rKmFjY2VsXzNkX3JlZ2lzdGVyX2NhbGxiYWNrcyh2b2lkKTsNCj4rDQo+ICNlbmRpZg0KPi0t
DQo+MS43LjcuNg0KPg0KPi0tDQo+VG8gdW5zdWJzY3JpYmUgZnJvbSB0aGlzIGxpc3Q6IHNlbmQg
dGhlIGxpbmUgInVuc3Vic2NyaWJlIGxpbnV4LWlpbyIgaW4gDQo+dGhlIGJvZHkgb2YgYSBtZXNz
YWdlIHRvIG1ham9yZG9tb0B2Z2VyLmtlcm5lbC5vcmcgTW9yZSBtYWpvcmRvbW8gaW5mbyANCj5h
dCAgaHR0cDovL3ZnZXIua2VybmVsLm9yZy9tYWpvcmRvbW8taW5mby5odG1sDQoNCi0tDQpTZW50
IGZyb20gbXkgQW5kcm9pZCBwaG9uZSB3aXRoIEstOSBNYWlsLiBQbGVhc2UgZXhjdXNlIG15IGJy
ZXZpdHkuDQo=
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH, 4/7] HID-Sensors: Added accelerometer 3D
2012-06-06 16:57 ` Pandruvada, Srinivas
@ 2012-06-06 17:07 ` Lars-Peter Clausen
2012-06-06 17:06 ` Pandruvada, Srinivas
2012-06-07 8:10 ` Jonathan Cameron
1 sibling, 1 reply; 16+ messages in thread
From: Lars-Peter Clausen @ 2012-06-06 17:07 UTC (permalink / raw)
To: Pandruvada, Srinivas
Cc: Jonathan Cameron, linux-input@vger.kernel.org,
linux-iio@vger.kernel.org
On 06/06/2012 06:57 PM, Pandruvada, Srinivas wrote:
> The USB sensor spec has a report structure which it sends as part of report descriptor we get during initial plug in. [...]
Is the USB sensor spec publicly available somewhere?
Thanks,
- Lars
^ permalink raw reply [flat|nested] 16+ messages in thread
* RE: [PATCH, 4/7] HID-Sensors: Added accelerometer 3D
2012-06-06 17:07 ` Lars-Peter Clausen
@ 2012-06-06 17:06 ` Pandruvada, Srinivas
0 siblings, 0 replies; 16+ messages in thread
From: Pandruvada, Srinivas @ 2012-06-06 17:06 UTC (permalink / raw)
To: Lars-Peter Clausen
Cc: Jonathan Cameron, linux-input@vger.kernel.org,
linux-iio@vger.kernel.org
WWVzLiBZb3UgY2FuIGRvd25sb2FkIGZyb206DQp3d3cudXNiLm9yZy9kZXZlbG9wZXJzL2hpZHBh
Z2UvSFVUUlIzOWIucGRmDQoNClRoYW5rcywNClNyaW5pdmFzDQoNCi0tLS0tT3JpZ2luYWwgTWVz
c2FnZS0tLS0tDQpGcm9tOiBMYXJzLVBldGVyIENsYXVzZW4gW21haWx0bzpsYXJzQG1ldGFmb28u
ZGVdIA0KU2VudDogV2VkbmVzZGF5LCBKdW5lIDA2LCAyMDEyIDEwOjA3IEFNDQpUbzogUGFuZHJ1
dmFkYSwgU3Jpbml2YXMNCkNjOiBKb25hdGhhbiBDYW1lcm9uOyBsaW51eC1pbnB1dEB2Z2VyLmtl
cm5lbC5vcmc7IGxpbnV4LWlpb0B2Z2VyLmtlcm5lbC5vcmcNClN1YmplY3Q6IFJlOiBbUEFUQ0gs
IDQvN10gSElELVNlbnNvcnM6IEFkZGVkIGFjY2VsZXJvbWV0ZXIgM0QNCg0KT24gMDYvMDYvMjAx
MiAwNjo1NyBQTSwgUGFuZHJ1dmFkYSwgU3Jpbml2YXMgd3JvdGU6DQo+IFRoZSBVU0Igc2Vuc29y
IHNwZWMgaGFzIGEgcmVwb3J0IHN0cnVjdHVyZSB3aGljaCBpdCBzZW5kcyBhcyBwYXJ0IG9mIHJl
cG9ydCBkZXNjcmlwdG9yIHdlIGdldCBkdXJpbmcgaW5pdGlhbCBwbHVnIGluLiBbLi4uXQ0KDQpJ
cyB0aGUgVVNCIHNlbnNvciBzcGVjIHB1YmxpY2x5IGF2YWlsYWJsZSBzb21ld2hlcmU/DQoNClRo
YW5rcywNCi0gTGFycw0KDQo=
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH, 4/7] HID-Sensors: Added accelerometer 3D
2012-06-06 16:57 ` Pandruvada, Srinivas
2012-06-06 17:07 ` Lars-Peter Clausen
@ 2012-06-07 8:10 ` Jonathan Cameron
2012-06-07 15:41 ` Pandruvada, Srinivas
1 sibling, 1 reply; 16+ messages in thread
From: Jonathan Cameron @ 2012-06-07 8:10 UTC (permalink / raw)
To: Pandruvada, Srinivas
Cc: linux-input@vger.kernel.org, linux-iio@vger.kernel.org
On 6/6/2012 5:57 PM, Pandruvada, Srinivas wrote:
> The USB sensor spec has a report structure which it sends as part of report descriptor we get during initial plug in. This report structure describes elements and their sizes. For example, it may say that an Accelerometer X axis value as 4 bytes long and what is the exponent and unit. Also it sends what control elements it has.
> The sequence is
> - Set sensitivity, interval, activate sys-fs interface. The USB sensor will send an event by USB-IN report when the captured sample is changed by sensitivity value and stable for at least interval. Also you need to activate the sensor so that the usb will start sending events.
>
> - Once USB report with the captured sample arrives, I format the data as defined in " struct accel_3d_sample" below and push to IIO ring buffer.
> I define a single channel
> IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X_AND_Y_AND_Z,
> IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
> IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
> ACCEL_X_Y_Z, ACCEL_3D_SCAN_ACC_X_Y_Z,
> IIO_ST('u', sizeof(struct accel_3d_sample) * 8,
> sizeof(struct accel_3d_sample) * 8, 0), 0), };
>
> Please suggest me if this is not the way IIO channel used.
You have 3 channels here. The iio buffer interface will handle the
fact that they are 'at the same time' on it's own.
Btw I've killed off that macro so this won't build against current
tree... Feel free if sensible to define a local macro. The global one
was a maintenance nightmare hence we scrapped it...
Sketching out what you should have
{
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_X,
.info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
.scan_index = 0,
.scan_type = {
.sign = 's',
.realbits = 12,
.storagebits = 16,
},
}, {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Y,
.info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
.scan_index = 1,
.scan_type = {
.sign = 's',
.realbits = 12,
.storagebits = 16,
},
}, {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Y,
.info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
.scan_index = 2,
.scan_type = {
.sign = 's',
.realbits = 12,
.storagebits = 16,
},
Actually given you had scale and offset for your combined channel, those
should probably be the SHARED versions.
The scan type is for a device that needs bits masked...
Hope that is enough for you to be getting on with. Feel free to
post a v2 without waiting for a formal review!
Jonathan
> Thanks,
> Srinivas
>
>
>
> -----Original Message-----
> From: Jonathan Cameron [mailto:jic23@cam.ac.uk]
> Sent: Wednesday, June 06, 2012 9:29 AM
> To: Pandruvada, Srinivas; linux-input@vger.kernel.org
> Cc: linux-iio@vger.kernel.org
> Subject: Re: [PATCH, 4/7] HID-Sensors: Added accelerometer 3D
>
>
>
> srinivas pandruvada<srinivas.pandruvada@intel.com> wrote:
>
>> From: Srinivas pandruvada<srinivas.pandruvada@intel.com>
>>
>> Added usage id processing for Accelrometer 3D. This uses IIO interfaces
>> "ring/buffer and trigger interface" to present data to user mode.
>
> I do not understand the data format. The way iio describes the format is done through sysfs attrs built from the iio_Chan spec... that way a scan is made up of a number of channel readings each taken at roughly the same time. However each is separately described. Perhaps the description needs extending. Please describe the format.
>>
>> Signed-off-by: Srinivas pandruvada<srinivas.pandruvada@intel.com>
>> ---
>> drivers/staging/hid-sensors/Makefile | 1 +
>> drivers/staging/hid-sensors/hid-sensor-accel-3d.c | 387
>> ++++++++++++++++++++
>> drivers/staging/hid-sensors/hid-sensor-hub.c | 1 +
>> drivers/staging/hid-sensors/hid-sensor-interface.h | 3 +
>> 4 files changed, 392 insertions(+), 0 deletions(-) create mode 100644
>> drivers/staging/hid-sensors/hid-sensor-accel-3d.c
>>
>> diff --git a/drivers/staging/hid-sensors/Makefile
>> b/drivers/staging/hid-sensors/Makefile
>> index 9a03953..4412079 100644
>> --- a/drivers/staging/hid-sensors/Makefile
>> +++ b/drivers/staging/hid-sensors/Makefile
>> @@ -9,4 +9,5 @@ hid-sensors-y := hid-sensor-hub.o hid-sensors-y +=
>> hid-sensor-attributes.o hid-sensors-y += hid-sensor-ring.o
>> hid-sensors-y += hid-sensor-trigger.o
>> +hid-sensors-y += hid-sensor-accel-3d.o
>> obj-$(CONFIG_HID_SENSORS) += hid-sensors.o diff --git
>> a/drivers/staging/hid-sensors/hid-sensor-accel-3d.c
>> b/drivers/staging/hid-sensors/hid-sensor-accel-3d.c
>> new file mode 100644
>> index 0000000..ffe2639
>> --- /dev/null
>> +++ b/drivers/staging/hid-sensors/hid-sensor-accel-3d.c
>> @@ -0,0 +1,387 @@
>> +/*
>> + * HID Sensors Driver
>> + * Copyright (c) 2012, Intel Corporation.
>> + *
>> + * This program is free software; you can redistribute it and/or
>> modify it
>> + * under the terms and conditions of the GNU General Public License,
>> + * version 2, as published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope it will be useful, but
>> WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
>> or
>> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
>> License for
>> + * more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> along with
>> + * this program; if not, write to the Free Software Foundation, Inc.,
>> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
>> + *
>> + */
>> +#include<linux/device.h>
>> +#include<linux/hid.h>
>> +#include<linux/usb.h>
>> +#include "usbhid/usbhid.h"
>> +#include<linux/module.h>
>> +#include<linux/slab.h>
>> +#include "iio/iio.h"
>> +#include "iio/sysfs.h"
>> +#include "iio/ring_sw.h"
>> +#include "iio/trigger.h"
>> +#include "hid-sensor-ids.h"
>> +#include "hid-sensor-interface.h"
>> +#include "hid-sensor-attributes.h"
>> +
>> +
>> +struct accel_3d_sample {
>> + u16 x_sz;
>> + u32 accel_x;
>> + u16 y_sz;
>> + u32 accel_y;
>> + u16 z_sz;
>> + u32 accel_z;
>> +} __packed;
>> +
>> +struct accel_3d_state {
>> + struct hid_sensor_hub_attribute_info accel_x;
>> + struct hid_sensor_hub_attribute_info accel_y;
>> + struct hid_sensor_hub_attribute_info accel_z;
>> + struct accel_3d_sample accel_sample_data; };
>> +
>> +
>> +enum accel_3d_chan {
>> + ACCEL_X_Y_Z,
>> +};
>> +
>> +enum accel_3d_scan {
>> + ACCEL_3D_SCAN_ACC_X_Y_Z,
>> +};
>> +
>> +static struct iio_chan_spec accel_3d_channels[] = {
>> + IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X_AND_Y_AND_Z,
>> + IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
>> + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
>> + ACCEL_X_Y_Z, ACCEL_3D_SCAN_ACC_X_Y_Z,
>> + IIO_ST('u', sizeof(struct accel_3d_sample) * 8,
>> + sizeof(struct accel_3d_sample) * 8, 0), 0), };
>> +
>> +static ssize_t accel_3d_read_accel(struct device *dev,
>> + struct device_attribute *attr,
>> + char *buf)
>> +{
>> + struct iio_dev *indio_dev = dev_get_drvdata(dev);
>> + struct hid_sensor_attributes *st = iio_priv(indio_dev);
>> + struct accel_3d_state *accel_state =
>> + (struct accel_3d_state *)st->private;
>> + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
>> + int report_id = -1;
>> +
>> + switch (this_attr->address) {
>> + case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS:
>> + report_id = accel_state->accel_x.report_id;
>> + break;
>> + case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS:
>> + report_id = accel_state->accel_y.report_id;
>> + break;
>> + case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS:
>> + report_id = accel_state->accel_z.report_id;
>> + break;
>> + default:
>> + break;
>> + }
>> + if (report_id< 0)
>> + return -EINVAL;
>> +
>> + return sensor_hub_input_attr_get_value(st->hdev,
>> + HID_USAGE_SENSOR_ACCEL_3D, this_attr->address,
>> + report_id, 4, buf);
>> +}
>> +
>> +static int accel_3d_read_raw(struct iio_dev *indio_dev,
>> + struct iio_chan_spec const *chan,
>> + int *val, int *val2,
>> + long mask)
>> +{
>> + struct hid_sensor_attributes *st = iio_priv(indio_dev);
>> + struct accel_3d_state *accel_state =
>> + (struct accel_3d_state *)st->private;
>> + *val = 0;
>> + *val2 = 0;
>> +
>> + switch (mask) {
>> + case 0:
>> + break;
>> + case IIO_CHAN_INFO_SCALE:
>> + *val = accel_state->accel_x.units;
>> + break;
>> + case IIO_CHAN_INFO_OFFSET:
>> + *val = accel_state->accel_x.unit_expo;
>> + break;
>> + default:
>> + break;
>> +
>> + }
>> + return IIO_VAL_INT;
>> +}
>> +
>> +static int accel_3d_write_raw(struct iio_dev *indio_dev,
>> + struct iio_chan_spec const *chan,
>> + int val,
>> + int val2,
>> + long mask)
>> +{
>> + printk(KERN_ERR "%s\n", __func__);
>> +
>> + return 0;
>> +}
>> +
>> +/* Usage specific attributes */
>> +#define IIO_DEV_ATTR_ACCEL_OFFSET(_mode, _show, _store, _addr) \
>> + IIO_DEVICE_ATTR(accel_offset, _mode, _show, _store, _addr)
>> +
>> +#define IIO_DEV_ATTR_ACCEL_X_OFFSET(_mode, _show, _store, _addr)
>> \
>> + IIO_DEVICE_ATTR(accel_x_offset, _mode, _show, _store, _addr)
>> +
>> +#define IIO_DEV_ATTR_ACCEL_Y_OFFSET(_mode, _show, _store, _addr)
>> \
>> + IIO_DEVICE_ATTR(accel_y_offset, _mode, _show, _store, _addr)
>> +
>> +#define IIO_DEV_ATTR_ACCEL_Z_OFFSET(_mode, _show, _store, _addr)
>> \
>> + IIO_DEVICE_ATTR(accel_z_offset, _mode, _show, _store, _addr)
>> +
>> +#define IIO_DEV_ATTR_ACCEL_SENSITIVITY(_mode, _show, _store, _addr)
>> \
>> + IIO_DEVICE_ATTR(accel_sensitivity, _mode, _show, _store, _addr)
>> +
>> +static IIO_DEV_ATTR_ACCEL_X_OFFSET(S_IWUSR | S_IRUGO,
>> accel_3d_read_accel,
>> + NULL, HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS);
>> +static IIO_DEV_ATTR_ACCEL_Y_OFFSET(S_IWUSR | S_IRUGO,
>> accel_3d_read_accel,
>> + NULL, HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS);
>> +static IIO_DEV_ATTR_ACCEL_Z_OFFSET(S_IWUSR | S_IRUGO,
>> accel_3d_read_accel,
>> + NULL, HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS);
>> +
>> +static struct attribute *accel_3d_attributes[] = {
>> + /* common attributes */
>> + &iio_dev_attr_poll_interval.dev_attr.attr,
>> + &iio_dev_attr_sensitivity.dev_attr.attr,
>> + &iio_dev_attr_activate.dev_attr.attr,
>> + /* Usage specific attributes */
>> + &iio_dev_attr_accel_x_offset.dev_attr.attr,
>> + &iio_dev_attr_accel_y_offset.dev_attr.attr,
>> + &iio_dev_attr_accel_z_offset.dev_attr.attr,
>> + NULL,
>> +};
>> +
>> +static const struct attribute_group accel_3d_attribute_group = {
>> + .attrs = accel_3d_attributes,
>> +};
>> +
>> +static const struct iio_info accel_3d_info = {
>> + .attrs =&accel_3d_attribute_group,
>> + .driver_module = THIS_MODULE,
>> + .read_raw =&accel_3d_read_raw,
>> + .write_raw =&accel_3d_write_raw,
>> +};
>> +
>> +
>> +/* Function to push data to IIO ring */ int accel_3d_proc_event(struct
>> +hid_device *hdev, unsigned usage_id,
>> void *priv)
>> +{
>> + struct iio_dev *indio_dev = (struct iio_dev *)priv;
>> + struct hid_sensor_attributes *st = iio_priv(indio_dev);
>> + struct accel_3d_state *accel_state =
>> + (struct accel_3d_state *)st->private;
>> +
>> + hid_dbg(hdev, "accel_3d_proc_event\n");
>> + if (st->data_ready)
>> + hid_sensor_push_data_to_ring(indio_dev,
>> + (u8 *)&accel_state->accel_sample_data,
>> + sizeof(struct accel_3d_sample));
>> + else
>> + hid_dbg(hdev, "accel_3d_proc_event data not ready\n");
>> + return 0;
>> +}
>> +
>> +/* Capture samples in local storage */ int
>> +accel_3d_capture_sample(struct hid_device *hdev, unsigned
>> usage_id,
>> + size_t raw_len, char *raw_data, void *priv) {
>> + struct iio_dev *indio_dev = (struct iio_dev *)priv;
>> + struct hid_sensor_attributes *st = iio_priv(indio_dev);
>> + struct accel_3d_state *accel_state =
>> + (struct accel_3d_state *)st->private;
>> +
>> + switch (usage_id) {
>> + case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS:
>> + accel_state->accel_sample_data.x_sz = raw_len;
>> + accel_state->accel_sample_data.accel_x =
>> + *(u32 *)raw_data;
>> + break;
>> + case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS:
>> + accel_state->accel_sample_data.y_sz = raw_len;
>> + accel_state->accel_sample_data.accel_y =
>> + *(u32 *)raw_data;
>> + break;
>> + case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS:
>> + accel_state->accel_sample_data.z_sz = raw_len;
>> + accel_state->accel_sample_data.accel_z =
>> + *(u32 *)raw_data;
>> + break;
>> + default:
>> + break;
>> + }
>> + return 0;
>> +}
>> +
>> +
>> +/* Parse report which is specific to an usage id*/ static int
>> +accel_3d_parse_report(struct hid_device *hdev, unsigned
>> usage_id,
>> + struct accel_3d_state *st)
>> +{
>> + int ret;
>> +
>> + ret = sensor_hub_input_get_attribute_info(hdev, HID_INPUT_REPORT,
>> + usage_id,
>> + HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS,
>> + &st->accel_x);
>> + if (!ret)
>> + hid_dbg(hdev, "No Accel X attribute\n");
>> +
>> +
>> + ret = sensor_hub_input_get_attribute_info(hdev, HID_INPUT_REPORT,
>> + usage_id,
>> + HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS,
>> + &st->accel_y);
>> + if (!ret)
>> + hid_dbg(hdev, "No Accel Y attribute\n");
>> +
>> +
>> + ret = sensor_hub_input_get_attribute_info(hdev, HID_INPUT_REPORT,
>> + usage_id,
>> + HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS,
>> + &st->accel_z);
>> + if (!ret)
>> + hid_dbg(hdev, "No Accel Z attribute\n");
>> +
>> + hid_dbg(hdev, "accel_3d %x:%x, %x:%x, %x:%x\n", st->accel_x.index,
>> + st->accel_x.report_id,
>> + st->accel_y.index, st->accel_y.report_id,
>> + st->accel_z.index, st->accel_z.report_id);
>> +
>> + return 0;
>> +}
>> +
>> +/* Entry function to initialize the processing for usage id */ static
>> +int accel_3d_enter(struct hid_device *hdev, unsigned usage_id,
>> + void **priv)
>> +{
>> + int ret = 0;
>> + static char *name = "accel_3d";
>> + struct iio_dev *indio_dev;
>> + struct accel_3d_state *accel_state;
>> + struct hid_sensor_attributes *st;
>> +
>> + accel_state = kzalloc(sizeof(struct accel_3d_state), GFP_KERNEL);
>> + if (accel_state == NULL) {
>> + ret = -ENOMEM;
>> + goto error_ret;
>> + }
>> +
>> + indio_dev = iio_allocate_device(sizeof(struct
>> hid_sensor_attributes));
>> + if (indio_dev == NULL) {
>> + ret = -ENOMEM;
>> + goto error_free_state;
>> + }
>> + st = iio_priv(indio_dev);
>> + st->usage_id = usage_id;
>> + st->hdev = hdev;
>> + st->private = (void *)accel_state;
>> +
>> + ret = hid_sensor_parse_common_attributes(hdev, usage_id, st);
>> + if (ret) {
>> + hid_err(hdev, "failed to setup common attributes\n");
>> + goto error_free_dev;
>> + }
>> + ret = accel_3d_parse_report(hdev, usage_id, accel_state);
>> + if (ret) {
>> + hid_err(hdev, "failed to setup attributes\n");
>> + goto error_free_dev;
>> + }
>> +
>> + indio_dev->channels = accel_3d_channels;
>> + indio_dev->num_channels =
>> + ARRAY_SIZE(accel_3d_channels);
>> + indio_dev->dev.parent =&hdev->dev;
>> + indio_dev->info =&accel_3d_info;
>> + indio_dev->name = name;
>> + indio_dev->modes = INDIO_DIRECT_MODE;
>> +
>> + ret = hid_sensor_configure_ring(indio_dev);
>> + if (ret) {
>> + hid_err(hdev, "failed to initialize the ring\n");
>> + goto error_free_dev;
>> + }
>> +
>> + ret = iio_buffer_register(indio_dev,
>> + accel_3d_channels,
>> + ARRAY_SIZE(accel_3d_channels));
>> + if (ret) {
>> + hid_err(hdev, "failed to initialize the ring\n");
>> + goto error_unreg_ring_funcs;
>> + }
>> + st->data_ready = true;
>> + ret = hid_sensor_setup_trigger(indio_dev, name);
>> + if (ret< 0) {
>> + hid_err(hdev, "trigger setup failed\n");
>> + goto error_uninit_ring;
>> + }
>> +
>> + ret = iio_device_register(indio_dev);
>> + if (ret) {
>> + hid_err(hdev, "device register failed\n");
>> + goto error_remove_trigger;
>> + }
>> + *priv = (void *)indio_dev;
>> + return ret;
>> +
>> +error_remove_trigger:
>> + hid_sensor_remove_trigger(indio_dev);
>> +error_uninit_ring:
>> + iio_buffer_unregister(indio_dev);
>> +error_unreg_ring_funcs:
>> + hid_sensor_ring_cleanup(indio_dev);
>> +error_free_dev:
>> + iio_free_device(indio_dev);
>> +error_free_state:
>> + kfree(accel_state);
>> +error_ret:
>> + return ret;
>> +}
>> +
>> +static int accel_3d_exit(struct hid_device *hdev, void *priv) {
>> + int ret = 0;
>> + struct iio_dev *indio_dev = (struct iio_dev *)priv;
>> + struct hid_sensor_attributes *st = iio_priv(indio_dev);
>> + struct accel_3d_state *accel_state =
>> + (struct accel_3d_state *)st->private;
>> +
>> + iio_device_unregister(indio_dev);
>> + hid_sensor_remove_trigger(indio_dev);
>> + iio_buffer_unregister(indio_dev);
>> + hid_sensor_ring_cleanup(indio_dev);
>> + iio_free_device(indio_dev);
>> +
>> + kfree(accel_state);
>> + return ret;
>> +}
>> +
>> +static struct sensor_hub_callbacks accel_3d_callbacks = {
>> + .enter = accel_3d_enter,
>> + .exit = accel_3d_exit,
>> + .send_event = accel_3d_proc_event,
>> + .capture_sample = accel_3d_capture_sample, };
>> +
>> +struct sensor_hub_callbacks *accel_3d_register_callbacks(void)
>> +{
>> + return&accel_3d_callbacks;
>> +}
>> diff --git a/drivers/staging/hid-sensors/hid-sensor-hub.c
>> b/drivers/staging/hid-sensors/hid-sensor-hub.c
>> index 384e0d0..55ae562 100644
>> --- a/drivers/staging/hid-sensors/hid-sensor-hub.c
>> +++ b/drivers/staging/hid-sensors/hid-sensor-hub.c
>> @@ -60,6 +60,7 @@ struct sensor_hub_callbacks_list { };
>>
>> static struct sensor_hub_callbacks_list usage_callbacks[] = {
>> + {HID_USAGE_SENSOR_ACCEL_3D, accel_3d_register_callbacks},
>> {0}
>> };
>>
>> diff --git a/drivers/staging/hid-sensors/hid-sensor-interface.h
>> b/drivers/staging/hid-sensors/hid-sensor-interface.h
>> index 477494f..3f4fe57 100644
>> --- a/drivers/staging/hid-sensors/hid-sensor-interface.h
>> +++ b/drivers/staging/hid-sensors/hid-sensor-interface.h
>> @@ -84,4 +84,7 @@ void hid_sensor_push_data_to_ring(struct iio_dev
>> *indio_dev, u8 *data, int hid_sensor_setup_trigger(struct iio_dev
>> *indio_dev, char *name); void hid_sensor_remove_trigger(struct iio_dev
>> *indio_dev);
>>
>> +/* Sensor usage id processing callbacks */ struct sensor_hub_callbacks
>> +*accel_3d_register_callbacks(void);
>> +
>> #endif
>> --
>> 1.7.7.6
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
>> the body of a message to majordomo@vger.kernel.org More majordomo info
>> at http://vger.kernel.org/majordomo-info.html
>
> --
> Sent from my Android phone with K-9 Mail. Please excuse my brevity.
^ permalink raw reply [flat|nested] 16+ messages in thread* RE: [PATCH, 4/7] HID-Sensors: Added accelerometer 3D
2012-06-07 8:10 ` Jonathan Cameron
@ 2012-06-07 15:41 ` Pandruvada, Srinivas
2012-06-07 20:27 ` Jonathan Cameron
0 siblings, 1 reply; 16+ messages in thread
From: Pandruvada, Srinivas @ 2012-06-07 15:41 UTC (permalink / raw)
To: Jonathan Cameron; +Cc: linux-input@vger.kernel.org, linux-iio@vger.kernel.org
VGhhbmtzIGZvciB5b3VyIGV4Y2VsbGVudCBjb21tZW50cy4gSSB0aGluayBJIGdldCBzb21lIGlk
ZWEgbm93Lg0KDQpEbyB5b3UgdGhpbmsgdGhlIHBsYWNlIGZvciB0aGlzIGRyaXZlciBpcyBpbiAi
c3RhZ2luZy9paW8vaGlkLXNlbnNvcnMiPw0KDQpUaGFua3MsDQpTcmluaXZhcw0KDQoNCg0KDQoN
Cg0KLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCkZyb206IEpvbmF0aGFuIENhbWVyb24gW21h
aWx0bzpqaWMyM0BjYW0uYWMudWtdIA0KU2VudDogVGh1cnNkYXksIEp1bmUgMDcsIDIwMTIgMTox
MSBBTQ0KVG86IFBhbmRydXZhZGEsIFNyaW5pdmFzDQpDYzogbGludXgtaW5wdXRAdmdlci5rZXJu
ZWwub3JnOyBsaW51eC1paW9Admdlci5rZXJuZWwub3JnDQpTdWJqZWN0OiBSZTogW1BBVENILCA0
LzddIEhJRC1TZW5zb3JzOiBBZGRlZCBhY2NlbGVyb21ldGVyIDNEDQoNCk9uIDYvNi8yMDEyIDU6
NTcgUE0sIFBhbmRydXZhZGEsIFNyaW5pdmFzIHdyb3RlOg0KPiBUaGUgVVNCIHNlbnNvciBzcGVj
IGhhcyBhIHJlcG9ydCBzdHJ1Y3R1cmUgd2hpY2ggaXQgc2VuZHMgYXMgcGFydCBvZiByZXBvcnQg
ZGVzY3JpcHRvciB3ZSBnZXQgZHVyaW5nIGluaXRpYWwgcGx1ZyBpbi4gVGhpcyByZXBvcnQgc3Ry
dWN0dXJlIGRlc2NyaWJlcyBlbGVtZW50cyBhbmQgdGhlaXIgc2l6ZXMuIEZvciBleGFtcGxlLCBp
dCBtYXkgc2F5IHRoYXQgYW4gQWNjZWxlcm9tZXRlciBYIGF4aXMgdmFsdWUgYXMgNCBieXRlcyBs
b25nIGFuZCB3aGF0IGlzIHRoZSBleHBvbmVudCBhbmQgdW5pdC4gQWxzbyBpdCBzZW5kcyB3aGF0
IGNvbnRyb2wgZWxlbWVudHMgaXQgaGFzLg0KPiBUaGUgc2VxdWVuY2UgaXMNCj4gLSBTZXQgc2Vu
c2l0aXZpdHksIGludGVydmFsLCBhY3RpdmF0ZSBzeXMtZnMgaW50ZXJmYWNlLiBUaGUgVVNCIHNl
bnNvciB3aWxsIHNlbmQgYW4gZXZlbnQgYnkgVVNCLUlOIHJlcG9ydCB3aGVuIHRoZSBjYXB0dXJl
ZCBzYW1wbGUgaXMgY2hhbmdlZCBieSBzZW5zaXRpdml0eSB2YWx1ZSBhbmQgc3RhYmxlIGZvciBh
dCBsZWFzdCBpbnRlcnZhbC4gQWxzbyB5b3UgbmVlZCB0byBhY3RpdmF0ZSB0aGUgc2Vuc29yIHNv
IHRoYXQgdGhlIHVzYiB3aWxsIHN0YXJ0IHNlbmRpbmcgZXZlbnRzLg0KPg0KPiAtIE9uY2UgVVNC
IHJlcG9ydCB3aXRoIHRoZSBjYXB0dXJlZCBzYW1wbGUgYXJyaXZlcywgSSBmb3JtYXQgdGhlIGRh
dGEgYXMgZGVmaW5lZCBpbiAiIHN0cnVjdCBhY2NlbF8zZF9zYW1wbGUiIGJlbG93IGFuZCBwdXNo
IHRvIElJTyByaW5nIGJ1ZmZlci4NCj4gSSBkZWZpbmUgYSBzaW5nbGUgY2hhbm5lbA0KPiAJSUlP
X0NIQU4oSUlPX0FDQ0VMLCAxLCAwLCAwLCBOVUxMLCAwLCBJSU9fTU9EX1hfQU5EX1lfQU5EX1os
DQo+IAlJSU9fQ0hBTl9JTkZPX1NDQUxFX1NFUEFSQVRFX0JJVCB8DQo+IAlJSU9fQ0hBTl9JTkZP
X09GRlNFVF9TRVBBUkFURV9CSVQsDQo+IAlBQ0NFTF9YX1lfWiwgQUNDRUxfM0RfU0NBTl9BQ0Nf
WF9ZX1osDQo+IAkJIElJT19TVCgndScsIHNpemVvZihzdHJ1Y3QgYWNjZWxfM2Rfc2FtcGxlKSAq
IDgsDQo+IAkJc2l6ZW9mKHN0cnVjdCBhY2NlbF8zZF9zYW1wbGUpICogOCwgMCksIDApLCB9Ow0K
Pg0KPiBQbGVhc2Ugc3VnZ2VzdCBtZSBpZiB0aGlzIGlzIG5vdCB0aGUgd2F5IElJTyBjaGFubmVs
IHVzZWQuDQpZb3UgaGF2ZSAzIGNoYW5uZWxzIGhlcmUuICBUaGUgaWlvIGJ1ZmZlciBpbnRlcmZh
Y2Ugd2lsbCBoYW5kbGUgdGhlIGZhY3QgdGhhdCB0aGV5IGFyZSAnYXQgdGhlIHNhbWUgdGltZScg
b24gaXQncyBvd24uDQoNCkJ0dyBJJ3ZlIGtpbGxlZCBvZmYgdGhhdCBtYWNybyBzbyB0aGlzIHdv
bid0IGJ1aWxkIGFnYWluc3QgY3VycmVudCB0cmVlLi4uICBGZWVsIGZyZWUgaWYgc2Vuc2libGUg
dG8gZGVmaW5lIGEgbG9jYWwgbWFjcm8uICBUaGUgZ2xvYmFsIG9uZSB3YXMgYSBtYWludGVuYW5j
ZSBuaWdodG1hcmUgaGVuY2Ugd2Ugc2NyYXBwZWQgaXQuLi4NCg0KU2tldGNoaW5nIG91dCB3aGF0
IHlvdSBzaG91bGQgaGF2ZQ0KDQp7DQogICAgICAgICAgLnR5cGUgPSBJSU9fQUNDRUwsDQogICAg
ICAgICAgLm1vZGlmaWVkID0gMSwNCiAgICAgICAgICAuY2hhbm5lbDIgPSBJSU9fTU9EX1gsDQog
ICAgICAgICAgLmluZm9fbWFzayA9IElJT19DSEFOX0lORk9fU0NBTEVfU0VQQVJBVEVfQklUIHwN
CiAgCQkgICAgICBJSU9fQ0hBTl9JTkZPX09GRlNFVF9TRVBBUkFURV9CSVQsDQogICAgICAgICAg
LnNjYW5faW5kZXggPSAwLA0KICAgICAgICAgIC5zY2FuX3R5cGUgPSB7DQogICAgICAgICAgICAg
ICAuc2lnbiA9ICdzJywNCiAgICAgICAgICAgICAgIC5yZWFsYml0cyA9IDEyLA0KICAgICAgICAg
ICAgICAgLnN0b3JhZ2ViaXRzID0gMTYsDQogICAgICAgICAgfSwNCn0sIHsNCiAgICAgICAgICAu
dHlwZSA9IElJT19BQ0NFTCwNCiAgICAgICAgICAubW9kaWZpZWQgPSAxLA0KICAgICAgICAgIC5j
aGFubmVsMiA9IElJT19NT0RfWSwNCiAgICAgICAgICAuaW5mb19tYXNrID0gSUlPX0NIQU5fSU5G
T19TQ0FMRV9TRVBBUkFURV9CSVQgfA0KICAJCSAgICAgIElJT19DSEFOX0lORk9fT0ZGU0VUX1NF
UEFSQVRFX0JJVCwNCiAgICAgICAgICAuc2Nhbl9pbmRleCA9IDEsDQogICAgICAgICAgLnNjYW5f
dHlwZSA9IHsNCiAgICAgICAgICAgICAgIC5zaWduID0gJ3MnLA0KICAgICAgICAgICAgICAgLnJl
YWxiaXRzID0gMTIsDQogICAgICAgICAgICAgICAuc3RvcmFnZWJpdHMgPSAxNiwNCiAgICAgICAg
ICB9LA0KfSwgew0KICAgICAgICAgIC50eXBlID0gSUlPX0FDQ0VMLA0KICAgICAgICAgIC5tb2Rp
ZmllZCA9IDEsDQogICAgICAgICAgLmNoYW5uZWwyID0gSUlPX01PRF9ZLA0KICAgICAgICAgIC5p
bmZvX21hc2sgPSBJSU9fQ0hBTl9JTkZPX1NDQUxFX1NFUEFSQVRFX0JJVCB8DQogIAkJICAgICAg
SUlPX0NIQU5fSU5GT19PRkZTRVRfU0VQQVJBVEVfQklULA0KICAgICAgICAgIC5zY2FuX2luZGV4
ID0gMiwNCiAgICAgICAgICAuc2Nhbl90eXBlID0gew0KICAgICAgICAgICAgICAgLnNpZ24gPSAn
cycsDQogICAgICAgICAgICAgICAucmVhbGJpdHMgPSAxMiwNCiAgICAgICAgICAgICAgIC5zdG9y
YWdlYml0cyA9IDE2LA0KICAgICAgICAgIH0sDQpBY3R1YWxseSBnaXZlbiB5b3UgaGFkIHNjYWxl
IGFuZCBvZmZzZXQgZm9yIHlvdXIgY29tYmluZWQgY2hhbm5lbCwgdGhvc2Ugc2hvdWxkIHByb2Jh
Ymx5IGJlIHRoZSBTSEFSRUQgdmVyc2lvbnMuDQoNClRoZSBzY2FuIHR5cGUgaXMgZm9yIGEgZGV2
aWNlIHRoYXQgbmVlZHMgYml0cyBtYXNrZWQuLi4NCg0KSG9wZSB0aGF0IGlzIGVub3VnaCBmb3Ig
eW91IHRvIGJlIGdldHRpbmcgb24gd2l0aC4gIEZlZWwgZnJlZSB0byBwb3N0IGEgdjIgd2l0aG91
dCB3YWl0aW5nIGZvciBhIGZvcm1hbCByZXZpZXchDQoNCkpvbmF0aGFuDQo+IFRoYW5rcywNCj4g
U3Jpbml2YXMNCj4NCj4NCj4NCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTog
Sm9uYXRoYW4gQ2FtZXJvbiBbbWFpbHRvOmppYzIzQGNhbS5hYy51a10NCj4gU2VudDogV2VkbmVz
ZGF5LCBKdW5lIDA2LCAyMDEyIDk6MjkgQU0NCj4gVG86IFBhbmRydXZhZGEsIFNyaW5pdmFzOyBs
aW51eC1pbnB1dEB2Z2VyLmtlcm5lbC5vcmcNCj4gQ2M6IGxpbnV4LWlpb0B2Z2VyLmtlcm5lbC5v
cmcNCj4gU3ViamVjdDogUmU6IFtQQVRDSCwgNC83XSBISUQtU2Vuc29yczogQWRkZWQgYWNjZWxl
cm9tZXRlciAzRA0KPg0KPg0KPg0KPiBzcmluaXZhcyBwYW5kcnV2YWRhPHNyaW5pdmFzLnBhbmRy
dXZhZGFAaW50ZWwuY29tPiAgd3JvdGU6DQo+DQo+PiBGcm9tOiBTcmluaXZhcyBwYW5kcnV2YWRh
PHNyaW5pdmFzLnBhbmRydXZhZGFAaW50ZWwuY29tPg0KPj4NCj4+IEFkZGVkIHVzYWdlIGlkIHBy
b2Nlc3NpbmcgZm9yIEFjY2Vscm9tZXRlciAzRC4gVGhpcyB1c2VzIElJTyANCj4+IGludGVyZmFj
ZXMgInJpbmcvYnVmZmVyIGFuZCB0cmlnZ2VyIGludGVyZmFjZSIgdG8gcHJlc2VudCBkYXRhIHRv
IHVzZXIgbW9kZS4NCj4NCj4gSSBkbyBub3QgdW5kZXJzdGFuZCB0aGUgZGF0YSBmb3JtYXQuICBU
aGUgd2F5IGlpbyBkZXNjcmliZXMgdGhlIGZvcm1hdCBpcyBkb25lIHRocm91Z2ggc3lzZnMgYXR0
cnMgYnVpbHQgZnJvbSB0aGUgaWlvX0NoYW4gc3BlYy4uLiB0aGF0IHdheSBhIHNjYW4gaXMgbWFk
ZSB1cCBvZiBhIG51bWJlciBvZiBjaGFubmVsIHJlYWRpbmdzIGVhY2ggdGFrZW4gYXQgcm91Z2hs
eSB0aGUgc2FtZSB0aW1lLiAgSG93ZXZlciBlYWNoIGlzIHNlcGFyYXRlbHkgZGVzY3JpYmVkLiAg
UGVyaGFwcyB0aGUgZGVzY3JpcHRpb24gbmVlZHMgZXh0ZW5kaW5nLiAgUGxlYXNlIGRlc2NyaWJl
IHRoZSBmb3JtYXQuDQo+Pg0KPj4gU2lnbmVkLW9mZi1ieTogU3Jpbml2YXMgcGFuZHJ1dmFkYTxz
cmluaXZhcy5wYW5kcnV2YWRhQGludGVsLmNvbT4NCj4+IC0tLQ0KPj4gZHJpdmVycy9zdGFnaW5n
L2hpZC1zZW5zb3JzL01ha2VmaWxlICAgICAgICAgICAgICAgfCAgICAxICsNCj4+IGRyaXZlcnMv
c3RhZ2luZy9oaWQtc2Vuc29ycy9oaWQtc2Vuc29yLWFjY2VsLTNkLmMgIHwgIDM4Nw0KPj4gKysr
KysrKysrKysrKysrKysrKysNCj4+IGRyaXZlcnMvc3RhZ2luZy9oaWQtc2Vuc29ycy9oaWQtc2Vu
c29yLWh1Yi5jICAgICAgIHwgICAgMSArDQo+PiBkcml2ZXJzL3N0YWdpbmcvaGlkLXNlbnNvcnMv
aGlkLXNlbnNvci1pbnRlcmZhY2UuaCB8ICAgIDMgKw0KPj4gNCBmaWxlcyBjaGFuZ2VkLCAzOTIg
aW5zZXJ0aW9ucygrKSwgMCBkZWxldGlvbnMoLSkgY3JlYXRlIG1vZGUgMTAwNjQ0IA0KPj4gZHJp
dmVycy9zdGFnaW5nL2hpZC1zZW5zb3JzL2hpZC1zZW5zb3ItYWNjZWwtM2QuYw0KPj4NCj4+IGRp
ZmYgLS1naXQgYS9kcml2ZXJzL3N0YWdpbmcvaGlkLXNlbnNvcnMvTWFrZWZpbGUNCj4+IGIvZHJp
dmVycy9zdGFnaW5nL2hpZC1zZW5zb3JzL01ha2VmaWxlDQo+PiBpbmRleCA5YTAzOTUzLi40NDEy
MDc5IDEwMDY0NA0KPj4gLS0tIGEvZHJpdmVycy9zdGFnaW5nL2hpZC1zZW5zb3JzL01ha2VmaWxl
DQo+PiArKysgYi9kcml2ZXJzL3N0YWdpbmcvaGlkLXNlbnNvcnMvTWFrZWZpbGUNCj4+IEBAIC05
LDQgKzksNSBAQCBoaWQtc2Vuc29ycy15IDo9IGhpZC1zZW5zb3ItaHViLm8gIGhpZC1zZW5zb3Jz
LXkgKz0gDQo+PiBoaWQtc2Vuc29yLWF0dHJpYnV0ZXMubyAgaGlkLXNlbnNvcnMteSArPSBoaWQt
c2Vuc29yLXJpbmcubyANCj4+IGhpZC1zZW5zb3JzLXkgKz0gaGlkLXNlbnNvci10cmlnZ2VyLm8N
Cj4+ICtoaWQtc2Vuc29ycy15ICs9IGhpZC1zZW5zb3ItYWNjZWwtM2Qubw0KPj4gb2JqLSQoQ09O
RklHX0hJRF9TRU5TT1JTKSArPSBoaWQtc2Vuc29ycy5vIGRpZmYgLS1naXQgDQo+PiBhL2RyaXZl
cnMvc3RhZ2luZy9oaWQtc2Vuc29ycy9oaWQtc2Vuc29yLWFjY2VsLTNkLmMNCj4+IGIvZHJpdmVy
cy9zdGFnaW5nL2hpZC1zZW5zb3JzL2hpZC1zZW5zb3ItYWNjZWwtM2QuYw0KPj4gbmV3IGZpbGUg
bW9kZSAxMDA2NDQNCj4+IGluZGV4IDAwMDAwMDAuLmZmZTI2MzkNCj4+IC0tLSAvZGV2L251bGwN
Cj4+ICsrKyBiL2RyaXZlcnMvc3RhZ2luZy9oaWQtc2Vuc29ycy9oaWQtc2Vuc29yLWFjY2VsLTNk
LmMNCj4+IEBAIC0wLDAgKzEsMzg3IEBADQo+PiArLyoNCj4+ICsgKiBISUQgU2Vuc29ycyBEcml2
ZXINCj4+ICsgKiBDb3B5cmlnaHQgKGMpIDIwMTIsIEludGVsIENvcnBvcmF0aW9uLg0KPj4gKyAq
DQo+PiArICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmli
dXRlIGl0IGFuZC9vcg0KPj4gbW9kaWZ5IGl0DQo+PiArICogdW5kZXIgdGhlIHRlcm1zIGFuZCBj
b25kaXRpb25zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSwNCj4+ICsgKiB2ZXJz
aW9uIDIsIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLg0KPj4g
KyAqDQo+PiArICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIGl0IHdp
bGwgYmUgdXNlZnVsLCBidXQNCj4+IFdJVEhPVVQNCj4+ICsgKiBBTlkgV0FSUkFOVFk7IHdpdGhv
dXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiANCj4+ICsgTUVSQ0hBTlRBQklMSVRZDQo+
PiBvcg0KPj4gKyAqIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBH
TlUgR2VuZXJhbCBQdWJsaWMNCj4+IExpY2Vuc2UgZm9yDQo+PiArICogbW9yZSBkZXRhaWxzLg0K
Pj4gKyAqDQo+PiArICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05V
IEdlbmVyYWwgUHVibGljIExpY2Vuc2UNCj4+IGFsb25nIHdpdGgNCj4+ICsgKiB0aGlzIHByb2dy
YW07IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgDQo+PiAr
SW5jLiwNCj4+ICsgKiA1MSBGcmFua2xpbiBTdCAtIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BIDAy
MTEwLTEzMDEgVVNBLg0KPj4gKyAqDQo+PiArICovDQo+PiArI2luY2x1ZGU8bGludXgvZGV2aWNl
Lmg+DQo+PiArI2luY2x1ZGU8bGludXgvaGlkLmg+DQo+PiArI2luY2x1ZGU8bGludXgvdXNiLmg+
DQo+PiArI2luY2x1ZGUgInVzYmhpZC91c2JoaWQuaCINCj4+ICsjaW5jbHVkZTxsaW51eC9tb2R1
bGUuaD4NCj4+ICsjaW5jbHVkZTxsaW51eC9zbGFiLmg+DQo+PiArI2luY2x1ZGUgImlpby9paW8u
aCINCj4+ICsjaW5jbHVkZSAiaWlvL3N5c2ZzLmgiDQo+PiArI2luY2x1ZGUgImlpby9yaW5nX3N3
LmgiDQo+PiArI2luY2x1ZGUgImlpby90cmlnZ2VyLmgiDQo+PiArI2luY2x1ZGUgImhpZC1zZW5z
b3ItaWRzLmgiDQo+PiArI2luY2x1ZGUgImhpZC1zZW5zb3ItaW50ZXJmYWNlLmgiDQo+PiArI2lu
Y2x1ZGUgImhpZC1zZW5zb3ItYXR0cmlidXRlcy5oIg0KPj4gKw0KPj4gKw0KPj4gK3N0cnVjdCBh
Y2NlbF8zZF9zYW1wbGUgew0KPj4gKwl1MTYgeF9zejsNCj4+ICsJdTMyIGFjY2VsX3g7DQo+PiAr
CXUxNiB5X3N6Ow0KPj4gKwl1MzIgYWNjZWxfeTsNCj4+ICsJdTE2IHpfc3o7DQo+PiArCXUzMiBh
Y2NlbF96Ow0KPj4gK30gX19wYWNrZWQ7DQo+PiArDQo+PiArc3RydWN0IGFjY2VsXzNkX3N0YXRl
IHsNCj4+ICsJc3RydWN0IGhpZF9zZW5zb3JfaHViX2F0dHJpYnV0ZV9pbmZvIGFjY2VsX3g7DQo+
PiArCXN0cnVjdCBoaWRfc2Vuc29yX2h1Yl9hdHRyaWJ1dGVfaW5mbyBhY2NlbF95Ow0KPj4gKwlz
dHJ1Y3QgaGlkX3NlbnNvcl9odWJfYXR0cmlidXRlX2luZm8gYWNjZWxfejsNCj4+ICsJc3RydWN0
IGFjY2VsXzNkX3NhbXBsZSBhY2NlbF9zYW1wbGVfZGF0YTsgfTsNCj4+ICsNCj4+ICsNCj4+ICtl
bnVtIGFjY2VsXzNkX2NoYW4gew0KPj4gKwlBQ0NFTF9YX1lfWiwNCj4+ICt9Ow0KPj4gKw0KPj4g
K2VudW0gYWNjZWxfM2Rfc2NhbiB7DQo+PiArCUFDQ0VMXzNEX1NDQU5fQUNDX1hfWV9aLA0KPj4g
K307DQo+PiArDQo+PiArc3RhdGljIHN0cnVjdCBpaW9fY2hhbl9zcGVjIGFjY2VsXzNkX2NoYW5u
ZWxzW10gPSB7DQo+PiArCUlJT19DSEFOKElJT19BQ0NFTCwgMSwgMCwgMCwgTlVMTCwgMCwgSUlP
X01PRF9YX0FORF9ZX0FORF9aLA0KPj4gKwlJSU9fQ0hBTl9JTkZPX1NDQUxFX1NFUEFSQVRFX0JJ
VCB8DQo+PiArCUlJT19DSEFOX0lORk9fT0ZGU0VUX1NFUEFSQVRFX0JJVCwNCj4+ICsJQUNDRUxf
WF9ZX1osIEFDQ0VMXzNEX1NDQU5fQUNDX1hfWV9aLA0KPj4gKwkJIElJT19TVCgndScsIHNpemVv
ZihzdHJ1Y3QgYWNjZWxfM2Rfc2FtcGxlKSAqIDgsDQo+PiArCQlzaXplb2Yoc3RydWN0IGFjY2Vs
XzNkX3NhbXBsZSkgKiA4LCAwKSwgMCksIH07DQo+PiArDQo+PiArc3RhdGljIHNzaXplX3QgYWNj
ZWxfM2RfcmVhZF9hY2NlbChzdHJ1Y3QgZGV2aWNlICpkZXYsDQo+PiArCQkJCXN0cnVjdCBkZXZp
Y2VfYXR0cmlidXRlICphdHRyLA0KPj4gKwkJCQljaGFyICpidWYpDQo+PiArew0KPj4gKwlzdHJ1
Y3QgaWlvX2RldiAqaW5kaW9fZGV2ID0gZGV2X2dldF9kcnZkYXRhKGRldik7DQo+PiArCXN0cnVj
dCBoaWRfc2Vuc29yX2F0dHJpYnV0ZXMgKnN0ID0gaWlvX3ByaXYoaW5kaW9fZGV2KTsNCj4+ICsJ
c3RydWN0IGFjY2VsXzNkX3N0YXRlICphY2NlbF9zdGF0ZSA9DQo+PiArCQkJKHN0cnVjdCBhY2Nl
bF8zZF9zdGF0ZSAqKXN0LT5wcml2YXRlOw0KPj4gKwlzdHJ1Y3QgaWlvX2Rldl9hdHRyICp0aGlz
X2F0dHIgPSB0b19paW9fZGV2X2F0dHIoYXR0cik7DQo+PiArCWludCByZXBvcnRfaWQgPSAtMTsN
Cj4+ICsNCj4+ICsJc3dpdGNoICh0aGlzX2F0dHItPmFkZHJlc3MpIHsNCj4+ICsJY2FzZSBISURf
VVNBR0VfU0VOU09SX0RBVEFfTU9USU9OX0FDQ0VMRVJBVElPTl9YX0FYSVM6DQo+PiArCQlyZXBv
cnRfaWQgPSBhY2NlbF9zdGF0ZS0+YWNjZWxfeC5yZXBvcnRfaWQ7DQo+PiArCQlicmVhazsNCj4+
ICsJY2FzZSBISURfVVNBR0VfU0VOU09SX0RBVEFfTU9USU9OX0FDQ0VMRVJBVElPTl9ZX0FYSVM6
DQo+PiArCQlyZXBvcnRfaWQgPSBhY2NlbF9zdGF0ZS0+YWNjZWxfeS5yZXBvcnRfaWQ7DQo+PiAr
CQlicmVhazsNCj4+ICsJY2FzZSBISURfVVNBR0VfU0VOU09SX0RBVEFfTU9USU9OX0FDQ0VMRVJB
VElPTl9aX0FYSVM6DQo+PiArCQlyZXBvcnRfaWQgPSBhY2NlbF9zdGF0ZS0+YWNjZWxfei5yZXBv
cnRfaWQ7DQo+PiArCQlicmVhazsNCj4+ICsJZGVmYXVsdDoNCj4+ICsJCWJyZWFrOw0KPj4gKwl9
DQo+PiArCWlmIChyZXBvcnRfaWQ8ICAwKQ0KPj4gKwkJcmV0dXJuIC1FSU5WQUw7DQo+PiArDQo+
PiArCXJldHVybiBzZW5zb3JfaHViX2lucHV0X2F0dHJfZ2V0X3ZhbHVlKHN0LT5oZGV2LA0KPj4g
KwkJCUhJRF9VU0FHRV9TRU5TT1JfQUNDRUxfM0QsIHRoaXNfYXR0ci0+YWRkcmVzcywNCj4+ICsJ
CQlyZXBvcnRfaWQsIDQsIGJ1Zik7DQo+PiArfQ0KPj4gKw0KPj4gK3N0YXRpYyBpbnQgYWNjZWxf
M2RfcmVhZF9yYXcoc3RydWN0IGlpb19kZXYgKmluZGlvX2RldiwNCj4+ICsJCQkgICAgICBzdHJ1
Y3QgaWlvX2NoYW5fc3BlYyBjb25zdCAqY2hhbiwNCj4+ICsJCQkgICAgICBpbnQgKnZhbCwgaW50
ICp2YWwyLA0KPj4gKwkJCSAgICAgIGxvbmcgbWFzaykNCj4+ICt7DQo+PiArCXN0cnVjdCBoaWRf
c2Vuc29yX2F0dHJpYnV0ZXMgKnN0ID0gaWlvX3ByaXYoaW5kaW9fZGV2KTsNCj4+ICsJc3RydWN0
IGFjY2VsXzNkX3N0YXRlICphY2NlbF9zdGF0ZSA9DQo+PiArCQkJKHN0cnVjdCBhY2NlbF8zZF9z
dGF0ZSAqKXN0LT5wcml2YXRlOw0KPj4gKwkqdmFsID0gMDsNCj4+ICsJKnZhbDIgPSAwOw0KPj4g
Kw0KPj4gKwlzd2l0Y2ggKG1hc2spIHsNCj4+ICsJY2FzZSAwOg0KPj4gKwkJYnJlYWs7DQo+PiAr
CWNhc2UgSUlPX0NIQU5fSU5GT19TQ0FMRToNCj4+ICsJCSp2YWwgPSBhY2NlbF9zdGF0ZS0+YWNj
ZWxfeC51bml0czsNCj4+ICsJCWJyZWFrOw0KPj4gKwljYXNlIElJT19DSEFOX0lORk9fT0ZGU0VU
Og0KPj4gKwkJKnZhbCA9IGFjY2VsX3N0YXRlLT5hY2NlbF94LnVuaXRfZXhwbzsNCj4+ICsJCWJy
ZWFrOw0KPj4gKwlkZWZhdWx0Og0KPj4gKwkJYnJlYWs7DQo+PiArDQo+PiArCX0NCj4+ICsJcmV0
dXJuIElJT19WQUxfSU5UOw0KPj4gK30NCj4+ICsNCj4+ICtzdGF0aWMgaW50IGFjY2VsXzNkX3dy
aXRlX3JhdyhzdHJ1Y3QgaWlvX2RldiAqaW5kaW9fZGV2LA0KPj4gKwkJCSAgICAgICBzdHJ1Y3Qg
aWlvX2NoYW5fc3BlYyBjb25zdCAqY2hhbiwNCj4+ICsJCQkgICAgICAgaW50IHZhbCwNCj4+ICsJ
CQkgICAgICAgaW50IHZhbDIsDQo+PiArCQkJICAgICAgIGxvbmcgbWFzaykNCj4+ICt7DQo+PiAr
CXByaW50ayhLRVJOX0VSUiAiJXNcbiIsIF9fZnVuY19fKTsNCj4+ICsNCj4+ICsJcmV0dXJuIDA7
DQo+PiArfQ0KPj4gKw0KPj4gKy8qIFVzYWdlIHNwZWNpZmljIGF0dHJpYnV0ZXMgKi8NCj4+ICsj
ZGVmaW5lIElJT19ERVZfQVRUUl9BQ0NFTF9PRkZTRVQoX21vZGUsIF9zaG93LCBfc3RvcmUsIF9h
ZGRyKSAgXA0KPj4gKwlJSU9fREVWSUNFX0FUVFIoYWNjZWxfb2Zmc2V0LCBfbW9kZSwgX3Nob3cs
IF9zdG9yZSwgX2FkZHIpDQo+PiArDQo+PiArI2RlZmluZSBJSU9fREVWX0FUVFJfQUNDRUxfWF9P
RkZTRVQoX21vZGUsIF9zaG93LCBfc3RvcmUsIF9hZGRyKQ0KPj4gXA0KPj4gKwlJSU9fREVWSUNF
X0FUVFIoYWNjZWxfeF9vZmZzZXQsIF9tb2RlLCBfc2hvdywgX3N0b3JlLCBfYWRkcikNCj4+ICsN
Cj4+ICsjZGVmaW5lIElJT19ERVZfQVRUUl9BQ0NFTF9ZX09GRlNFVChfbW9kZSwgX3Nob3csIF9z
dG9yZSwgX2FkZHIpDQo+PiBcDQo+PiArCUlJT19ERVZJQ0VfQVRUUihhY2NlbF95X29mZnNldCwg
X21vZGUsIF9zaG93LCBfc3RvcmUsIF9hZGRyKQ0KPj4gKw0KPj4gKyNkZWZpbmUgSUlPX0RFVl9B
VFRSX0FDQ0VMX1pfT0ZGU0VUKF9tb2RlLCBfc2hvdywgX3N0b3JlLCBfYWRkcikNCj4+IFwNCj4+
ICsJSUlPX0RFVklDRV9BVFRSKGFjY2VsX3pfb2Zmc2V0LCBfbW9kZSwgX3Nob3csIF9zdG9yZSwg
X2FkZHIpDQo+PiArDQo+PiArI2RlZmluZSBJSU9fREVWX0FUVFJfQUNDRUxfU0VOU0lUSVZJVFko
X21vZGUsIF9zaG93LCBfc3RvcmUsIF9hZGRyKQ0KPj4gICAgIFwNCj4+ICsJSUlPX0RFVklDRV9B
VFRSKGFjY2VsX3NlbnNpdGl2aXR5LCBfbW9kZSwgX3Nob3csIF9zdG9yZSwgX2FkZHIpDQo+PiAr
DQo+PiArc3RhdGljIElJT19ERVZfQVRUUl9BQ0NFTF9YX09GRlNFVChTX0lXVVNSIHwgU19JUlVH
TywNCj4+IGFjY2VsXzNkX3JlYWRfYWNjZWwsDQo+PiArCQkgTlVMTCwgSElEX1VTQUdFX1NFTlNP
Ul9EQVRBX01PVElPTl9BQ0NFTEVSQVRJT05fWF9BWElTKTsNCj4+ICtzdGF0aWMgSUlPX0RFVl9B
VFRSX0FDQ0VMX1lfT0ZGU0VUKFNfSVdVU1IgfCBTX0lSVUdPLA0KPj4gYWNjZWxfM2RfcmVhZF9h
Y2NlbCwNCj4+ICsJCSBOVUxMLCBISURfVVNBR0VfU0VOU09SX0RBVEFfTU9USU9OX0FDQ0VMRVJB
VElPTl9ZX0FYSVMpOw0KPj4gK3N0YXRpYyBJSU9fREVWX0FUVFJfQUNDRUxfWl9PRkZTRVQoU19J
V1VTUiB8IFNfSVJVR08sDQo+PiBhY2NlbF8zZF9yZWFkX2FjY2VsLA0KPj4gKwkJIE5VTEwsIEhJ
RF9VU0FHRV9TRU5TT1JfREFUQV9NT1RJT05fQUNDRUxFUkFUSU9OX1pfQVhJUyk7DQo+PiArDQo+
PiArc3RhdGljIHN0cnVjdCBhdHRyaWJ1dGUgKmFjY2VsXzNkX2F0dHJpYnV0ZXNbXSA9IHsNCj4+
ICsJLyogY29tbW9uIGF0dHJpYnV0ZXMgKi8NCj4+ICsJJmlpb19kZXZfYXR0cl9wb2xsX2ludGVy
dmFsLmRldl9hdHRyLmF0dHIsDQo+PiArCSZpaW9fZGV2X2F0dHJfc2Vuc2l0aXZpdHkuZGV2X2F0
dHIuYXR0ciwNCj4+ICsJJmlpb19kZXZfYXR0cl9hY3RpdmF0ZS5kZXZfYXR0ci5hdHRyLA0KPj4g
KwkvKiBVc2FnZSBzcGVjaWZpYyBhdHRyaWJ1dGVzICovDQo+PiArCSZpaW9fZGV2X2F0dHJfYWNj
ZWxfeF9vZmZzZXQuZGV2X2F0dHIuYXR0ciwNCj4+ICsJJmlpb19kZXZfYXR0cl9hY2NlbF95X29m
ZnNldC5kZXZfYXR0ci5hdHRyLA0KPj4gKwkmaWlvX2Rldl9hdHRyX2FjY2VsX3pfb2Zmc2V0LmRl
dl9hdHRyLmF0dHIsDQo+PiArCU5VTEwsDQo+PiArfTsNCj4+ICsNCj4+ICtzdGF0aWMgY29uc3Qg
c3RydWN0IGF0dHJpYnV0ZV9ncm91cCBhY2NlbF8zZF9hdHRyaWJ1dGVfZ3JvdXAgPSB7DQo+PiAr
CS5hdHRycyA9IGFjY2VsXzNkX2F0dHJpYnV0ZXMsDQo+PiArfTsNCj4+ICsNCj4+ICtzdGF0aWMg
Y29uc3Qgc3RydWN0IGlpb19pbmZvIGFjY2VsXzNkX2luZm8gPSB7DQo+PiArCS5hdHRycyA9JmFj
Y2VsXzNkX2F0dHJpYnV0ZV9ncm91cCwNCj4+ICsJLmRyaXZlcl9tb2R1bGUgPSBUSElTX01PRFVM
RSwNCj4+ICsJLnJlYWRfcmF3ID0mYWNjZWxfM2RfcmVhZF9yYXcsDQo+PiArCS53cml0ZV9yYXcg
PSZhY2NlbF8zZF93cml0ZV9yYXcsDQo+PiArfTsNCj4+ICsNCj4+ICsNCj4+ICsvKiBGdW5jdGlv
biB0byBwdXNoIGRhdGEgdG8gSUlPIHJpbmcgKi8gaW50IA0KPj4gK2FjY2VsXzNkX3Byb2NfZXZl
bnQoc3RydWN0IGhpZF9kZXZpY2UgKmhkZXYsIHVuc2lnbmVkIHVzYWdlX2lkLA0KPj4gdm9pZCAq
cHJpdikNCj4+ICt7DQo+PiArCXN0cnVjdCBpaW9fZGV2ICppbmRpb19kZXYgPSAoc3RydWN0IGlp
b19kZXYgKilwcml2Ow0KPj4gKwlzdHJ1Y3QgaGlkX3NlbnNvcl9hdHRyaWJ1dGVzICpzdCA9IGlp
b19wcml2KGluZGlvX2Rldik7DQo+PiArCXN0cnVjdCBhY2NlbF8zZF9zdGF0ZSAqYWNjZWxfc3Rh
dGUgPQ0KPj4gKwkJCShzdHJ1Y3QgYWNjZWxfM2Rfc3RhdGUgKilzdC0+cHJpdmF0ZTsNCj4+ICsN
Cj4+ICsJaGlkX2RiZyhoZGV2LCAiYWNjZWxfM2RfcHJvY19ldmVudFxuIik7DQo+PiArCWlmIChz
dC0+ZGF0YV9yZWFkeSkNCj4+ICsJCWhpZF9zZW5zb3JfcHVzaF9kYXRhX3RvX3JpbmcoaW5kaW9f
ZGV2LA0KPj4gKwkJCQkodTggKikmYWNjZWxfc3RhdGUtPmFjY2VsX3NhbXBsZV9kYXRhLA0KPj4g
KwkJCQlzaXplb2Yoc3RydWN0IGFjY2VsXzNkX3NhbXBsZSkpOw0KPj4gKwllbHNlDQo+PiArCQlo
aWRfZGJnKGhkZXYsICJhY2NlbF8zZF9wcm9jX2V2ZW50IGRhdGEgbm90IHJlYWR5XG4iKTsNCj4+
ICsJcmV0dXJuIDA7DQo+PiArfQ0KPj4gKw0KPj4gKy8qIENhcHR1cmUgc2FtcGxlcyBpbiBsb2Nh
bCBzdG9yYWdlICovIGludCANCj4+ICthY2NlbF8zZF9jYXB0dXJlX3NhbXBsZShzdHJ1Y3QgaGlk
X2RldmljZSAqaGRldiwgdW5zaWduZWQNCj4+IHVzYWdlX2lkLA0KPj4gKwkJCQkgc2l6ZV90IHJh
d19sZW4sIGNoYXIgKnJhd19kYXRhLCB2b2lkICpwcml2KSB7DQo+PiArCXN0cnVjdCBpaW9fZGV2
ICppbmRpb19kZXYgPSAoc3RydWN0IGlpb19kZXYgKilwcml2Ow0KPj4gKwlzdHJ1Y3QgaGlkX3Nl
bnNvcl9hdHRyaWJ1dGVzICpzdCA9IGlpb19wcml2KGluZGlvX2Rldik7DQo+PiArCXN0cnVjdCBh
Y2NlbF8zZF9zdGF0ZSAqYWNjZWxfc3RhdGUgPQ0KPj4gKwkJCShzdHJ1Y3QgYWNjZWxfM2Rfc3Rh
dGUgKilzdC0+cHJpdmF0ZTsNCj4+ICsNCj4+ICsJc3dpdGNoICh1c2FnZV9pZCkgew0KPj4gKwlj
YXNlIEhJRF9VU0FHRV9TRU5TT1JfREFUQV9NT1RJT05fQUNDRUxFUkFUSU9OX1hfQVhJUzoNCj4+
ICsJCWFjY2VsX3N0YXRlLT5hY2NlbF9zYW1wbGVfZGF0YS54X3N6ID0gcmF3X2xlbjsNCj4+ICsJ
CWFjY2VsX3N0YXRlLT5hY2NlbF9zYW1wbGVfZGF0YS5hY2NlbF94ID0NCj4+ICsJCSoodTMyICop
cmF3X2RhdGE7DQo+PiArCQlicmVhazsNCj4+ICsJY2FzZSBISURfVVNBR0VfU0VOU09SX0RBVEFf
TU9USU9OX0FDQ0VMRVJBVElPTl9ZX0FYSVM6DQo+PiArCQlhY2NlbF9zdGF0ZS0+YWNjZWxfc2Ft
cGxlX2RhdGEueV9zeiA9IHJhd19sZW47DQo+PiArCQlhY2NlbF9zdGF0ZS0+YWNjZWxfc2FtcGxl
X2RhdGEuYWNjZWxfeSA9DQo+PiArCQkqKHUzMiAqKXJhd19kYXRhOw0KPj4gKwkJYnJlYWs7DQo+
PiArCWNhc2UgSElEX1VTQUdFX1NFTlNPUl9EQVRBX01PVElPTl9BQ0NFTEVSQVRJT05fWl9BWElT
Og0KPj4gKwkJYWNjZWxfc3RhdGUtPmFjY2VsX3NhbXBsZV9kYXRhLnpfc3ogPSByYXdfbGVuOw0K
Pj4gKwkJYWNjZWxfc3RhdGUtPmFjY2VsX3NhbXBsZV9kYXRhLmFjY2VsX3ogPQ0KPj4gKwkJKih1
MzIgKilyYXdfZGF0YTsNCj4+ICsJCWJyZWFrOw0KPj4gKwlkZWZhdWx0Og0KPj4gKwkJYnJlYWs7
DQo+PiArCX0NCj4+ICsJcmV0dXJuIDA7DQo+PiArfQ0KPj4gKw0KPj4gKw0KPj4gKy8qIFBhcnNl
IHJlcG9ydCB3aGljaCBpcyBzcGVjaWZpYyB0byBhbiB1c2FnZSBpZCovIHN0YXRpYyBpbnQgDQo+
PiArYWNjZWxfM2RfcGFyc2VfcmVwb3J0KHN0cnVjdCBoaWRfZGV2aWNlICpoZGV2LCB1bnNpZ25l
ZA0KPj4gdXNhZ2VfaWQsDQo+PiArCQkJCXN0cnVjdCBhY2NlbF8zZF9zdGF0ZSAqc3QpDQo+PiAr
ew0KPj4gKwlpbnQgcmV0Ow0KPj4gKw0KPj4gKwlyZXQgPSBzZW5zb3JfaHViX2lucHV0X2dldF9h
dHRyaWJ1dGVfaW5mbyhoZGV2LCBISURfSU5QVVRfUkVQT1JULA0KPj4gKwkJCXVzYWdlX2lkLA0K
Pj4gKwkJCUhJRF9VU0FHRV9TRU5TT1JfREFUQV9NT1RJT05fQUNDRUxFUkFUSU9OX1hfQVhJUywN
Cj4+ICsJCQkmc3QtPmFjY2VsX3gpOw0KPj4gKwlpZiAoIXJldCkNCj4+ICsJCWhpZF9kYmcoaGRl
diwgIk5vIEFjY2VsIFggYXR0cmlidXRlXG4iKTsNCj4+ICsNCj4+ICsNCj4+ICsJcmV0ID0gc2Vu
c29yX2h1Yl9pbnB1dF9nZXRfYXR0cmlidXRlX2luZm8oaGRldiwgSElEX0lOUFVUX1JFUE9SVCwN
Cj4+ICsJCQl1c2FnZV9pZCwNCj4+ICsJCQlISURfVVNBR0VfU0VOU09SX0RBVEFfTU9USU9OX0FD
Q0VMRVJBVElPTl9ZX0FYSVMsDQo+PiArCQkJJnN0LT5hY2NlbF95KTsNCj4+ICsJaWYgKCFyZXQp
DQo+PiArCQloaWRfZGJnKGhkZXYsICJObyBBY2NlbCBZIGF0dHJpYnV0ZVxuIik7DQo+PiArDQo+
PiArDQo+PiArCXJldCA9IHNlbnNvcl9odWJfaW5wdXRfZ2V0X2F0dHJpYnV0ZV9pbmZvKGhkZXYs
IEhJRF9JTlBVVF9SRVBPUlQsDQo+PiArCQkJdXNhZ2VfaWQsDQo+PiArCQkJSElEX1VTQUdFX1NF
TlNPUl9EQVRBX01PVElPTl9BQ0NFTEVSQVRJT05fWl9BWElTLA0KPj4gKwkJCSZzdC0+YWNjZWxf
eik7DQo+PiArCWlmICghcmV0KQ0KPj4gKwkJaGlkX2RiZyhoZGV2LCAiTm8gQWNjZWwgWiBhdHRy
aWJ1dGVcbiIpOw0KPj4gKw0KPj4gKwloaWRfZGJnKGhkZXYsICJhY2NlbF8zZCAleDoleCwgJXg6
JXgsICV4OiV4XG4iLCBzdC0+YWNjZWxfeC5pbmRleCwNCj4+ICsJCQlzdC0+YWNjZWxfeC5yZXBv
cnRfaWQsDQo+PiArCQkJc3QtPmFjY2VsX3kuaW5kZXgsIHN0LT5hY2NlbF95LnJlcG9ydF9pZCwN
Cj4+ICsJCQlzdC0+YWNjZWxfei5pbmRleCwgc3QtPmFjY2VsX3oucmVwb3J0X2lkKTsNCj4+ICsN
Cj4+ICsJcmV0dXJuIDA7DQo+PiArfQ0KPj4gKw0KPj4gKy8qIEVudHJ5IGZ1bmN0aW9uIHRvIGlu
aXRpYWxpemUgdGhlIHByb2Nlc3NpbmcgZm9yIHVzYWdlIGlkICovIA0KPj4gK3N0YXRpYyBpbnQg
YWNjZWxfM2RfZW50ZXIoc3RydWN0IGhpZF9kZXZpY2UgKmhkZXYsIHVuc2lnbmVkIHVzYWdlX2lk
LA0KPj4gKwkJCQl2b2lkICoqcHJpdikNCj4+ICt7DQo+PiArCWludCByZXQgPSAwOw0KPj4gKwlz
dGF0aWMgY2hhciAqbmFtZSA9ICJhY2NlbF8zZCI7DQo+PiArCXN0cnVjdCBpaW9fZGV2ICppbmRp
b19kZXY7DQo+PiArCXN0cnVjdCBhY2NlbF8zZF9zdGF0ZSAqYWNjZWxfc3RhdGU7DQo+PiArCXN0
cnVjdCBoaWRfc2Vuc29yX2F0dHJpYnV0ZXMgKnN0Ow0KPj4gKw0KPj4gKwlhY2NlbF9zdGF0ZSA9
IGt6YWxsb2Moc2l6ZW9mKHN0cnVjdCBhY2NlbF8zZF9zdGF0ZSksIEdGUF9LRVJORUwpOw0KPj4g
KwlpZiAoYWNjZWxfc3RhdGUgPT0gTlVMTCkgew0KPj4gKwkJcmV0ID0gLUVOT01FTTsNCj4+ICsJ
CWdvdG8gZXJyb3JfcmV0Ow0KPj4gKwl9DQo+PiArDQo+PiArCWluZGlvX2RldiA9IGlpb19hbGxv
Y2F0ZV9kZXZpY2Uoc2l6ZW9mKHN0cnVjdA0KPj4gaGlkX3NlbnNvcl9hdHRyaWJ1dGVzKSk7DQo+
PiArCWlmIChpbmRpb19kZXYgPT0gTlVMTCkgew0KPj4gKwkJcmV0ID0gLUVOT01FTTsNCj4+ICsJ
CWdvdG8gZXJyb3JfZnJlZV9zdGF0ZTsNCj4+ICsJfQ0KPj4gKwlzdCA9IGlpb19wcml2KGluZGlv
X2Rldik7DQo+PiArCXN0LT51c2FnZV9pZCA9IHVzYWdlX2lkOw0KPj4gKwlzdC0+aGRldiA9IGhk
ZXY7DQo+PiArCXN0LT5wcml2YXRlID0gKHZvaWQgKilhY2NlbF9zdGF0ZTsNCj4+ICsNCj4+ICsJ
cmV0ID0gaGlkX3NlbnNvcl9wYXJzZV9jb21tb25fYXR0cmlidXRlcyhoZGV2LCB1c2FnZV9pZCwg
c3QpOw0KPj4gKwlpZiAocmV0KSB7DQo+PiArCQloaWRfZXJyKGhkZXYsICJmYWlsZWQgdG8gc2V0
dXAgY29tbW9uIGF0dHJpYnV0ZXNcbiIpOw0KPj4gKwkJZ290byBlcnJvcl9mcmVlX2RldjsNCj4+
ICsJfQ0KPj4gKwlyZXQgPSBhY2NlbF8zZF9wYXJzZV9yZXBvcnQoaGRldiwgdXNhZ2VfaWQsIGFj
Y2VsX3N0YXRlKTsNCj4+ICsJaWYgKHJldCkgew0KPj4gKwkJaGlkX2VycihoZGV2LCAiZmFpbGVk
IHRvIHNldHVwIGF0dHJpYnV0ZXNcbiIpOw0KPj4gKwkJZ290byBlcnJvcl9mcmVlX2RldjsNCj4+
ICsJfQ0KPj4gKw0KPj4gKwlpbmRpb19kZXYtPmNoYW5uZWxzID0gYWNjZWxfM2RfY2hhbm5lbHM7
DQo+PiArCWluZGlvX2Rldi0+bnVtX2NoYW5uZWxzID0NCj4+ICsJCQkJQVJSQVlfU0laRShhY2Nl
bF8zZF9jaGFubmVscyk7DQo+PiArCWluZGlvX2Rldi0+ZGV2LnBhcmVudCA9JmhkZXYtPmRldjsN
Cj4+ICsJaW5kaW9fZGV2LT5pbmZvID0mYWNjZWxfM2RfaW5mbzsNCj4+ICsJaW5kaW9fZGV2LT5u
YW1lID0gbmFtZTsNCj4+ICsJaW5kaW9fZGV2LT5tb2RlcyA9IElORElPX0RJUkVDVF9NT0RFOw0K
Pj4gKw0KPj4gKwlyZXQgPSBoaWRfc2Vuc29yX2NvbmZpZ3VyZV9yaW5nKGluZGlvX2Rldik7DQo+
PiArCWlmIChyZXQpIHsNCj4+ICsJCWhpZF9lcnIoaGRldiwgImZhaWxlZCB0byBpbml0aWFsaXpl
IHRoZSByaW5nXG4iKTsNCj4+ICsJCWdvdG8gZXJyb3JfZnJlZV9kZXY7DQo+PiArCX0NCj4+ICsN
Cj4+ICsJcmV0ID0gaWlvX2J1ZmZlcl9yZWdpc3RlcihpbmRpb19kZXYsDQo+PiArCQkJCQlhY2Nl
bF8zZF9jaGFubmVscywNCj4+ICsJCQkJCUFSUkFZX1NJWkUoYWNjZWxfM2RfY2hhbm5lbHMpKTsN
Cj4+ICsJaWYgKHJldCkgew0KPj4gKwkJaGlkX2VycihoZGV2LCAiZmFpbGVkIHRvIGluaXRpYWxp
emUgdGhlIHJpbmdcbiIpOw0KPj4gKwkJZ290byBlcnJvcl91bnJlZ19yaW5nX2Z1bmNzOw0KPj4g
Kwl9DQo+PiArCXN0LT5kYXRhX3JlYWR5ID0gdHJ1ZTsNCj4+ICsJcmV0ID0gaGlkX3NlbnNvcl9z
ZXR1cF90cmlnZ2VyKGluZGlvX2RldiwgbmFtZSk7DQo+PiArCWlmIChyZXQ8ICAwKSB7DQo+PiAr
CQloaWRfZXJyKGhkZXYsICJ0cmlnZ2VyIHNldHVwIGZhaWxlZFxuIik7DQo+PiArCQlnb3RvIGVy
cm9yX3VuaW5pdF9yaW5nOw0KPj4gKwl9DQo+PiArDQo+PiArCXJldCA9IGlpb19kZXZpY2VfcmVn
aXN0ZXIoaW5kaW9fZGV2KTsNCj4+ICsJaWYgKHJldCkgew0KPj4gKwkJaGlkX2VycihoZGV2LCAi
ZGV2aWNlIHJlZ2lzdGVyIGZhaWxlZFxuIik7DQo+PiArCQlnb3RvIGVycm9yX3JlbW92ZV90cmln
Z2VyOw0KPj4gKwl9DQo+PiArCSpwcml2ID0gKHZvaWQgKilpbmRpb19kZXY7DQo+PiArCXJldHVy
biByZXQ7DQo+PiArDQo+PiArZXJyb3JfcmVtb3ZlX3RyaWdnZXI6DQo+PiArCQloaWRfc2Vuc29y
X3JlbW92ZV90cmlnZ2VyKGluZGlvX2Rldik7DQo+PiArZXJyb3JfdW5pbml0X3Jpbmc6DQo+PiAr
CQlpaW9fYnVmZmVyX3VucmVnaXN0ZXIoaW5kaW9fZGV2KTsNCj4+ICtlcnJvcl91bnJlZ19yaW5n
X2Z1bmNzOg0KPj4gKwkJaGlkX3NlbnNvcl9yaW5nX2NsZWFudXAoaW5kaW9fZGV2KTsNCj4+ICtl
cnJvcl9mcmVlX2RldjoNCj4+ICsJCWlpb19mcmVlX2RldmljZShpbmRpb19kZXYpOw0KPj4gK2Vy
cm9yX2ZyZWVfc3RhdGU6DQo+PiArCQlrZnJlZShhY2NlbF9zdGF0ZSk7DQo+PiArZXJyb3JfcmV0
Og0KPj4gKwkJcmV0dXJuIHJldDsNCj4+ICt9DQo+PiArDQo+PiArc3RhdGljIGludCBhY2NlbF8z
ZF9leGl0KHN0cnVjdCBoaWRfZGV2aWNlICpoZGV2LCB2b2lkICpwcml2KSB7DQo+PiArCWludCBy
ZXQgPSAwOw0KPj4gKwlzdHJ1Y3QgaWlvX2RldiAqaW5kaW9fZGV2ID0gKHN0cnVjdCBpaW9fZGV2
ICopcHJpdjsNCj4+ICsJc3RydWN0IGhpZF9zZW5zb3JfYXR0cmlidXRlcyAqc3QgPSBpaW9fcHJp
dihpbmRpb19kZXYpOw0KPj4gKwlzdHJ1Y3QgYWNjZWxfM2Rfc3RhdGUgKmFjY2VsX3N0YXRlID0N
Cj4+ICsJCQkoc3RydWN0IGFjY2VsXzNkX3N0YXRlICopc3QtPnByaXZhdGU7DQo+PiArDQo+PiAr
CWlpb19kZXZpY2VfdW5yZWdpc3RlcihpbmRpb19kZXYpOw0KPj4gKwloaWRfc2Vuc29yX3JlbW92
ZV90cmlnZ2VyKGluZGlvX2Rldik7DQo+PiArCWlpb19idWZmZXJfdW5yZWdpc3RlcihpbmRpb19k
ZXYpOw0KPj4gKwloaWRfc2Vuc29yX3JpbmdfY2xlYW51cChpbmRpb19kZXYpOw0KPj4gKwlpaW9f
ZnJlZV9kZXZpY2UoaW5kaW9fZGV2KTsNCj4+ICsNCj4+ICsJa2ZyZWUoYWNjZWxfc3RhdGUpOw0K
Pj4gKwlyZXR1cm4gcmV0Ow0KPj4gK30NCj4+ICsNCj4+ICtzdGF0aWMgc3RydWN0IHNlbnNvcl9o
dWJfY2FsbGJhY2tzIGFjY2VsXzNkX2NhbGxiYWNrcyA9IHsNCj4+ICsJLmVudGVyID0gYWNjZWxf
M2RfZW50ZXIsDQo+PiArCS5leGl0ID0gYWNjZWxfM2RfZXhpdCwNCj4+ICsJLnNlbmRfZXZlbnQg
PSBhY2NlbF8zZF9wcm9jX2V2ZW50LA0KPj4gKwkuY2FwdHVyZV9zYW1wbGUgPSBhY2NlbF8zZF9j
YXB0dXJlX3NhbXBsZSwgfTsNCj4+ICsNCj4+ICtzdHJ1Y3Qgc2Vuc29yX2h1Yl9jYWxsYmFja3Mg
ICphY2NlbF8zZF9yZWdpc3Rlcl9jYWxsYmFja3Modm9pZCkNCj4+ICt7DQo+PiArCXJldHVybiZh
Y2NlbF8zZF9jYWxsYmFja3M7DQo+PiArfQ0KPj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvc3RhZ2lu
Zy9oaWQtc2Vuc29ycy9oaWQtc2Vuc29yLWh1Yi5jDQo+PiBiL2RyaXZlcnMvc3RhZ2luZy9oaWQt
c2Vuc29ycy9oaWQtc2Vuc29yLWh1Yi5jDQo+PiBpbmRleCAzODRlMGQwLi41NWFlNTYyIDEwMDY0
NA0KPj4gLS0tIGEvZHJpdmVycy9zdGFnaW5nL2hpZC1zZW5zb3JzL2hpZC1zZW5zb3ItaHViLmMN
Cj4+ICsrKyBiL2RyaXZlcnMvc3RhZ2luZy9oaWQtc2Vuc29ycy9oaWQtc2Vuc29yLWh1Yi5jDQo+
PiBAQCAtNjAsNiArNjAsNyBAQCBzdHJ1Y3Qgc2Vuc29yX2h1Yl9jYWxsYmFja3NfbGlzdCB7ICB9
Ow0KPj4NCj4+IHN0YXRpYyBzdHJ1Y3Qgc2Vuc29yX2h1Yl9jYWxsYmFja3NfbGlzdCB1c2FnZV9j
YWxsYmFja3NbXSA9IHsNCj4+ICsJe0hJRF9VU0FHRV9TRU5TT1JfQUNDRUxfM0QsIGFjY2VsXzNk
X3JlZ2lzdGVyX2NhbGxiYWNrc30sDQo+PiAJezB9DQo+PiB9Ow0KPj4NCj4+IGRpZmYgLS1naXQg
YS9kcml2ZXJzL3N0YWdpbmcvaGlkLXNlbnNvcnMvaGlkLXNlbnNvci1pbnRlcmZhY2UuaA0KPj4g
Yi9kcml2ZXJzL3N0YWdpbmcvaGlkLXNlbnNvcnMvaGlkLXNlbnNvci1pbnRlcmZhY2UuaA0KPj4g
aW5kZXggNDc3NDk0Zi4uM2Y0ZmU1NyAxMDA2NDQNCj4+IC0tLSBhL2RyaXZlcnMvc3RhZ2luZy9o
aWQtc2Vuc29ycy9oaWQtc2Vuc29yLWludGVyZmFjZS5oDQo+PiArKysgYi9kcml2ZXJzL3N0YWdp
bmcvaGlkLXNlbnNvcnMvaGlkLXNlbnNvci1pbnRlcmZhY2UuaA0KPj4gQEAgLTg0LDQgKzg0LDcg
QEAgdm9pZCBoaWRfc2Vuc29yX3B1c2hfZGF0YV90b19yaW5nKHN0cnVjdCBpaW9fZGV2IA0KPj4g
KmluZGlvX2RldiwgdTggKmRhdGEsICBpbnQgaGlkX3NlbnNvcl9zZXR1cF90cmlnZ2VyKHN0cnVj
dCBpaW9fZGV2IA0KPj4gKmluZGlvX2RldiwgY2hhciAqbmFtZSk7ICB2b2lkIGhpZF9zZW5zb3Jf
cmVtb3ZlX3RyaWdnZXIoc3RydWN0IA0KPj4gaWlvX2RldiAqaW5kaW9fZGV2KTsNCj4+DQo+PiAr
LyogU2Vuc29yIHVzYWdlIGlkIHByb2Nlc3NpbmcgY2FsbGJhY2tzICovIHN0cnVjdCANCj4+ICtz
ZW5zb3JfaHViX2NhbGxiYWNrcyAqYWNjZWxfM2RfcmVnaXN0ZXJfY2FsbGJhY2tzKHZvaWQpOw0K
Pj4gKw0KPj4gI2VuZGlmDQo+PiAtLQ0KPj4gMS43LjcuNg0KPj4NCj4+IC0tDQo+PiBUbyB1bnN1
YnNjcmliZSBmcm9tIHRoaXMgbGlzdDogc2VuZCB0aGUgbGluZSAidW5zdWJzY3JpYmUgbGludXgt
aWlvIiANCj4+IGluIHRoZSBib2R5IG9mIGEgbWVzc2FnZSB0byBtYWpvcmRvbW9Admdlci5rZXJu
ZWwub3JnIE1vcmUgbWFqb3Jkb21vIA0KPj4gaW5mbyBhdCAgaHR0cDovL3ZnZXIua2VybmVsLm9y
Zy9tYWpvcmRvbW8taW5mby5odG1sDQo+DQo+IC0tDQo+IFNlbnQgZnJvbSBteSBBbmRyb2lkIHBo
b25lIHdpdGggSy05IE1haWwuIFBsZWFzZSBleGN1c2UgbXkgYnJldml0eS4NCg0K
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH, 4/7] HID-Sensors: Added accelerometer 3D
2012-06-07 15:41 ` Pandruvada, Srinivas
@ 2012-06-07 20:27 ` Jonathan Cameron
0 siblings, 0 replies; 16+ messages in thread
From: Jonathan Cameron @ 2012-06-07 20:27 UTC (permalink / raw)
To: Pandruvada, Srinivas
Cc: Jonathan Cameron, linux-input@vger.kernel.org,
linux-iio@vger.kernel.org
On 06/07/2012 04:41 PM, Pandruvada, Srinivas wrote:
> Thanks for your excellent comments. I think I get some idea now.
>
> Do you think the place for this driver is in "staging/iio/hid-sensors"?
Firstly don't put it in staging unless you have non iio related reasons!
The iio core is now out in drivers/iio.
Secondly the question is whether to treat the individual sensor
components as individual drivers (and the core as effectively and mfd)
or to treat it all as one big 'compound' sensor, similar to we do with
IMUs. As it currently stands it is a compound sensor.
The mfd route breaks the various components into independent modules
with a core handling the data and interrupt flow to and from the
hardware. Might be worth doing for a clean result...
Also note that there are some patches changing the route of data
into the buffers under review. You might want to develop with
those in place as quite a few of your elements will probably want
bridging to input (which relies on that series...)
The series.
[PATCH 0/4 V2] staging:iio: Add support for multiple buffer.
>
> Thanks,
> Srinivas
>
>
>
>
>
>
> -----Original Message-----
> From: Jonathan Cameron [mailto:jic23@cam.ac.uk]
> Sent: Thursday, June 07, 2012 1:11 AM
> To: Pandruvada, Srinivas
> Cc: linux-input@vger.kernel.org; linux-iio@vger.kernel.org
> Subject: Re: [PATCH, 4/7] HID-Sensors: Added accelerometer 3D
>
> On 6/6/2012 5:57 PM, Pandruvada, Srinivas wrote:
>> The USB sensor spec has a report structure which it sends as part of report descriptor we get during initial plug in. This report structure describes elements and their sizes. For example, it may say that an Accelerometer X axis value as 4 bytes long and what is the exponent and unit. Also it sends what control elements it has.
>> The sequence is
>> - Set sensitivity, interval, activate sys-fs interface. The USB sensor will send an event by USB-IN report when the captured sample is changed by sensitivity value and stable for at least interval. Also you need to activate the sensor so that the usb will start sending events.
>>
>> - Once USB report with the captured sample arrives, I format the data as defined in " struct accel_3d_sample" below and push to IIO ring buffer.
>> I define a single channel
>> IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X_AND_Y_AND_Z,
>> IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
>> IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
>> ACCEL_X_Y_Z, ACCEL_3D_SCAN_ACC_X_Y_Z,
>> IIO_ST('u', sizeof(struct accel_3d_sample) * 8,
>> sizeof(struct accel_3d_sample) * 8, 0), 0), };
>>
>> Please suggest me if this is not the way IIO channel used.
> You have 3 channels here. The iio buffer interface will handle the fact that they are 'at the same time' on it's own.
>
> Btw I've killed off that macro so this won't build against current tree... Feel free if sensible to define a local macro. The global one was a maintenance nightmare hence we scrapped it...
>
> Sketching out what you should have
>
> {
> .type = IIO_ACCEL,
> .modified = 1,
> .channel2 = IIO_MOD_X,
> .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
> IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
> .scan_index = 0,
> .scan_type = {
> .sign = 's',
> .realbits = 12,
> .storagebits = 16,
> },
> }, {
> .type = IIO_ACCEL,
> .modified = 1,
> .channel2 = IIO_MOD_Y,
> .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
> IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
> .scan_index = 1,
> .scan_type = {
> .sign = 's',
> .realbits = 12,
> .storagebits = 16,
> },
> }, {
> .type = IIO_ACCEL,
> .modified = 1,
> .channel2 = IIO_MOD_Y,
> .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
> IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
> .scan_index = 2,
> .scan_type = {
> .sign = 's',
> .realbits = 12,
> .storagebits = 16,
> },
> Actually given you had scale and offset for your combined channel, those should probably be the SHARED versions.
>
> The scan type is for a device that needs bits masked...
>
> Hope that is enough for you to be getting on with. Feel free to post a v2 without waiting for a formal review!
>
> Jonathan
>> Thanks,
>> Srinivas
>>
>>
>>
>> -----Original Message-----
>> From: Jonathan Cameron [mailto:jic23@cam.ac.uk]
>> Sent: Wednesday, June 06, 2012 9:29 AM
>> To: Pandruvada, Srinivas; linux-input@vger.kernel.org
>> Cc: linux-iio@vger.kernel.org
>> Subject: Re: [PATCH, 4/7] HID-Sensors: Added accelerometer 3D
>>
>>
>>
>> srinivas pandruvada<srinivas.pandruvada@intel.com> wrote:
>>
>>> From: Srinivas pandruvada<srinivas.pandruvada@intel.com>
>>>
>>> Added usage id processing for Accelrometer 3D. This uses IIO
>>> interfaces "ring/buffer and trigger interface" to present data to user mode.
>>
>> I do not understand the data format. The way iio describes the format is done through sysfs attrs built from the iio_Chan spec... that way a scan is made up of a number of channel readings each taken at roughly the same time. However each is separately described. Perhaps the description needs extending. Please describe the format.
>>>
>>> Signed-off-by: Srinivas pandruvada<srinivas.pandruvada@intel.com>
>>> ---
>>> drivers/staging/hid-sensors/Makefile | 1 +
>>> drivers/staging/hid-sensors/hid-sensor-accel-3d.c | 387
>>> ++++++++++++++++++++
>>> drivers/staging/hid-sensors/hid-sensor-hub.c | 1 +
>>> drivers/staging/hid-sensors/hid-sensor-interface.h | 3 +
>>> 4 files changed, 392 insertions(+), 0 deletions(-) create mode 100644
>>> drivers/staging/hid-sensors/hid-sensor-accel-3d.c
>>>
>>> diff --git a/drivers/staging/hid-sensors/Makefile
>>> b/drivers/staging/hid-sensors/Makefile
>>> index 9a03953..4412079 100644
>>> --- a/drivers/staging/hid-sensors/Makefile
>>> +++ b/drivers/staging/hid-sensors/Makefile
>>> @@ -9,4 +9,5 @@ hid-sensors-y := hid-sensor-hub.o hid-sensors-y +=
>>> hid-sensor-attributes.o hid-sensors-y += hid-sensor-ring.o
>>> hid-sensors-y += hid-sensor-trigger.o
>>> +hid-sensors-y += hid-sensor-accel-3d.o
>>> obj-$(CONFIG_HID_SENSORS) += hid-sensors.o diff --git
>>> a/drivers/staging/hid-sensors/hid-sensor-accel-3d.c
>>> b/drivers/staging/hid-sensors/hid-sensor-accel-3d.c
>>> new file mode 100644
>>> index 0000000..ffe2639
>>> --- /dev/null
>>> +++ b/drivers/staging/hid-sensors/hid-sensor-accel-3d.c
>>> @@ -0,0 +1,387 @@
>>> +/*
>>> + * HID Sensors Driver
>>> + * Copyright (c) 2012, Intel Corporation.
>>> + *
>>> + * This program is free software; you can redistribute it and/or
>>> modify it
>>> + * under the terms and conditions of the GNU General Public License,
>>> + * version 2, as published by the Free Software Foundation.
>>> + *
>>> + * This program is distributed in the hope it will be useful, but
>>> WITHOUT
>>> + * ANY WARRANTY; without even the implied warranty of
>>> + MERCHANTABILITY
>>> or
>>> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
>>> License for
>>> + * more details.
>>> + *
>>> + * You should have received a copy of the GNU General Public License
>>> along with
>>> + * this program; if not, write to the Free Software Foundation,
>>> +Inc.,
>>> + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
>>> + *
>>> + */
>>> +#include<linux/device.h>
>>> +#include<linux/hid.h>
>>> +#include<linux/usb.h>
>>> +#include "usbhid/usbhid.h"
>>> +#include<linux/module.h>
>>> +#include<linux/slab.h>
>>> +#include "iio/iio.h"
>>> +#include "iio/sysfs.h"
>>> +#include "iio/ring_sw.h"
>>> +#include "iio/trigger.h"
>>> +#include "hid-sensor-ids.h"
>>> +#include "hid-sensor-interface.h"
>>> +#include "hid-sensor-attributes.h"
>>> +
>>> +
>>> +struct accel_3d_sample {
>>> + u16 x_sz;
>>> + u32 accel_x;
>>> + u16 y_sz;
>>> + u32 accel_y;
>>> + u16 z_sz;
>>> + u32 accel_z;
>>> +} __packed;
>>> +
>>> +struct accel_3d_state {
>>> + struct hid_sensor_hub_attribute_info accel_x;
>>> + struct hid_sensor_hub_attribute_info accel_y;
>>> + struct hid_sensor_hub_attribute_info accel_z;
>>> + struct accel_3d_sample accel_sample_data; };
>>> +
>>> +
>>> +enum accel_3d_chan {
>>> + ACCEL_X_Y_Z,
>>> +};
>>> +
>>> +enum accel_3d_scan {
>>> + ACCEL_3D_SCAN_ACC_X_Y_Z,
>>> +};
>>> +
>>> +static struct iio_chan_spec accel_3d_channels[] = {
>>> + IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X_AND_Y_AND_Z,
>>> + IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
>>> + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
>>> + ACCEL_X_Y_Z, ACCEL_3D_SCAN_ACC_X_Y_Z,
>>> + IIO_ST('u', sizeof(struct accel_3d_sample) * 8,
>>> + sizeof(struct accel_3d_sample) * 8, 0), 0), };
>>> +
>>> +static ssize_t accel_3d_read_accel(struct device *dev,
>>> + struct device_attribute *attr,
>>> + char *buf)
>>> +{
>>> + struct iio_dev *indio_dev = dev_get_drvdata(dev);
>>> + struct hid_sensor_attributes *st = iio_priv(indio_dev);
>>> + struct accel_3d_state *accel_state =
>>> + (struct accel_3d_state *)st->private;
>>> + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
>>> + int report_id = -1;
>>> +
>>> + switch (this_attr->address) {
>>> + case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS:
>>> + report_id = accel_state->accel_x.report_id;
>>> + break;
>>> + case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS:
>>> + report_id = accel_state->accel_y.report_id;
>>> + break;
>>> + case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS:
>>> + report_id = accel_state->accel_z.report_id;
>>> + break;
>>> + default:
>>> + break;
>>> + }
>>> + if (report_id< 0)
>>> + return -EINVAL;
>>> +
>>> + return sensor_hub_input_attr_get_value(st->hdev,
>>> + HID_USAGE_SENSOR_ACCEL_3D, this_attr->address,
>>> + report_id, 4, buf);
>>> +}
>>> +
>>> +static int accel_3d_read_raw(struct iio_dev *indio_dev,
>>> + struct iio_chan_spec const *chan,
>>> + int *val, int *val2,
>>> + long mask)
>>> +{
>>> + struct hid_sensor_attributes *st = iio_priv(indio_dev);
>>> + struct accel_3d_state *accel_state =
>>> + (struct accel_3d_state *)st->private;
>>> + *val = 0;
>>> + *val2 = 0;
>>> +
>>> + switch (mask) {
>>> + case 0:
>>> + break;
>>> + case IIO_CHAN_INFO_SCALE:
>>> + *val = accel_state->accel_x.units;
>>> + break;
>>> + case IIO_CHAN_INFO_OFFSET:
>>> + *val = accel_state->accel_x.unit_expo;
>>> + break;
>>> + default:
>>> + break;
>>> +
>>> + }
>>> + return IIO_VAL_INT;
>>> +}
>>> +
>>> +static int accel_3d_write_raw(struct iio_dev *indio_dev,
>>> + struct iio_chan_spec const *chan,
>>> + int val,
>>> + int val2,
>>> + long mask)
>>> +{
>>> + printk(KERN_ERR "%s\n", __func__);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +/* Usage specific attributes */
>>> +#define IIO_DEV_ATTR_ACCEL_OFFSET(_mode, _show, _store, _addr) \
>>> + IIO_DEVICE_ATTR(accel_offset, _mode, _show, _store, _addr)
>>> +
>>> +#define IIO_DEV_ATTR_ACCEL_X_OFFSET(_mode, _show, _store, _addr)
>>> \
>>> + IIO_DEVICE_ATTR(accel_x_offset, _mode, _show, _store, _addr)
>>> +
>>> +#define IIO_DEV_ATTR_ACCEL_Y_OFFSET(_mode, _show, _store, _addr)
>>> \
>>> + IIO_DEVICE_ATTR(accel_y_offset, _mode, _show, _store, _addr)
>>> +
>>> +#define IIO_DEV_ATTR_ACCEL_Z_OFFSET(_mode, _show, _store, _addr)
>>> \
>>> + IIO_DEVICE_ATTR(accel_z_offset, _mode, _show, _store, _addr)
>>> +
>>> +#define IIO_DEV_ATTR_ACCEL_SENSITIVITY(_mode, _show, _store, _addr)
>>> \
>>> + IIO_DEVICE_ATTR(accel_sensitivity, _mode, _show, _store, _addr)
>>> +
>>> +static IIO_DEV_ATTR_ACCEL_X_OFFSET(S_IWUSR | S_IRUGO,
>>> accel_3d_read_accel,
>>> + NULL, HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS);
>>> +static IIO_DEV_ATTR_ACCEL_Y_OFFSET(S_IWUSR | S_IRUGO,
>>> accel_3d_read_accel,
>>> + NULL, HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS);
>>> +static IIO_DEV_ATTR_ACCEL_Z_OFFSET(S_IWUSR | S_IRUGO,
>>> accel_3d_read_accel,
>>> + NULL, HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS);
>>> +
>>> +static struct attribute *accel_3d_attributes[] = {
>>> + /* common attributes */
>>> + &iio_dev_attr_poll_interval.dev_attr.attr,
>>> + &iio_dev_attr_sensitivity.dev_attr.attr,
>>> + &iio_dev_attr_activate.dev_attr.attr,
>>> + /* Usage specific attributes */
>>> + &iio_dev_attr_accel_x_offset.dev_attr.attr,
>>> + &iio_dev_attr_accel_y_offset.dev_attr.attr,
>>> + &iio_dev_attr_accel_z_offset.dev_attr.attr,
>>> + NULL,
>>> +};
>>> +
>>> +static const struct attribute_group accel_3d_attribute_group = {
>>> + .attrs = accel_3d_attributes,
>>> +};
>>> +
>>> +static const struct iio_info accel_3d_info = {
>>> + .attrs =&accel_3d_attribute_group,
>>> + .driver_module = THIS_MODULE,
>>> + .read_raw =&accel_3d_read_raw,
>>> + .write_raw =&accel_3d_write_raw,
>>> +};
>>> +
>>> +
>>> +/* Function to push data to IIO ring */ int
>>> +accel_3d_proc_event(struct hid_device *hdev, unsigned usage_id,
>>> void *priv)
>>> +{
>>> + struct iio_dev *indio_dev = (struct iio_dev *)priv;
>>> + struct hid_sensor_attributes *st = iio_priv(indio_dev);
>>> + struct accel_3d_state *accel_state =
>>> + (struct accel_3d_state *)st->private;
>>> +
>>> + hid_dbg(hdev, "accel_3d_proc_event\n");
>>> + if (st->data_ready)
>>> + hid_sensor_push_data_to_ring(indio_dev,
>>> + (u8 *)&accel_state->accel_sample_data,
>>> + sizeof(struct accel_3d_sample));
>>> + else
>>> + hid_dbg(hdev, "accel_3d_proc_event data not ready\n");
>>> + return 0;
>>> +}
>>> +
>>> +/* Capture samples in local storage */ int
>>> +accel_3d_capture_sample(struct hid_device *hdev, unsigned
>>> usage_id,
>>> + size_t raw_len, char *raw_data, void *priv) {
>>> + struct iio_dev *indio_dev = (struct iio_dev *)priv;
>>> + struct hid_sensor_attributes *st = iio_priv(indio_dev);
>>> + struct accel_3d_state *accel_state =
>>> + (struct accel_3d_state *)st->private;
>>> +
>>> + switch (usage_id) {
>>> + case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS:
>>> + accel_state->accel_sample_data.x_sz = raw_len;
>>> + accel_state->accel_sample_data.accel_x =
>>> + *(u32 *)raw_data;
>>> + break;
>>> + case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS:
>>> + accel_state->accel_sample_data.y_sz = raw_len;
>>> + accel_state->accel_sample_data.accel_y =
>>> + *(u32 *)raw_data;
>>> + break;
>>> + case HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS:
>>> + accel_state->accel_sample_data.z_sz = raw_len;
>>> + accel_state->accel_sample_data.accel_z =
>>> + *(u32 *)raw_data;
>>> + break;
>>> + default:
>>> + break;
>>> + }
>>> + return 0;
>>> +}
>>> +
>>> +
>>> +/* Parse report which is specific to an usage id*/ static int
>>> +accel_3d_parse_report(struct hid_device *hdev, unsigned
>>> usage_id,
>>> + struct accel_3d_state *st)
>>> +{
>>> + int ret;
>>> +
>>> + ret = sensor_hub_input_get_attribute_info(hdev, HID_INPUT_REPORT,
>>> + usage_id,
>>> + HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_X_AXIS,
>>> + &st->accel_x);
>>> + if (!ret)
>>> + hid_dbg(hdev, "No Accel X attribute\n");
>>> +
>>> +
>>> + ret = sensor_hub_input_get_attribute_info(hdev, HID_INPUT_REPORT,
>>> + usage_id,
>>> + HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Y_AXIS,
>>> + &st->accel_y);
>>> + if (!ret)
>>> + hid_dbg(hdev, "No Accel Y attribute\n");
>>> +
>>> +
>>> + ret = sensor_hub_input_get_attribute_info(hdev, HID_INPUT_REPORT,
>>> + usage_id,
>>> + HID_USAGE_SENSOR_DATA_MOTION_ACCELERATION_Z_AXIS,
>>> + &st->accel_z);
>>> + if (!ret)
>>> + hid_dbg(hdev, "No Accel Z attribute\n");
>>> +
>>> + hid_dbg(hdev, "accel_3d %x:%x, %x:%x, %x:%x\n", st->accel_x.index,
>>> + st->accel_x.report_id,
>>> + st->accel_y.index, st->accel_y.report_id,
>>> + st->accel_z.index, st->accel_z.report_id);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +/* Entry function to initialize the processing for usage id */
>>> +static int accel_3d_enter(struct hid_device *hdev, unsigned usage_id,
>>> + void **priv)
>>> +{
>>> + int ret = 0;
>>> + static char *name = "accel_3d";
>>> + struct iio_dev *indio_dev;
>>> + struct accel_3d_state *accel_state;
>>> + struct hid_sensor_attributes *st;
>>> +
>>> + accel_state = kzalloc(sizeof(struct accel_3d_state), GFP_KERNEL);
>>> + if (accel_state == NULL) {
>>> + ret = -ENOMEM;
>>> + goto error_ret;
>>> + }
>>> +
>>> + indio_dev = iio_allocate_device(sizeof(struct
>>> hid_sensor_attributes));
>>> + if (indio_dev == NULL) {
>>> + ret = -ENOMEM;
>>> + goto error_free_state;
>>> + }
>>> + st = iio_priv(indio_dev);
>>> + st->usage_id = usage_id;
>>> + st->hdev = hdev;
>>> + st->private = (void *)accel_state;
>>> +
>>> + ret = hid_sensor_parse_common_attributes(hdev, usage_id, st);
>>> + if (ret) {
>>> + hid_err(hdev, "failed to setup common attributes\n");
>>> + goto error_free_dev;
>>> + }
>>> + ret = accel_3d_parse_report(hdev, usage_id, accel_state);
>>> + if (ret) {
>>> + hid_err(hdev, "failed to setup attributes\n");
>>> + goto error_free_dev;
>>> + }
>>> +
>>> + indio_dev->channels = accel_3d_channels;
>>> + indio_dev->num_channels =
>>> + ARRAY_SIZE(accel_3d_channels);
>>> + indio_dev->dev.parent =&hdev->dev;
>>> + indio_dev->info =&accel_3d_info;
>>> + indio_dev->name = name;
>>> + indio_dev->modes = INDIO_DIRECT_MODE;
>>> +
>>> + ret = hid_sensor_configure_ring(indio_dev);
>>> + if (ret) {
>>> + hid_err(hdev, "failed to initialize the ring\n");
>>> + goto error_free_dev;
>>> + }
>>> +
>>> + ret = iio_buffer_register(indio_dev,
>>> + accel_3d_channels,
>>> + ARRAY_SIZE(accel_3d_channels));
>>> + if (ret) {
>>> + hid_err(hdev, "failed to initialize the ring\n");
>>> + goto error_unreg_ring_funcs;
>>> + }
>>> + st->data_ready = true;
>>> + ret = hid_sensor_setup_trigger(indio_dev, name);
>>> + if (ret< 0) {
>>> + hid_err(hdev, "trigger setup failed\n");
>>> + goto error_uninit_ring;
>>> + }
>>> +
>>> + ret = iio_device_register(indio_dev);
>>> + if (ret) {
>>> + hid_err(hdev, "device register failed\n");
>>> + goto error_remove_trigger;
>>> + }
>>> + *priv = (void *)indio_dev;
>>> + return ret;
>>> +
>>> +error_remove_trigger:
>>> + hid_sensor_remove_trigger(indio_dev);
>>> +error_uninit_ring:
>>> + iio_buffer_unregister(indio_dev);
>>> +error_unreg_ring_funcs:
>>> + hid_sensor_ring_cleanup(indio_dev);
>>> +error_free_dev:
>>> + iio_free_device(indio_dev);
>>> +error_free_state:
>>> + kfree(accel_state);
>>> +error_ret:
>>> + return ret;
>>> +}
>>> +
>>> +static int accel_3d_exit(struct hid_device *hdev, void *priv) {
>>> + int ret = 0;
>>> + struct iio_dev *indio_dev = (struct iio_dev *)priv;
>>> + struct hid_sensor_attributes *st = iio_priv(indio_dev);
>>> + struct accel_3d_state *accel_state =
>>> + (struct accel_3d_state *)st->private;
>>> +
>>> + iio_device_unregister(indio_dev);
>>> + hid_sensor_remove_trigger(indio_dev);
>>> + iio_buffer_unregister(indio_dev);
>>> + hid_sensor_ring_cleanup(indio_dev);
>>> + iio_free_device(indio_dev);
>>> +
>>> + kfree(accel_state);
>>> + return ret;
>>> +}
>>> +
>>> +static struct sensor_hub_callbacks accel_3d_callbacks = {
>>> + .enter = accel_3d_enter,
>>> + .exit = accel_3d_exit,
>>> + .send_event = accel_3d_proc_event,
>>> + .capture_sample = accel_3d_capture_sample, };
>>> +
>>> +struct sensor_hub_callbacks *accel_3d_register_callbacks(void)
>>> +{
>>> + return&accel_3d_callbacks;
>>> +}
>>> diff --git a/drivers/staging/hid-sensors/hid-sensor-hub.c
>>> b/drivers/staging/hid-sensors/hid-sensor-hub.c
>>> index 384e0d0..55ae562 100644
>>> --- a/drivers/staging/hid-sensors/hid-sensor-hub.c
>>> +++ b/drivers/staging/hid-sensors/hid-sensor-hub.c
>>> @@ -60,6 +60,7 @@ struct sensor_hub_callbacks_list { };
>>>
>>> static struct sensor_hub_callbacks_list usage_callbacks[] = {
>>> + {HID_USAGE_SENSOR_ACCEL_3D, accel_3d_register_callbacks},
>>> {0}
>>> };
>>>
>>> diff --git a/drivers/staging/hid-sensors/hid-sensor-interface.h
>>> b/drivers/staging/hid-sensors/hid-sensor-interface.h
>>> index 477494f..3f4fe57 100644
>>> --- a/drivers/staging/hid-sensors/hid-sensor-interface.h
>>> +++ b/drivers/staging/hid-sensors/hid-sensor-interface.h
>>> @@ -84,4 +84,7 @@ void hid_sensor_push_data_to_ring(struct iio_dev
>>> *indio_dev, u8 *data, int hid_sensor_setup_trigger(struct iio_dev
>>> *indio_dev, char *name); void hid_sensor_remove_trigger(struct
>>> iio_dev *indio_dev);
>>>
>>> +/* Sensor usage id processing callbacks */ struct
>>> +sensor_hub_callbacks *accel_3d_register_callbacks(void);
>>> +
>>> #endif
>>> --
>>> 1.7.7.6
>>>
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-iio"
>>> in the body of a message to majordomo@vger.kernel.org More majordomo
>>> info at http://vger.kernel.org/majordomo-info.html
>>
>> --
>> Sent from my Android phone with K-9 Mail. Please excuse my brevity.
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH, 5/7] HID-Sensors: Added Gyro 3D
2012-06-06 15:39 [PATCH, 0/7] HID Sensor Driver srinivas pandruvada
` (3 preceding siblings ...)
2012-06-06 15:39 ` [PATCH, 4/7] HID-Sensors: Added accelerometer 3D srinivas pandruvada
@ 2012-06-06 15:39 ` srinivas pandruvada
2012-06-06 15:39 ` [PATCH, 6/7] HID-Sensors: Added Compass 3D srinivas pandruvada
2012-06-06 15:39 ` [PATCH, 7/7] HID-Sensors: Added ALS srinivas pandruvada
6 siblings, 0 replies; 16+ messages in thread
From: srinivas pandruvada @ 2012-06-06 15:39 UTC (permalink / raw)
To: linux-input; +Cc: linux-iio, Srinivas pandruvada
From: Srinivas pandruvada <srinivas.pandruvada@intel.com>
Added usage id processing for Gyro 3D. This uses IIO
interfaces "ring/buffer and trigger interface" to present
data to user mode.
Signed-off-by: Srinivas pandruvada <srinivas.pandruvada@intel.com>
---
drivers/staging/hid-sensors/Makefile | 1 +
drivers/staging/hid-sensors/hid-sensor-gyro-3d.c | 384 ++++++++++++++++++++
drivers/staging/hid-sensors/hid-sensor-hub.c | 1 +
drivers/staging/hid-sensors/hid-sensor-interface.h | 1 +
4 files changed, 387 insertions(+), 0 deletions(-)
create mode 100644 drivers/staging/hid-sensors/hid-sensor-gyro-3d.c
diff --git a/drivers/staging/hid-sensors/Makefile b/drivers/staging/hid-sensors/Makefile
index 4412079..9c975a0 100644
--- a/drivers/staging/hid-sensors/Makefile
+++ b/drivers/staging/hid-sensors/Makefile
@@ -10,4 +10,5 @@ hid-sensors-y += hid-sensor-attributes.o
hid-sensors-y += hid-sensor-ring.o
hid-sensors-y += hid-sensor-trigger.o
hid-sensors-y += hid-sensor-accel-3d.o
+hid-sensors-y += hid-sensor-gyro-3d.o
obj-$(CONFIG_HID_SENSORS) += hid-sensors.o
diff --git a/drivers/staging/hid-sensors/hid-sensor-gyro-3d.c b/drivers/staging/hid-sensors/hid-sensor-gyro-3d.c
new file mode 100644
index 0000000..33db581
--- /dev/null
+++ b/drivers/staging/hid-sensors/hid-sensor-gyro-3d.c
@@ -0,0 +1,384 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/usb.h>
+#include "usbhid/usbhid.h"
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "iio/iio.h"
+#include "iio/sysfs.h"
+#include "iio/ring_sw.h"
+#include "iio/trigger.h"
+#include "hid-sensor-ids.h"
+#include "hid-sensor-interface.h"
+#include "hid-sensor-attributes.h"
+
+
+struct gyro_3d_sample {
+ u16 x_sz;
+ u32 gyro_x;
+ u16 y_sz;
+ u32 gyro_y;
+ u16 z_sz;
+ u32 gyro_z;
+} __packed;
+
+struct gyro_3d_state {
+ struct hid_sensor_hub_attribute_info gyro_x;
+ struct hid_sensor_hub_attribute_info gyro_y;
+ struct hid_sensor_hub_attribute_info gyro_z;
+ struct gyro_3d_sample gyro_sample_data;
+};
+
+
+enum gyro_3d_chan {
+ GYRO_X_Y_Z,
+};
+
+enum gyro_3d_scan {
+ GYRO_3D_SCAN_ACC_X_Y_Z,
+};
+
+static struct iio_chan_spec gyro_3d_channels[] = {
+ IIO_CHAN(IIO_ANGL_VEL, 1, 0, 0, NULL, 0, IIO_MOD_X_AND_Y_AND_Z,
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
+ GYRO_X_Y_Z, GYRO_3D_SCAN_ACC_X_Y_Z,
+ IIO_ST('u', sizeof(struct gyro_3d_sample) * 8,
+ sizeof(struct gyro_3d_sample) * 8 , 0), 0),
+};
+
+static ssize_t gyro_3d_read_gyro(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ struct gyro_3d_state *gyro_state =
+ (struct gyro_3d_state *)st->private;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int report_id = -1;
+
+ switch (this_attr->address) {
+ case HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_X_AXIS:
+ report_id = gyro_state->gyro_x.report_id;
+ break;
+ case HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_Y_AXIS:
+ report_id = gyro_state->gyro_y.report_id;
+ break;
+ case HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_Z_AXIS:
+ report_id = gyro_state->gyro_z.report_id;
+ break;
+ default:
+ break;
+ }
+ if (report_id < 0)
+ return -EINVAL;
+
+ return sensor_hub_input_attr_get_value(st->hdev,
+ HID_USAGE_SENSOR_GYRO_3D, this_attr->address,
+ report_id, 4, buf);
+}
+
+static int gyro_3d_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2,
+ long mask)
+{
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ struct gyro_3d_state *gyro_state =
+ (struct gyro_3d_state *)st->private;
+ *val = 0;
+ *val2 = 0;
+
+ switch (mask) {
+ case 0:
+ break;
+ case IIO_CHAN_INFO_SCALE:
+ *val = gyro_state->gyro_x.units;
+ break;
+ case IIO_CHAN_INFO_OFFSET:
+ *val = gyro_state->gyro_x.unit_expo;
+ break;
+ default:
+ break;
+
+ }
+ return IIO_VAL_INT;
+}
+
+static int gyro_3d_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long mask)
+{
+ printk(KERN_ERR "%s\n", __func__);
+
+ return 0;
+}
+
+/* Usage specific attributes */
+#define IIO_DEV_ATTR_GYRO_OFFSET(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(gyro_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_GYRO_X_OFFSET(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(gyro_x_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_GYRO_Y_OFFSET(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(gyro_y_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_GYRO_Z_OFFSET(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(gyro_z_offset, _mode, _show, _store, _addr)
+
+static IIO_DEV_ATTR_GYRO_X_OFFSET(S_IWUSR | S_IRUGO, gyro_3d_read_gyro,
+ NULL, HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_X_AXIS);
+static IIO_DEV_ATTR_GYRO_Y_OFFSET(S_IWUSR | S_IRUGO, gyro_3d_read_gyro,
+ NULL, HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_Y_AXIS);
+static IIO_DEV_ATTR_GYRO_Z_OFFSET(S_IWUSR | S_IRUGO, gyro_3d_read_gyro,
+ NULL, HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_Z_AXIS);
+
+static struct attribute *gyro_3d_attributes[] = {
+ /* common attributes */
+ &iio_dev_attr_poll_interval.dev_attr.attr,
+ &iio_dev_attr_sensitivity.dev_attr.attr,
+ &iio_dev_attr_activate.dev_attr.attr,
+ /* Usage specific attributes */
+ &iio_dev_attr_gyro_x_offset.dev_attr.attr,
+ &iio_dev_attr_gyro_y_offset.dev_attr.attr,
+ &iio_dev_attr_gyro_z_offset.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group gyro_3d_attribute_group = {
+ .attrs = gyro_3d_attributes,
+};
+
+static const struct iio_info gyro_3d_info = {
+ .attrs = &gyro_3d_attribute_group,
+ .driver_module = THIS_MODULE,
+ .read_raw = &gyro_3d_read_raw,
+ .write_raw = &gyro_3d_write_raw,
+};
+
+
+/* Function to push data to IIO ring */
+int gyro_3d_proc_event(struct hid_device *hdev, unsigned usage_id, void *priv)
+{
+ struct iio_dev *indio_dev = (struct iio_dev *)priv;
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ struct gyro_3d_state *gyro_state =
+ (struct gyro_3d_state *)st->private;
+
+ hid_dbg(hdev, "gyro_3d_proc_event\n");
+ if (st->data_ready)
+ hid_sensor_push_data_to_ring(indio_dev,
+ (u8 *)&gyro_state->gyro_sample_data,
+ sizeof(struct gyro_3d_sample));
+ else
+ hid_dbg(hdev, "gyro_3d_proc_event data not ready\n");
+ return 0;
+}
+
+/* Capture samples in local storage */
+int gyro_3d_capture_sample(struct hid_device *hdev, unsigned usage_id,
+ size_t raw_len, char *raw_data, void *priv)
+{
+ struct iio_dev *indio_dev = (struct iio_dev *)priv;
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ struct gyro_3d_state *gyro_state =
+ (struct gyro_3d_state *)st->private;
+
+ switch (usage_id) {
+ case HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_X_AXIS:
+ gyro_state->gyro_sample_data.x_sz = raw_len;
+ gyro_state->gyro_sample_data.gyro_x =
+ *(u32 *)raw_data;
+ break;
+ case HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_Y_AXIS:
+ gyro_state->gyro_sample_data.y_sz = raw_len;
+ gyro_state->gyro_sample_data.gyro_y =
+ *(u32 *)raw_data;
+ break;
+ case HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_Z_AXIS:
+ gyro_state->gyro_sample_data.z_sz = raw_len;
+ gyro_state->gyro_sample_data.gyro_z =
+ *(u32 *)raw_data;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+/* Parse report which is specific to an usage id*/
+static int gyro_3d_parse_report(struct hid_device *hdev, unsigned usage_id,
+ struct gyro_3d_state *st)
+{
+ int ret;
+
+ ret = sensor_hub_input_get_attribute_info(hdev, HID_INPUT_REPORT,
+ usage_id,
+ HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_X_AXIS,
+ &st->gyro_x);
+ if (!ret)
+ hid_dbg(hdev, "No Gyro X attribute\n");
+
+
+ ret = sensor_hub_input_get_attribute_info(hdev, HID_INPUT_REPORT,
+ usage_id,
+ HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_Y_AXIS,
+ &st->gyro_y);
+ if (!ret)
+ hid_dbg(hdev, "No Gyro Y attribute\n");
+
+
+ ret = sensor_hub_input_get_attribute_info(hdev, HID_INPUT_REPORT,
+ usage_id,
+ HID_USAGE_SENSOR_DATA_MOTION_ANGULAR_VELOCITY_Z_AXIS,
+ &st->gyro_z);
+ if (!ret)
+ hid_dbg(hdev, "No Gyro Z attribute\n");
+
+ hid_dbg(hdev, "gyro_3d %x:%x, %x:%x, %x:%x\n", st->gyro_x.index,
+ st->gyro_x.report_id,
+ st->gyro_y.index, st->gyro_y.report_id,
+ st->gyro_z.index, st->gyro_z.report_id);
+
+ return 0;
+}
+
+/* Entry function to initialize the processing for usage id */
+static int gyro_3d_enter(struct hid_device *hdev, unsigned usage_id,
+ void **priv)
+{
+ int ret = 0;
+ static char *name = "gyro_3d";
+ struct iio_dev *indio_dev;
+ struct gyro_3d_state *gyro_state;
+ struct hid_sensor_attributes *st;
+
+ gyro_state = kzalloc(sizeof(struct gyro_3d_state), GFP_KERNEL);
+ if (gyro_state == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ indio_dev = iio_allocate_device(sizeof(struct hid_sensor_attributes));
+ if (indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_state;
+ }
+ st = iio_priv(indio_dev);
+ st->usage_id = usage_id;
+ st->hdev = hdev;
+ st->private = (void *)gyro_state;
+
+ ret = hid_sensor_parse_common_attributes(hdev, usage_id, st);
+ if (ret) {
+ hid_err(hdev, "failed to setup common attributes\n");
+ goto error_free_dev;
+ }
+ ret = gyro_3d_parse_report(hdev, usage_id, gyro_state);
+ if (ret) {
+ hid_err(hdev, "failed to setup attributes\n");
+ goto error_free_dev;
+ }
+
+ indio_dev->channels = gyro_3d_channels;
+ indio_dev->num_channels =
+ ARRAY_SIZE(gyro_3d_channels);
+ indio_dev->dev.parent = &hdev->dev;
+ indio_dev->info = &gyro_3d_info;
+ indio_dev->name = name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = hid_sensor_configure_ring(indio_dev);
+ if (ret) {
+ hid_err(hdev, "failed to initialize the ring\n");
+ goto error_free_dev;
+ }
+
+ ret = iio_buffer_register(indio_dev,
+ gyro_3d_channels,
+ ARRAY_SIZE(gyro_3d_channels));
+ if (ret) {
+ hid_err(hdev, "failed to initialize the ring\n");
+ goto error_unreg_ring_funcs;
+ }
+ st->data_ready = true;
+ ret = hid_sensor_setup_trigger(indio_dev, name);
+ if (ret < 0) {
+ hid_err(hdev, "trigger setup failed\n");
+ goto error_uninit_ring;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ hid_err(hdev, "device register failed\n");
+ goto error_remove_trigger;
+ }
+ *priv = (void *)indio_dev;
+ return ret;
+
+error_remove_trigger:
+ hid_sensor_remove_trigger(indio_dev);
+error_uninit_ring:
+ iio_buffer_unregister(indio_dev);
+error_unreg_ring_funcs:
+ hid_sensor_ring_cleanup(indio_dev);
+error_free_dev:
+ iio_free_device(indio_dev);
+error_free_state:
+ kfree(gyro_state);
+error_ret:
+ return ret;
+}
+
+static int gyro_3d_exit(struct hid_device *hdev, void *priv)
+{
+ int ret = 0;
+ struct iio_dev *indio_dev = (struct iio_dev *)priv;
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ struct gyro_3d_state *gyro_state =
+ (struct gyro_3d_state *)st->private;
+
+ iio_device_unregister(indio_dev);
+ hid_sensor_remove_trigger(indio_dev);
+ iio_buffer_unregister(indio_dev);
+ hid_sensor_ring_cleanup(indio_dev);
+ iio_free_device(indio_dev);
+
+ kfree(gyro_state);
+ return ret;
+}
+
+static struct sensor_hub_callbacks gyro_3d_callbacks = {
+ .enter = gyro_3d_enter,
+ .exit = gyro_3d_exit,
+ .send_event = gyro_3d_proc_event,
+ .capture_sample = gyro_3d_capture_sample,
+};
+
+struct sensor_hub_callbacks *gyro_3d_register_callbacks(void)
+{
+ return &gyro_3d_callbacks;
+}
diff --git a/drivers/staging/hid-sensors/hid-sensor-hub.c b/drivers/staging/hid-sensors/hid-sensor-hub.c
index 55ae562..f98b5fe 100644
--- a/drivers/staging/hid-sensors/hid-sensor-hub.c
+++ b/drivers/staging/hid-sensors/hid-sensor-hub.c
@@ -61,6 +61,7 @@ struct sensor_hub_callbacks_list {
static struct sensor_hub_callbacks_list usage_callbacks[] = {
{HID_USAGE_SENSOR_ACCEL_3D, accel_3d_register_callbacks},
+ {HID_USAGE_SENSOR_GYRO_3D, gyro_3d_register_callbacks},
{0}
};
diff --git a/drivers/staging/hid-sensors/hid-sensor-interface.h b/drivers/staging/hid-sensors/hid-sensor-interface.h
index 3f4fe57..b242d87 100644
--- a/drivers/staging/hid-sensors/hid-sensor-interface.h
+++ b/drivers/staging/hid-sensors/hid-sensor-interface.h
@@ -86,5 +86,6 @@ void hid_sensor_remove_trigger(struct iio_dev *indio_dev);
/* Sensor usage id processing callbacks */
struct sensor_hub_callbacks *accel_3d_register_callbacks(void);
+struct sensor_hub_callbacks *gyro_3d_register_callbacks(void);
#endif
--
1.7.7.6
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH, 6/7] HID-Sensors: Added Compass 3D
2012-06-06 15:39 [PATCH, 0/7] HID Sensor Driver srinivas pandruvada
` (4 preceding siblings ...)
2012-06-06 15:39 ` [PATCH, 5/7] HID-Sensors: Added Gyro 3D srinivas pandruvada
@ 2012-06-06 15:39 ` srinivas pandruvada
2012-06-06 15:39 ` [PATCH, 7/7] HID-Sensors: Added ALS srinivas pandruvada
6 siblings, 0 replies; 16+ messages in thread
From: srinivas pandruvada @ 2012-06-06 15:39 UTC (permalink / raw)
To: linux-input; +Cc: linux-iio, Srinivas pandruvada
From: Srinivas pandruvada <srinivas.pandruvada@intel.com>
Added usage id processing for Compass 3D. This uses IIO
interfaces "ring/buffer and trigger interface" to present
data to user mode.
Signed-off-by: Srinivas pandruvada <srinivas.pandruvada@intel.com>
---
drivers/staging/hid-sensors/Makefile | 1 +
.../staging/hid-sensors/hid-sensor-compass-3d.c | 385 ++++++++++++++++++++
drivers/staging/hid-sensors/hid-sensor-hub.c | 1 +
drivers/staging/hid-sensors/hid-sensor-interface.h | 1 +
4 files changed, 388 insertions(+), 0 deletions(-)
create mode 100644 drivers/staging/hid-sensors/hid-sensor-compass-3d.c
diff --git a/drivers/staging/hid-sensors/Makefile b/drivers/staging/hid-sensors/Makefile
index 9c975a0..9762232 100644
--- a/drivers/staging/hid-sensors/Makefile
+++ b/drivers/staging/hid-sensors/Makefile
@@ -11,4 +11,5 @@ hid-sensors-y += hid-sensor-ring.o
hid-sensors-y += hid-sensor-trigger.o
hid-sensors-y += hid-sensor-accel-3d.o
hid-sensors-y += hid-sensor-gyro-3d.o
+hid-sensors-y += hid-sensor-compass-3d.o
obj-$(CONFIG_HID_SENSORS) += hid-sensors.o
diff --git a/drivers/staging/hid-sensors/hid-sensor-compass-3d.c b/drivers/staging/hid-sensors/hid-sensor-compass-3d.c
new file mode 100644
index 0000000..fb24059
--- /dev/null
+++ b/drivers/staging/hid-sensors/hid-sensor-compass-3d.c
@@ -0,0 +1,385 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/usb.h>
+#include "usbhid/usbhid.h"
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "iio/iio.h"
+#include "iio/sysfs.h"
+#include "iio/ring_sw.h"
+#include "iio/trigger.h"
+#include "hid-sensor-ids.h"
+#include "hid-sensor-interface.h"
+#include "hid-sensor-attributes.h"
+
+
+struct compass_3d_sample {
+ u16 x_sz;
+ u32 compass_x;
+ u16 y_sz;
+ u32 compass_y;
+ u16 z_sz;
+ u32 compass_z;
+} __packed;
+
+struct compass_3d_state {
+ struct hid_sensor_hub_attribute_info compass_x;
+ struct hid_sensor_hub_attribute_info compass_y;
+ struct hid_sensor_hub_attribute_info compass_z;
+ struct compass_3d_sample compass_sample_data;
+};
+
+
+enum compass_3d_chan {
+ COMPASS_X_Y_Z,
+};
+
+enum compass_3d_scan {
+ COMPASS_3D_SCAN_ACC_X_Y_Z,
+};
+
+static struct iio_chan_spec compass_3d_channels[] = {
+ IIO_CHAN(IIO_MAGN, 1, 0, 0, NULL, 0, IIO_MOD_X_AND_Y_AND_Z,
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
+ COMPASS_X_Y_Z, COMPASS_3D_SCAN_ACC_X_Y_Z,
+ IIO_ST('u', sizeof(struct compass_3d_sample) * 8,
+ sizeof(struct compass_3d_sample) * 8, 0), 0),
+};
+
+static ssize_t compass_3d_read_compass(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ struct compass_3d_state *compass_state =
+ (struct compass_3d_state *)st->private;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int report_id = -1;
+
+ switch (this_attr->address) {
+ case HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_X_AXIS:
+ report_id = compass_state->compass_x.report_id;
+ break;
+ case HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Y_AXIS:
+ report_id = compass_state->compass_y.report_id;
+ break;
+ case HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Z_AXIS:
+ report_id = compass_state->compass_z.report_id;
+ break;
+ default:
+ break;
+ }
+ if (report_id < 0)
+ return -EINVAL;
+
+ return sensor_hub_input_attr_get_value(st->hdev,
+ HID_USAGE_SENSOR_COMPASS_3D, this_attr->address,
+ report_id, 4, buf);
+}
+
+static int compass_3d_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2,
+ long mask)
+{
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ struct compass_3d_state *compass_state =
+ (struct compass_3d_state *)st->private;
+ *val = 0;
+ *val2 = 0;
+
+ switch (mask) {
+ case 0:
+ break;
+ case IIO_CHAN_INFO_SCALE:
+ *val = compass_state->compass_x.units;
+ break;
+ case IIO_CHAN_INFO_OFFSET:
+ *val = compass_state->compass_x.unit_expo;
+ break;
+ default:
+ break;
+
+ }
+ return IIO_VAL_INT;
+}
+
+static int compass_3d_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long mask)
+{
+ printk(KERN_ERR "%s\n", __func__);
+
+ return 0;
+}
+
+/* Usage specific attributes */
+#define IIO_DEV_ATTR_MAGN_OFFSET(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(compass_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_MAGN_X_OFFSET(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(compass_x_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_MAGN_Y_OFFSET(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(compass_y_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_MAGN_Z_OFFSET(_mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(compass_z_offset, _mode, _show, _store, _addr)
+
+static IIO_DEV_ATTR_MAGN_X_OFFSET(S_IWUSR | S_IRUGO, compass_3d_read_compass,
+ NULL, HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_X_AXIS);
+static IIO_DEV_ATTR_MAGN_Y_OFFSET(S_IWUSR | S_IRUGO, compass_3d_read_compass,
+ NULL, HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Y_AXIS);
+static IIO_DEV_ATTR_MAGN_Z_OFFSET(S_IWUSR | S_IRUGO, compass_3d_read_compass,
+ NULL, HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Z_AXIS);
+
+static struct attribute *compass_3d_attributes[] = {
+ /* common attributes */
+ &iio_dev_attr_poll_interval.dev_attr.attr,
+ &iio_dev_attr_sensitivity.dev_attr.attr,
+ &iio_dev_attr_activate.dev_attr.attr,
+ /* Usage specific attributes */
+ &iio_dev_attr_compass_x_offset.dev_attr.attr,
+ &iio_dev_attr_compass_y_offset.dev_attr.attr,
+ &iio_dev_attr_compass_z_offset.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group compass_3d_attribute_group = {
+ .attrs = compass_3d_attributes,
+};
+
+static const struct iio_info compass_3d_info = {
+ .attrs = &compass_3d_attribute_group,
+ .driver_module = THIS_MODULE,
+ .read_raw = &compass_3d_read_raw,
+ .write_raw = &compass_3d_write_raw,
+};
+
+
+/* Function to push data to IIO ring */
+int compass_3d_proc_event(struct hid_device *hdev, unsigned usage_id,
+ void *priv)
+{
+ struct iio_dev *indio_dev = (struct iio_dev *)priv;
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ struct compass_3d_state *compass_state =
+ (struct compass_3d_state *)st->private;
+
+ hid_dbg(hdev, "compass_3d_proc_event\n");
+ if (st->data_ready)
+ hid_sensor_push_data_to_ring(indio_dev,
+ (u8 *)&compass_state->compass_sample_data,
+ sizeof(struct compass_3d_sample));
+ else
+ hid_dbg(hdev, "compass_3d_proc_event data not ready\n");
+ return 0;
+}
+
+/* Capture samples in local storage */
+int compass_3d_capture_sample(struct hid_device *hdev, unsigned usage_id,
+ size_t raw_len, char *raw_data, void *priv)
+{
+ struct iio_dev *indio_dev = (struct iio_dev *)priv;
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ struct compass_3d_state *compass_state =
+ (struct compass_3d_state *)st->private;
+
+ switch (usage_id) {
+ case HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_X_AXIS:
+ compass_state->compass_sample_data.x_sz = raw_len;
+ compass_state->compass_sample_data.compass_x =
+ *(u32 *)raw_data;
+ break;
+ case HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Y_AXIS:
+ compass_state->compass_sample_data.y_sz = raw_len;
+ compass_state->compass_sample_data.compass_y =
+ *(u32 *)raw_data;
+ break;
+ case HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Z_AXIS:
+ compass_state->compass_sample_data.z_sz = raw_len;
+ compass_state->compass_sample_data.compass_z =
+ *(u32 *)raw_data;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+/* Parse report which is specific to an usage id*/
+static int compass_3d_parse_report(struct hid_device *hdev, unsigned usage_id,
+ struct compass_3d_state *st)
+{
+ int ret;
+
+ ret = sensor_hub_input_get_attribute_info(hdev, HID_INPUT_REPORT,
+ usage_id,
+ HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_X_AXIS,
+ &st->compass_x);
+ if (!ret)
+ hid_dbg(hdev, "No Gyro X attribute\n");
+
+
+ ret = sensor_hub_input_get_attribute_info(hdev, HID_INPUT_REPORT,
+ usage_id,
+ HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Y_AXIS,
+ &st->compass_y);
+ if (!ret)
+ hid_dbg(hdev, "No Gyro Y attribute\n");
+
+
+ ret = sensor_hub_input_get_attribute_info(hdev, HID_INPUT_REPORT,
+ usage_id,
+ HID_USAGE_SENSOR_DATA_ORIENTATION_MAGNETIC_FLUX_Z_AXIS,
+ &st->compass_z);
+ if (!ret)
+ hid_dbg(hdev, "No Gyro Z attribute\n");
+
+ hid_dbg(hdev, "compass_3d %x:%x, %x:%x, %x:%x\n", st->compass_x.index,
+ st->compass_x.report_id,
+ st->compass_y.index, st->compass_y.report_id,
+ st->compass_z.index, st->compass_z.report_id);
+
+ return 0;
+}
+
+/* Entry function to initialize the processing for usage id */
+static int compass_3d_enter(struct hid_device *hdev, unsigned usage_id,
+ void **priv)
+{
+ int ret = 0;
+ static char *name = "compass_3d";
+ struct iio_dev *indio_dev;
+ struct compass_3d_state *compass_state;
+ struct hid_sensor_attributes *st;
+
+ compass_state = kzalloc(sizeof(struct compass_3d_state), GFP_KERNEL);
+ if (compass_state == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ indio_dev = iio_allocate_device(sizeof(struct hid_sensor_attributes));
+ if (indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_state;
+ }
+ st = iio_priv(indio_dev);
+ st->usage_id = usage_id;
+ st->hdev = hdev;
+ st->private = (void *)compass_state;
+
+ ret = hid_sensor_parse_common_attributes(hdev, usage_id, st);
+ if (ret) {
+ hid_err(hdev, "failed to setup common attributes\n");
+ goto error_free_dev;
+ }
+ ret = compass_3d_parse_report(hdev, usage_id, compass_state);
+ if (ret) {
+ hid_err(hdev, "failed to setup attributes\n");
+ goto error_free_dev;
+ }
+
+ indio_dev->channels = compass_3d_channels;
+ indio_dev->num_channels =
+ ARRAY_SIZE(compass_3d_channels);
+ indio_dev->dev.parent = &hdev->dev;
+ indio_dev->info = &compass_3d_info;
+ indio_dev->name = name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = hid_sensor_configure_ring(indio_dev);
+ if (ret) {
+ hid_err(hdev, "failed to initialize the ring\n");
+ goto error_free_dev;
+ }
+
+ ret = iio_buffer_register(indio_dev,
+ compass_3d_channels,
+ ARRAY_SIZE(compass_3d_channels));
+ if (ret) {
+ hid_err(hdev, "failed to initialize the ring\n");
+ goto error_unreg_ring_funcs;
+ }
+ st->data_ready = true;
+ ret = hid_sensor_setup_trigger(indio_dev, name);
+ if (ret < 0) {
+ hid_err(hdev, "trigger setup failed\n");
+ goto error_uninit_ring;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ hid_err(hdev, "device register failed\n");
+ goto error_remove_trigger;
+ }
+ *priv = (void *)indio_dev;
+ return ret;
+
+error_remove_trigger:
+ hid_sensor_remove_trigger(indio_dev);
+error_uninit_ring:
+ iio_buffer_unregister(indio_dev);
+error_unreg_ring_funcs:
+ hid_sensor_ring_cleanup(indio_dev);
+error_free_dev:
+ iio_free_device(indio_dev);
+error_free_state:
+ kfree(compass_state);
+error_ret:
+ return ret;
+}
+
+static int compass_3d_exit(struct hid_device *hdev, void *priv)
+{
+ int ret = 0;
+ struct iio_dev *indio_dev = (struct iio_dev *)priv;
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ struct compass_3d_state *compass_state =
+ (struct compass_3d_state *)st->private;
+
+ iio_device_unregister(indio_dev);
+ hid_sensor_remove_trigger(indio_dev);
+ iio_buffer_unregister(indio_dev);
+ hid_sensor_ring_cleanup(indio_dev);
+ iio_free_device(indio_dev);
+
+ kfree(compass_state);
+ return ret;
+}
+
+static struct sensor_hub_callbacks compass_3d_callbacks = {
+ .enter = compass_3d_enter,
+ .exit = compass_3d_exit,
+ .send_event = compass_3d_proc_event,
+ .capture_sample = compass_3d_capture_sample,
+};
+
+struct sensor_hub_callbacks *compass_3d_register_callbacks(void)
+{
+ return &compass_3d_callbacks;
+}
diff --git a/drivers/staging/hid-sensors/hid-sensor-hub.c b/drivers/staging/hid-sensors/hid-sensor-hub.c
index f98b5fe..d61affa 100644
--- a/drivers/staging/hid-sensors/hid-sensor-hub.c
+++ b/drivers/staging/hid-sensors/hid-sensor-hub.c
@@ -62,6 +62,7 @@ struct sensor_hub_callbacks_list {
static struct sensor_hub_callbacks_list usage_callbacks[] = {
{HID_USAGE_SENSOR_ACCEL_3D, accel_3d_register_callbacks},
{HID_USAGE_SENSOR_GYRO_3D, gyro_3d_register_callbacks},
+ {HID_USAGE_SENSOR_COMPASS_3D, compass_3d_register_callbacks},
{0}
};
diff --git a/drivers/staging/hid-sensors/hid-sensor-interface.h b/drivers/staging/hid-sensors/hid-sensor-interface.h
index b242d87..b0df328 100644
--- a/drivers/staging/hid-sensors/hid-sensor-interface.h
+++ b/drivers/staging/hid-sensors/hid-sensor-interface.h
@@ -87,5 +87,6 @@ void hid_sensor_remove_trigger(struct iio_dev *indio_dev);
/* Sensor usage id processing callbacks */
struct sensor_hub_callbacks *accel_3d_register_callbacks(void);
struct sensor_hub_callbacks *gyro_3d_register_callbacks(void);
+struct sensor_hub_callbacks *compass_3d_register_callbacks(void);
#endif
--
1.7.7.6
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH, 7/7] HID-Sensors: Added ALS
2012-06-06 15:39 [PATCH, 0/7] HID Sensor Driver srinivas pandruvada
` (5 preceding siblings ...)
2012-06-06 15:39 ` [PATCH, 6/7] HID-Sensors: Added Compass 3D srinivas pandruvada
@ 2012-06-06 15:39 ` srinivas pandruvada
6 siblings, 0 replies; 16+ messages in thread
From: srinivas pandruvada @ 2012-06-06 15:39 UTC (permalink / raw)
To: linux-input; +Cc: linux-iio, Srinivas pandruvada
From: Srinivas pandruvada <srinivas.pandruvada@intel.com>
Added usage id processing for ALS. This uses IIO
interfaces "ring/buffer and trigger interface" to present
data to user mode.
Signed-off-by: srinivas pandruvada <srinivas.pandruvada@intel.com>
---
drivers/staging/hid-sensors/Makefile | 1 +
drivers/staging/hid-sensors/hid-sensor-als.c | 326 ++++++++++++++++++++
drivers/staging/hid-sensors/hid-sensor-hub.c | 1 +
drivers/staging/hid-sensors/hid-sensor-interface.h | 1 +
4 files changed, 329 insertions(+), 0 deletions(-)
create mode 100644 drivers/staging/hid-sensors/hid-sensor-als.c
diff --git a/drivers/staging/hid-sensors/Makefile b/drivers/staging/hid-sensors/Makefile
index 9762232..e8d728a 100644
--- a/drivers/staging/hid-sensors/Makefile
+++ b/drivers/staging/hid-sensors/Makefile
@@ -12,4 +12,5 @@ hid-sensors-y += hid-sensor-trigger.o
hid-sensors-y += hid-sensor-accel-3d.o
hid-sensors-y += hid-sensor-gyro-3d.o
hid-sensors-y += hid-sensor-compass-3d.o
+hid-sensors-y += hid-sensor-als.o
obj-$(CONFIG_HID_SENSORS) += hid-sensors.o
diff --git a/drivers/staging/hid-sensors/hid-sensor-als.c b/drivers/staging/hid-sensors/hid-sensor-als.c
new file mode 100644
index 0000000..360e0c2
--- /dev/null
+++ b/drivers/staging/hid-sensors/hid-sensor-als.c
@@ -0,0 +1,326 @@
+/*
+ * HID Sensors Driver
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/usb.h>
+#include "usbhid/usbhid.h"
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "iio/iio.h"
+#include "iio/sysfs.h"
+#include "iio/ring_sw.h"
+#include "iio/trigger.h"
+#include "hid-sensor-ids.h"
+#include "hid-sensor-interface.h"
+#include "hid-sensor-attributes.h"
+
+
+struct als_sample {
+ u16 illum;
+ u16 chromocity;
+} __packed;
+
+struct als_state {
+ struct hid_sensor_hub_attribute_info als_illum;
+ struct hid_sensor_hub_attribute_info als_chromocity;
+ struct als_sample als_sample_data;
+};
+
+
+enum als_chan {
+ ALS_ILLUM,
+};
+
+enum als_scan {
+ ALS_ILLUM_SCAN_ILLUM,
+};
+
+static struct iio_chan_spec als_channels[] = {
+ IIO_CHAN(IIO_INTENSITY, 1, 0, 0, NULL, 0, IIO_MOD_LIGHT_BOTH,
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
+ ALS_ILLUM, ALS_ILLUM_SCAN_ILLUM,
+ IIO_ST('u', 32, 32, 32), 0),
+};
+
+static ssize_t als_read(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ struct als_state *als_state =
+ (struct als_state *)st->private;
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ int report_id = -1;
+
+ switch (this_attr->address) {
+ case HID_USAGE_SENSOR_DATA_LIGHT_ILLUMINANCE:
+ report_id = als_state->als_illum.report_id;
+ break;
+
+ default:
+ break;
+ }
+ if (report_id < 0)
+ return -EINVAL;
+
+ return sensor_hub_input_attr_get_value(st->hdev,
+ HID_USAGE_SENSOR_ALS, this_attr->address,
+ report_id, 4, buf);
+}
+
+static int als_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2,
+ long mask)
+{
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ struct als_state *als_state =
+ (struct als_state *)st->private;
+ *val = 0;
+ *val2 = 0;
+
+ switch (mask) {
+ case 0:
+ break;
+ case IIO_CHAN_INFO_SCALE:
+ *val = als_state->als_illum.units;
+ break;
+ case IIO_CHAN_INFO_OFFSET:
+ *val = als_state->als_illum.unit_expo;
+ break;
+ default:
+ break;
+
+ }
+ return IIO_VAL_INT;
+}
+
+static int als_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long mask)
+{
+ printk(KERN_ERR "%s\n", __func__);
+
+ return 0;
+}
+
+/* Usage specific attributes */
+static DEVICE_ATTR(illuminance0_input, S_IRUGO, als_read, NULL);
+
+static struct attribute *als_attributes[] = {
+ /* common attributes */
+ &iio_dev_attr_poll_interval.dev_attr.attr,
+ &iio_dev_attr_sensitivity.dev_attr.attr,
+ &iio_dev_attr_activate.dev_attr.attr,
+ /* Usage specific attributes */
+ &dev_attr_illuminance0_input.attr,
+ NULL,
+};
+
+static const struct attribute_group als_attribute_group = {
+ .attrs = als_attributes,
+};
+
+static const struct iio_info als_info = {
+ .attrs = &als_attribute_group,
+ .driver_module = THIS_MODULE,
+ .read_raw = &als_read_raw,
+ .write_raw = &als_write_raw,
+};
+
+
+/* Function to push data to IIO ring */
+int als_proc_event(struct hid_device *hdev, unsigned usage_id, void *priv)
+{
+ struct iio_dev *indio_dev = (struct iio_dev *)priv;
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ struct als_state *als_state =
+ (struct als_state *)st->private;
+
+ hid_dbg(hdev, "als_proc_event\n");
+ if (st->data_ready)
+ hid_sensor_push_data_to_ring(indio_dev,
+ (u8 *)&als_state->als_sample_data,
+ sizeof(struct als_sample));
+ else
+ hid_dbg(hdev, "als_proc_event data not ready\n");
+ return 0;
+}
+
+/* Capture samples in local storage */
+int als_capture_sample(struct hid_device *hdev, unsigned usage_id,
+ size_t raw_len, char *raw_data, void *priv)
+{
+ struct iio_dev *indio_dev = (struct iio_dev *)priv;
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ struct als_state *als_state =
+ (struct als_state *)st->private;
+
+ switch (usage_id) {
+ case HID_USAGE_SENSOR_DATA_LIGHT_ILLUMINANCE:
+ als_state->als_sample_data.illum =
+ *(u32 *)raw_data;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+/* Parse report which is specific to an usage id*/
+static int als_parse_report(struct hid_device *hdev, unsigned usage_id,
+ struct als_state *st)
+{
+ int ret;
+
+ ret = sensor_hub_input_get_attribute_info(hdev, HID_INPUT_REPORT,
+ usage_id,
+ HID_USAGE_SENSOR_DATA_LIGHT_ILLUMINANCE,
+ &st->als_illum);
+ if (!ret)
+ hid_dbg(hdev, "No Light Illum attribute\n");
+
+
+ hid_dbg(hdev, "als %x:%x\n", st->als_illum.index,
+ st->als_illum.report_id);
+
+ return 0;
+}
+
+/* Entry function to initialize the processing for usage id */
+static int als_enter(struct hid_device *hdev, unsigned usage_id,
+ void **priv)
+{
+ int ret = 0;
+ static char *name = "als";
+ struct iio_dev *indio_dev;
+ struct als_state *als_state;
+ struct hid_sensor_attributes *st;
+
+ als_state = kzalloc(sizeof(struct als_state), GFP_KERNEL);
+ if (als_state == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ indio_dev = iio_allocate_device(sizeof(struct hid_sensor_attributes));
+ if (indio_dev == NULL) {
+ ret = -ENOMEM;
+ goto error_free_state;
+ }
+ st = iio_priv(indio_dev);
+ st->usage_id = usage_id;
+ st->hdev = hdev;
+ st->private = (void *)als_state;
+
+ ret = hid_sensor_parse_common_attributes(hdev, usage_id, st);
+ if (ret) {
+ hid_err(hdev, "failed to setup common attributes\n");
+ goto error_free_dev;
+ }
+ ret = als_parse_report(hdev, usage_id, als_state);
+ if (ret) {
+ hid_err(hdev, "failed to setup attributes\n");
+ goto error_free_dev;
+ }
+
+ indio_dev->channels = als_channels;
+ indio_dev->num_channels =
+ ARRAY_SIZE(als_channels);
+ indio_dev->dev.parent = &hdev->dev;
+ indio_dev->info = &als_info;
+ indio_dev->name = name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = hid_sensor_configure_ring(indio_dev);
+ if (ret) {
+ hid_err(hdev, "failed to initialize the ring\n");
+ goto error_free_dev;
+ }
+
+ ret = iio_buffer_register(indio_dev,
+ als_channels,
+ ARRAY_SIZE(als_channels));
+ if (ret) {
+ hid_err(hdev, "failed to initialize the ring\n");
+ goto error_unreg_ring_funcs;
+ }
+ st->data_ready = true;
+ ret = hid_sensor_setup_trigger(indio_dev, name);
+ if (ret < 0) {
+ hid_err(hdev, "trigger setup failed\n");
+ goto error_uninit_ring;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ hid_err(hdev, "device register failed\n");
+ goto error_remove_trigger;
+ }
+ *priv = (void *)indio_dev;
+ return ret;
+
+error_remove_trigger:
+ hid_sensor_remove_trigger(indio_dev);
+error_uninit_ring:
+ iio_buffer_unregister(indio_dev);
+error_unreg_ring_funcs:
+ hid_sensor_ring_cleanup(indio_dev);
+error_free_dev:
+ iio_free_device(indio_dev);
+error_free_state:
+ kfree(als_state);
+error_ret:
+ return ret;
+}
+
+static int als_exit(struct hid_device *hdev, void *priv)
+{
+ int ret = 0;
+ struct iio_dev *indio_dev = (struct iio_dev *)priv;
+ struct hid_sensor_attributes *st = iio_priv(indio_dev);
+ struct als_state *als_state =
+ (struct als_state *)st->private;
+
+ iio_device_unregister(indio_dev);
+ hid_sensor_remove_trigger(indio_dev);
+ iio_buffer_unregister(indio_dev);
+ hid_sensor_ring_cleanup(indio_dev);
+ iio_free_device(indio_dev);
+
+ kfree(als_state);
+ return ret;
+}
+
+static struct sensor_hub_callbacks als_callbacks = {
+ .enter = als_enter,
+ .exit = als_exit,
+ .send_event = als_proc_event,
+ .capture_sample = als_capture_sample,
+};
+
+struct sensor_hub_callbacks *als_register_callbacks(void)
+{
+ return &als_callbacks;
+}
diff --git a/drivers/staging/hid-sensors/hid-sensor-hub.c b/drivers/staging/hid-sensors/hid-sensor-hub.c
index d61affa..6d724da 100644
--- a/drivers/staging/hid-sensors/hid-sensor-hub.c
+++ b/drivers/staging/hid-sensors/hid-sensor-hub.c
@@ -63,6 +63,7 @@ static struct sensor_hub_callbacks_list usage_callbacks[] = {
{HID_USAGE_SENSOR_ACCEL_3D, accel_3d_register_callbacks},
{HID_USAGE_SENSOR_GYRO_3D, gyro_3d_register_callbacks},
{HID_USAGE_SENSOR_COMPASS_3D, compass_3d_register_callbacks},
+ {HID_USAGE_SENSOR_ALS, als_register_callbacks},
{0}
};
diff --git a/drivers/staging/hid-sensors/hid-sensor-interface.h b/drivers/staging/hid-sensors/hid-sensor-interface.h
index b0df328..2d283ae 100644
--- a/drivers/staging/hid-sensors/hid-sensor-interface.h
+++ b/drivers/staging/hid-sensors/hid-sensor-interface.h
@@ -88,5 +88,6 @@ void hid_sensor_remove_trigger(struct iio_dev *indio_dev);
struct sensor_hub_callbacks *accel_3d_register_callbacks(void);
struct sensor_hub_callbacks *gyro_3d_register_callbacks(void);
struct sensor_hub_callbacks *compass_3d_register_callbacks(void);
+struct sensor_hub_callbacks *als_register_callbacks(void);
#endif
--
1.7.7.6
^ permalink raw reply related [flat|nested] 16+ messages in thread