[PATCH, 0/7] HID Sensor Driver

STALE5182d

7 messages, 3 authors, 2012-06-06 · open the first message on its own page

[PATCH, 0/7] HID Sensor Driver

From: srinivas pandruvada <hidden>
Date: 2012-06-06 15:39:17

This submits a set of patches to enable USB HID Sensor driver.
It is implemented as a HID driver and exports sensor interface
via Linux IIO interfaces. This implements a basic usage id processing
for Accelerometer 3D, Gyro 3D, Magnetometer 3D and ALS.

Srinivas pandruvada (5):
  HID-Sensors: Common attributes and interfaces
  HID-Sensors: Added accelerometer 3D
  HID-Sensors: Added Gyro 3D
  HID-Sensors: Added Compass 3D
  HID-Sensors: Added ALS

srinivas pandruvada (2):
  HID-Sensors: Add Intel HID sensor
  HID-Sensors: Sensor framework

 drivers/hid/hid-core.c                             |    6 +
 drivers/hid/hid-ids.h                              |    5 +
 drivers/staging/Kconfig                            |    2 +
 drivers/staging/Makefile                           |    1 +
 drivers/staging/hid-sensors/Kconfig                |   19 +
 drivers/staging/hid-sensors/Makefile               |   16 +
 drivers/staging/hid-sensors/hid-sensor-accel-3d.c  |  387 +++++++++++
 drivers/staging/hid-sensors/hid-sensor-als.c       |  326 +++++++++
 .../staging/hid-sensors/hid-sensor-attributes.c    |  203 ++++++
 .../staging/hid-sensors/hid-sensor-attributes.h    |   67 ++
 .../staging/hid-sensors/hid-sensor-compass-3d.c    |  385 +++++++++++
 drivers/staging/hid-sensors/hid-sensor-gyro-3d.c   |  384 +++++++++++
 drivers/staging/hid-sensors/hid-sensor-hub.c       |  709 ++++++++++++++++++++
 drivers/staging/hid-sensors/hid-sensor-ids.h       |  117 ++++
 drivers/staging/hid-sensors/hid-sensor-interface.h |   93 +++
 drivers/staging/hid-sensors/hid-sensor-ring.c      |  104 +++
 drivers/staging/hid-sensors/hid-sensor-trigger.c   |   81 +++
 17 files changed, 2905 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-accel-3d.c
 create mode 100644 drivers/staging/hid-sensors/hid-sensor-als.c
 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-compass-3d.c
 create mode 100644 drivers/staging/hid-sensors/hid-sensor-gyro-3d.c
 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
 create mode 100644 drivers/staging/hid-sensors/hid-sensor-ring.c
 create mode 100644 drivers/staging/hid-sensors/hid-sensor-trigger.c

-- 
1.7.7.6

[PATCH, 5/7] HID-Sensors: Added Gyro 3D

From: srinivas pandruvada <hidden>
Date: 2012-06-06 15:50:36

From: Srinivas pandruvada <redacted>

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 <redacted>
---
 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

[PATCH, 4/7] HID-Sensors: Added accelerometer 3D

From: srinivas pandruvada <hidden>
Date: 2012-06-06 15:50:36

From: Srinivas pandruvada <redacted>

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 <redacted>
---
 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

[PATCH, 6/7] HID-Sensors: Added Compass 3D

From: srinivas pandruvada <hidden>
Date: 2012-06-06 15:50:37

From: Srinivas pandruvada <redacted>

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 <redacted>
---
 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

[PATCH, 7/7] HID-Sensors: Added ALS

From: srinivas pandruvada <hidden>
Date: 2012-06-06 15:50:37

From: Srinivas pandruvada <redacted>

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 <redacted>
---
 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

Re: [PATCH, 4/7] HID-Sensors: Added accelerometer 3D

From: Jonathan Cameron <hidden>
Date: 2012-06-06 16:28:54


srinivas pandruvada [off-list ref] wrote:
From: Srinivas pandruvada <redacted>

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.
quoted hunk
Signed-off-by: Srinivas pandruvada <redacted>
---
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.

RE: [PATCH, 4/7] HID-Sensors: Added accelerometer 3D

From: Pandruvada, Srinivas <hidden>
Date: 2012-06-06 16:57:37

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. 

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 [off-list ref] wrote:
From: Srinivas pandruvada <redacted>

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.
quoted hunk
Signed-off-by: Srinivas pandruvada <redacted>
---
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.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help