sensors: hardware abstraction layer for native sensor support

This is the alternative sensor solution for platforms without
separate sensor processor, such as 8x10, 8x30, etc

Change-Id: I26f092f2728079aaec5b9d662f8e19fb9cdc4a50
diff --git a/AccelSensor.h b/AccelSensor.h
new file mode 100644
index 0000000..34b9c94
--- /dev/null
+++ b/AccelSensor.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *		http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_ACCEL_SENSOR_H
+#define ANDROID_ACCEL_SENSOR_H
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include "SensorBase.h"
+#include "InputEventReader.h"
+
+/*****************************************************************************/
+
+struct input_event;
+
+class AccelSensor : public SensorBase {
+	int mEnabled;
+	InputEventCircularReader mInputReader;
+	sensors_event_t mPendingEvent;
+	bool mHasPendingEvent;
+	char input_sysfs_path[PATH_MAX];
+	int input_sysfs_path_len;
+	int64_t mEnabledTime;
+
+	int setInitialState();
+
+public:
+			AccelSensor();
+	virtual ~AccelSensor();
+	virtual int readEvents(sensors_event_t* data, int count);
+	virtual bool hasPendingEvents() const;
+	virtual int setDelay(int32_t handle, int64_t ns);
+	virtual int enable(int32_t handle, int enabled);
+};
+
+/*****************************************************************************/
+
+#endif  // ANDROID_ACCEL_SENSOR_H
diff --git a/AkmSensor.cpp b/AkmSensor.cpp
new file mode 100644
index 0000000..dd17afc
--- /dev/null
+++ b/AkmSensor.cpp
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *		http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <poll.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/select.h>
+#include <linux/akm8975.h>
+#include <cutils/log.h>
+#include "AkmSensor.h"
+#include "sensors.h"
+
+#define	SENSOR_STATE_MASK	(0x7FFF)
+
+#define AKM_DEVICE_NAME		"/dev/akm8975_aot"
+
+#define	ID_A	SENSORS_ACCELERATION_HANDLE
+#define	ID_M	SENSORS_MAGNETIC_FIELD_HANDLE
+#define ID_O	SENSORS_ORIENTATION_HANDLE
+
+#define EVENT_TYPE_ACCEL_X			REL_X
+#define EVENT_TYPE_ACCEL_Y			REL_Y
+#define EVENT_TYPE_ACCEL_Z			REL_Z
+
+#define EVENT_TYPE_YAW				REL_RX
+#define EVENT_TYPE_PITCH			REL_RY
+#define EVENT_TYPE_ROLL				REL_RZ
+#define EVENT_TYPE_ORIENT_STATUS	REL_HWHEEL
+
+#define EVENT_TYPE_MAGV_X			REL_DIAL
+#define EVENT_TYPE_MAGV_Y			REL_WHEEL
+#define EVENT_TYPE_MAGV_Z			REL_MISC
+
+// 1024 LSG = 1G
+#define LSG							(1024.0f)
+#define MAX_RANGE_A					(2*GRAVITY_EARTH)
+// conversion of acceleration data to SI units (m/s^2)
+#define CONVERT_A					(GRAVITY_EARTH / LSG)
+#define CONVERT_A_X					(CONVERT_A)
+#define CONVERT_A_Y					(CONVERT_A)
+#define CONVERT_A_Z					(CONVERT_A)
+
+// conversion of magnetic data to uT units
+#define CONVERT_M					(1.0f/16.0f)
+#define CONVERT_M_X					(CONVERT_M)
+#define CONVERT_M_Y					(CONVERT_M)
+#define CONVERT_M_Z					(CONVERT_M)
+
+#define CONVERT_O					(1.0f/64.0f)
+#define CONVERT_O_Y					(CONVERT_O)
+#define CONVERT_O_P					(CONVERT_O)
+#define CONVERT_O_R					(-CONVERT_O)
+
+/*****************************************************************************/
+
+AkmSensor::AkmSensor()
+	: SensorBase(AKM_DEVICE_NAME, "compass"),
+	mEnabled(0),
+	mPendingMask(0),
+	mInputReader(32)
+{
+	memset(mPendingEvents, 0, sizeof(mPendingEvents));
+
+	mPendingEvents[Accelerometer].version = sizeof(sensors_event_t);
+	mPendingEvents[Accelerometer].sensor = ID_A;
+	mPendingEvents[Accelerometer].type = SENSOR_TYPE_ACCELEROMETER;
+	mPendingEvents[Accelerometer].acceleration.status = SENSOR_STATUS_ACCURACY_HIGH;
+
+	mPendingEvents[MagneticField].version = sizeof(sensors_event_t);
+	mPendingEvents[MagneticField].sensor = ID_M;
+	mPendingEvents[MagneticField].type = SENSOR_TYPE_MAGNETIC_FIELD;
+	mPendingEvents[MagneticField].magnetic.status = SENSOR_STATUS_ACCURACY_HIGH;
+
+	mPendingEvents[Orientation  ].version = sizeof(sensors_event_t);
+	mPendingEvents[Orientation  ].sensor = ID_O;
+	mPendingEvents[Orientation  ].type = SENSOR_TYPE_ORIENTATION;
+	mPendingEvents[Orientation  ].orientation.status = SENSOR_STATUS_ACCURACY_HIGH;
+
+	for (int i=0 ; i<numSensors ; i++)
+		mDelays[i] = 200000000; // 200 ms by default
+
+	// read the actual value of all sensors if they're enabled already
+	struct input_absinfo absinfo;
+	short flags = 0;
+
+	open_device();
+
+	if (!ioctl(dev_fd, ECS_IOCTL_APP_GET_AFLAG, &flags)) {
+		if (flags)  {
+			mEnabled |= 1<<Accelerometer;
+		}
+	}
+	if (!ioctl(dev_fd, ECS_IOCTL_APP_GET_MVFLAG, &flags)) {
+		if (flags)  {
+			mEnabled |= 1<<MagneticField;
+		}
+	}
+	if (!ioctl(dev_fd, ECS_IOCTL_APP_GET_MFLAG, &flags)) {
+		if (flags)  {
+			mEnabled |= 1<<Orientation;
+		}
+	}
+	if (!mEnabled) {
+		close_device();
+	}
+}
+
+AkmSensor::~AkmSensor() {
+}
+
+int AkmSensor::enable(int32_t handle, int en)
+{
+	int what = -1;
+	switch (handle) {
+		case ID_A: what = Accelerometer; break;
+		case ID_M: what = MagneticField; break;
+		case ID_O: what = Orientation;   break;
+	}
+
+	if (uint32_t(what) >= numSensors)
+		return -EINVAL;
+
+	int newState  = en ? 1 : 0;
+	int err = 0;
+
+	if ((uint32_t(newState)<<what) != (mEnabled & (1<<what))) {
+		if (!mEnabled) {
+			open_device();
+		}
+		int cmd;
+		switch (what) {
+			case Accelerometer: cmd = ECS_IOCTL_APP_SET_AFLAG;  break;
+			case MagneticField: cmd = ECS_IOCTL_APP_SET_MVFLAG; break;
+			case Orientation:   cmd = ECS_IOCTL_APP_SET_MFLAG;  break;
+		}
+		short flags = newState;
+		err = ioctl(dev_fd, cmd, &flags);
+		err = err<0 ? -errno : 0;
+		ALOGE_IF(err, "ECS_IOCTL_APP_SET_XXX failed (%s)", strerror(-err));
+		if (!err) {
+			mEnabled &= ~(1<<what);
+			mEnabled |= (uint32_t(flags)<<what);
+			update_delay();
+		}
+		if (!mEnabled) {
+			close_device();
+		}
+	}
+	return err;
+}
+
+int AkmSensor::setDelay(int32_t handle, int64_t ns)
+{
+#ifdef ECS_IOCTL_APP_SET_DELAY
+	int what = -1;
+	switch (handle) {
+		case ID_A: what = Accelerometer; break;
+		case ID_M: what = MagneticField; break;
+		case ID_O: what = Orientation;   break;
+	}
+
+	if (uint32_t(what) >= numSensors)
+		return -EINVAL;
+
+	if (ns < 0)
+		return -EINVAL;
+
+	mDelays[what] = ns;
+	return update_delay();
+#else
+	return -1;
+#endif
+}
+
+int AkmSensor::update_delay()
+{
+	if (mEnabled) {
+		uint64_t wanted = -1LLU;
+		for (int i=0 ; i<numSensors ; i++) {
+			if (mEnabled & (1<<i)) {
+				uint64_t ns = mDelays[i];
+				wanted = wanted < ns ? wanted : ns;
+			}
+		}
+		short delay = int64_t(wanted) / 1000000;
+		if (ioctl(dev_fd, ECS_IOCTL_APP_SET_DELAY, &delay)) {
+			return -errno;
+		}
+	}
+	return 0;
+}
+
+int AkmSensor::readEvents(sensors_event_t* data, int count)
+{
+	if (count < 1)
+		return -EINVAL;
+
+	ssize_t n = mInputReader.fill(data_fd);
+	if (n < 0)
+		return n;
+
+	int numEventReceived = 0;
+	input_event const* event;
+
+	while (count && mInputReader.readEvent(&event)) {
+		int type = event->type;
+		if (type == EV_REL) {
+			processEvent(event->code, event->value);
+			mInputReader.next();
+		} else if (type == EV_SYN) {
+			int64_t time = timevalToNano(event->time);
+			for (int j=0 ; count && mPendingMask && j<numSensors ; j++) {
+				if (mPendingMask & (1<<j)) {
+					mPendingMask &= ~(1<<j);
+					mPendingEvents[j].timestamp = time;
+					if (mEnabled & (1<<j)) {
+						*data++ = mPendingEvents[j];
+						count--;
+						numEventReceived++;
+					}
+				}
+			}
+			if (!mPendingMask) {
+				mInputReader.next();
+			}
+		} else {
+			ALOGE("AkmSensor: unknown event (type=%d, code=%d)",
+					type, event->code);
+			mInputReader.next();
+		}
+	}
+
+	return numEventReceived;
+}
+
+void AkmSensor::processEvent(int code, int value)
+{
+	switch (code) {
+		case EVENT_TYPE_ACCEL_X:
+			mPendingMask |= 1<<Accelerometer;
+			mPendingEvents[Accelerometer].acceleration.x = value * CONVERT_A_X;
+			break;
+		case EVENT_TYPE_ACCEL_Y:
+			mPendingMask |= 1<<Accelerometer;
+			mPendingEvents[Accelerometer].acceleration.y = value * CONVERT_A_Y;
+			break;
+		case EVENT_TYPE_ACCEL_Z:
+			mPendingMask |= 1<<Accelerometer;
+			mPendingEvents[Accelerometer].acceleration.z = value * CONVERT_A_Z;
+			break;
+
+		case EVENT_TYPE_MAGV_X:
+			mPendingMask |= 1<<MagneticField;
+			mPendingEvents[MagneticField].magnetic.x = value * CONVERT_M_X;
+			break;
+		case EVENT_TYPE_MAGV_Y:
+			mPendingMask |= 1<<MagneticField;
+			mPendingEvents[MagneticField].magnetic.y = value * CONVERT_M_Y;
+			break;
+		case EVENT_TYPE_MAGV_Z:
+			mPendingMask |= 1<<MagneticField;
+			mPendingEvents[MagneticField].magnetic.z = value * CONVERT_M_Z;
+			break;
+
+		case EVENT_TYPE_YAW:
+			mPendingMask |= 1<<Orientation;
+			mPendingEvents[Orientation].orientation.azimuth = value * CONVERT_O_Y;
+			break;
+		case EVENT_TYPE_PITCH:
+			mPendingMask |= 1<<Orientation;
+			mPendingEvents[Orientation].orientation.pitch = value * CONVERT_O_P;
+			break;
+		case EVENT_TYPE_ROLL:
+			mPendingMask |= 1<<Orientation;
+			mPendingEvents[Orientation].orientation.roll = value * CONVERT_O_R;
+			break;
+		case EVENT_TYPE_ORIENT_STATUS:
+			mPendingMask |= 1<<Orientation;
+			mPendingEvents[Orientation].orientation.status =
+					uint8_t(value & SENSOR_STATE_MASK);
+			break;
+	}
+}
diff --git a/AkmSensor.h b/AkmSensor.h
new file mode 100644
index 0000000..8c81ae5
--- /dev/null
+++ b/AkmSensor.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AKM_SENSOR_H
+#define ANDROID_AKM_SENSOR_H
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include "SensorBase.h"
+#include "InputEventReader.h"
+
+/*****************************************************************************/
+
+struct input_event;
+
+class AkmSensor : public SensorBase {
+public:
+			AkmSensor();
+	virtual ~AkmSensor();
+
+	enum {
+		Accelerometer	= 0,
+		MagneticField	= 1,
+		Orientation		= 2,
+		numSensors
+	};
+
+	virtual int setDelay(int32_t handle, int64_t ns);
+	virtual int enable(int32_t handle, int enabled);
+	virtual int readEvents(sensors_event_t* data, int count);
+	void processEvent(int code, int value);
+
+private:
+	int update_delay();
+	uint32_t mEnabled;
+	uint32_t mPendingMask;
+	InputEventCircularReader mInputReader;
+	sensors_event_t mPendingEvents[numSensors];
+	uint64_t mDelays[numSensors];
+};
+
+/*****************************************************************************/
+
+#endif  // ANDROID_AKM_SENSOR_H
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..6a02c72
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,33 @@
+ifneq ($(BUILD_TINY_ANDROID),true)
+LOCAL_PATH := $(call my-dir)
+
+# HAL module implemenation stored in
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := sensors.msm8930
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS := -DLOG_TAG=\"Sensors\"
+ifeq ($(call is-board-platform,msm8960),true)
+  LOCAL_CFLAGS += -DTARGET_8930
+endif
+
+LOCAL_SRC_FILES :=	\
+		sensors.cpp 			\
+		SensorBase.cpp			\
+		LightSensor.cpp			\
+		ProximitySensor.cpp		\
+		AkmSensor.cpp			\
+		Lis3dh.cpp				\
+		Mpu3050.cpp				\
+		Bmp180.cpp				\
+		InputEventReader.cpp
+
+LOCAL_SHARED_LIBRARIES := liblog libcutils libdl
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif #BUILD_TINY_ANDROID
diff --git a/Bmp180.cpp b/Bmp180.cpp
new file mode 100644
index 0000000..f43b6d0
--- /dev/null
+++ b/Bmp180.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *	  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <poll.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/select.h>
+#include <cutils/log.h>
+
+#include "PressureSensor.h"
+#include "sensors.h"
+
+#define FETCH_FULL_EVENT_BEFORE_RETURN 	1
+
+#define	EVENT_TYPE_PRESSURE		ABS_PRESSURE
+
+#define CONVERT_PRESSURE		(0.01)
+
+#define IGNORE_EVENT_TIME		0
+
+/*****************************************************************************/
+
+PressureSensor::PressureSensor()
+	: SensorBase(NULL, "barometer_sensor"),
+	  mEnabled(0),
+	  mInputReader(4),
+	  mHasPendingEvent(false),
+	  mEnabledTime(0)
+{
+	mPendingEvent.version = sizeof(sensors_event_t);
+	mPendingEvent.sensor = SENSORS_PRESSURE_HANDLE;
+	mPendingEvent.type = SENSOR_TYPE_PRESSURE;
+	memset(mPendingEvent.data, 0, sizeof(mPendingEvent.data));
+
+	if (data_fd) {
+		strcpy(input_sysfs_path, "/sys/class/input/");
+		strcat(input_sysfs_path, input_name);
+		strcat(input_sysfs_path, "/device/device/");
+		input_sysfs_path_len = strlen(input_sysfs_path);
+		enable(0, 1);
+	}
+}
+
+PressureSensor::~PressureSensor() {
+	if (mEnabled) {
+		enable(0, 0);
+	}
+}
+
+int PressureSensor::setInitialState() {
+	struct input_absinfo absinfo;
+	float value;
+	if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_PRESSURE), &absinfo)) {
+		value = absinfo.value;
+		mPendingEvent.pressure = value * CONVERT_PRESSURE;
+		mHasPendingEvent = true;
+	}
+	return 0;
+}
+
+int PressureSensor::enable(int32_t, int en) {
+	int flags = en ? 1 : 0;
+	if (flags != mEnabled) {
+		int fd;
+		strcpy(&input_sysfs_path[input_sysfs_path_len], "enable");
+		fd = open(input_sysfs_path, O_RDWR);
+		if (fd >= 0) {
+			char buf[2];
+			int err;
+			buf[1] = 0;
+			if (flags) {
+				buf[0] = '1';
+				mEnabledTime = getTimestamp() + IGNORE_EVENT_TIME;
+			} else {
+				buf[0] = '0';
+			}
+			err = write(fd, buf, sizeof(buf));
+			close(fd);
+			mEnabled = flags;
+			setInitialState();
+			return 0;
+		}
+		return -1;
+	}
+	return 0;
+}
+
+bool PressureSensor::hasPendingEvents() const {
+	return mHasPendingEvent;
+}
+
+int PressureSensor::setDelay(int32_t handle, int64_t delay_ns)
+{
+	int fd;
+	strcpy(&input_sysfs_path[input_sysfs_path_len], "poll_delay");
+	fd = open(input_sysfs_path, O_RDWR);
+	if (fd >= 0) {
+		char buf[80];
+		sprintf(buf, "%lld", delay_ns);
+		write(fd, buf, strlen(buf)+1);
+		close(fd);
+		return 0;
+	}
+	return -1;
+}
+
+int PressureSensor::readEvents(sensors_event_t* data, int count)
+{
+	if (count < 1)
+		return -EINVAL;
+
+	if (mHasPendingEvent) {
+		mHasPendingEvent = false;
+		mPendingEvent.timestamp = getTimestamp();
+		*data = mPendingEvent;
+		return mEnabled ? 1 : 0;
+	}
+
+	ssize_t n = mInputReader.fill(data_fd);
+	if (n < 0)
+		return n;
+
+	int numEventReceived = 0;
+	input_event const* event;
+
+#if FETCH_FULL_EVENT_BEFORE_RETURN
+again:
+#endif
+	while (count && mInputReader.readEvent(&event)) {
+		int type = event->type;
+		if (type == EV_ABS) {
+			float value = event->value;
+			mPendingEvent.pressure = value * CONVERT_PRESSURE;
+		} else if (type == EV_SYN) {
+			mPendingEvent.timestamp = timevalToNano(event->time);
+			if (mEnabled) {
+				if (mPendingEvent.timestamp >= mEnabledTime) {
+					*data++ = mPendingEvent;
+					numEventReceived++;
+				}
+				count--;
+			}
+		} else {
+			ALOGE("PressureSensor: unknown event (type=%d, code=%d)",
+					type, event->code);
+		}
+		mInputReader.next();
+	}
+
+#if FETCH_FULL_EVENT_BEFORE_RETURN
+	/* if we didn't read a complete event, see if we can fill and
+	   try again instead of returning with nothing and redoing poll. */
+	if (numEventReceived == 0 && mEnabled == 1) {
+		n = mInputReader.fill(data_fd);
+		if (n)
+			goto again;
+	}
+#endif
+
+	return numEventReceived;
+}
+
diff --git a/GyroSensor.h b/GyroSensor.h
new file mode 100644
index 0000000..cf398fd
--- /dev/null
+++ b/GyroSensor.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *		http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GYRO_SENSOR_H
+#define ANDROID_GYRO_SENSOR_H
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include "SensorBase.h"
+#include "InputEventReader.h"
+
+/*****************************************************************************/
+
+struct input_event;
+
+class GyroSensor : public SensorBase {
+	int mEnabled;
+	InputEventCircularReader mInputReader;
+	sensors_event_t mPendingEvent;
+	bool mHasPendingEvent;
+	char input_sysfs_path[PATH_MAX];
+	int input_sysfs_path_len;
+	int64_t mEnabledTime;
+
+	int setInitialState();
+
+public:
+			GyroSensor();
+	virtual ~GyroSensor();
+	virtual int readEvents(sensors_event_t* data, int count);
+	virtual bool hasPendingEvents() const;
+	virtual int setDelay(int32_t handle, int64_t ns);
+	virtual int enable(int32_t handle, int enabled);
+};
+
+/*****************************************************************************/
+
+#endif  // ANDROID_GYRO_SENSOR_H
diff --git a/InputEventReader.cpp b/InputEventReader.cpp
new file mode 100644
index 0000000..1014f29
--- /dev/null
+++ b/InputEventReader.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <errno.h>
+#include <unistd.h>
+#include <poll.h>
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <linux/input.h>
+
+#include <cutils/log.h>
+
+#include "InputEventReader.h"
+
+/*****************************************************************************/
+
+struct input_event;
+
+InputEventCircularReader::InputEventCircularReader(size_t numEvents)
+    : mBuffer(new input_event[numEvents * 2]),
+      mBufferEnd(mBuffer + numEvents),
+      mHead(mBuffer),
+      mCurr(mBuffer),
+      mFreeSpace(numEvents)
+{
+}
+
+InputEventCircularReader::~InputEventCircularReader()
+{
+    delete [] mBuffer;
+}
+
+ssize_t InputEventCircularReader::fill(int fd)
+{
+    size_t numEventsRead = 0;
+    if (mFreeSpace) {
+        const ssize_t nread = read(fd, mHead, mFreeSpace * sizeof(input_event));
+        if (nread<0 || nread % sizeof(input_event)) {
+            // we got a partial event!!
+            return nread<0 ? -errno : -EINVAL;
+        }
+
+        numEventsRead = nread / sizeof(input_event);
+        if (numEventsRead) {
+            mHead += numEventsRead;
+            mFreeSpace -= numEventsRead;
+            if (mHead > mBufferEnd) {
+                size_t s = mHead - mBufferEnd;
+                memcpy(mBuffer, mBufferEnd, s * sizeof(input_event));
+                mHead = mBuffer + s;
+            }
+        }
+    }
+
+    return numEventsRead;
+}
+
+ssize_t InputEventCircularReader::readEvent(input_event const** events)
+{
+    *events = mCurr;
+    ssize_t available = (mBufferEnd - mBuffer) - mFreeSpace;
+    return available ? 1 : 0;
+}
+
+void InputEventCircularReader::next()
+{
+    mCurr++;
+    mFreeSpace++;
+    if (mCurr >= mBufferEnd) {
+        mCurr = mBuffer;
+    }
+}
diff --git a/InputEventReader.h b/InputEventReader.h
new file mode 100644
index 0000000..254c00e
--- /dev/null
+++ b/InputEventReader.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *		http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_INPUT_EVENT_READER_H
+#define ANDROID_INPUT_EVENT_READER_H
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+/*****************************************************************************/
+
+struct input_event;
+
+class InputEventCircularReader
+{
+	struct input_event* const mBuffer;
+	struct input_event* const mBufferEnd;
+	struct input_event* mHead;
+	struct input_event* mCurr;
+	ssize_t mFreeSpace;
+
+public:
+	InputEventCircularReader(size_t numEvents);
+	~InputEventCircularReader();
+	ssize_t fill(int fd);
+	ssize_t readEvent(input_event const** events);
+	void next();
+};
+
+/*****************************************************************************/
+
+#endif  // ANDROID_INPUT_EVENT_READER_H
diff --git a/LightSensor.cpp b/LightSensor.cpp
new file mode 100644
index 0000000..a97e3fd
--- /dev/null
+++ b/LightSensor.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <poll.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/select.h>
+#include <cutils/log.h>
+
+#include "sensors.h"
+#include "LightSensor.h"
+
+#define EVENT_TYPE_LIGHT		ABS_MISC
+/*****************************************************************************/
+
+LightSensor::LightSensor()
+	: SensorBase(NULL, "lightsensor-level"),
+	  mEnabled(0),
+	  mInputReader(4),
+	  mHasPendingEvent(false)
+{
+	mPendingEvent.version = sizeof(sensors_event_t);
+	mPendingEvent.sensor = SENSORS_LIGHT_HANDLE;
+	mPendingEvent.type = SENSOR_TYPE_LIGHT;
+	memset(mPendingEvent.data, 0, sizeof(mPendingEvent.data));
+
+	if (data_fd) {
+		strcpy(input_sysfs_path, "/sys/class/input/");
+		strcat(input_sysfs_path, input_name);
+		strcat(input_sysfs_path, "/device/");
+		input_sysfs_path_len = strlen(input_sysfs_path);
+		enable(0, 1);
+	}
+}
+
+LightSensor::~LightSensor() {
+	if (mEnabled) {
+		enable(0, 0);
+	}
+}
+
+int LightSensor::setDelay(int32_t handle, int64_t ns)
+{
+	int fd;
+	strcpy(&input_sysfs_path[input_sysfs_path_len], "poll_delay");
+	fd = open(input_sysfs_path, O_RDWR);
+	if (fd >= 0) {
+		char buf[80];
+		sprintf(buf, "%lld", ns);
+		write(fd, buf, strlen(buf)+1);
+		close(fd);
+		return 0;
+	}
+	return -1;
+}
+
+int LightSensor::enable(int32_t handle, int en)
+{
+	int flags = en ? 1 : 0;
+	if (flags != mEnabled) {
+		int fd;
+		strcpy(&input_sysfs_path[input_sysfs_path_len], "enable");
+		fd = open(input_sysfs_path, O_RDWR);
+		if (fd >= 0) {
+			char buf[2];
+			int err;
+			buf[1] = 0;
+			if (flags) {
+				buf[0] = '1';
+			} else {
+				buf[0] = '0';
+			}
+			err = write(fd, buf, sizeof(buf));
+			close(fd);
+			mEnabled = flags;
+			return 0;
+		}
+		return -1;
+	}
+	return 0;
+}
+
+bool LightSensor::hasPendingEvents() const {
+	return mHasPendingEvent;
+}
+
+int LightSensor::readEvents(sensors_event_t* data, int count)
+{
+	if (count < 1)
+		return -EINVAL;
+
+	if (mHasPendingEvent) {
+		mHasPendingEvent = false;
+		mPendingEvent.timestamp = getTimestamp();
+		*data = mPendingEvent;
+		return mEnabled ? 1 : 0;
+	}
+
+	ssize_t n = mInputReader.fill(data_fd);
+	if (n < 0)
+		return n;
+
+	int numEventReceived = 0;
+	input_event const* event;
+
+	while (count && mInputReader.readEvent(&event)) {
+		int type = event->type;
+		if (type == EV_ABS) {
+			if (event->code == EVENT_TYPE_LIGHT) {
+				// Convert adc value to lux assuming:
+				// I = 10 * log(Ev) uA
+				// R = 47kOhm
+				// Max adc value 4095 = 3.3V
+				// 1/4 of light reaches sensor
+				mPendingEvent.light = powf(10, event->value * (330.0f / 4095.0f / 47.0f)) * 4;
+			}
+		} else if (type == EV_SYN) {
+			mPendingEvent.timestamp = timevalToNano(event->time);
+			if (mEnabled) {
+				*data++ = mPendingEvent;
+				count--;
+				numEventReceived++;
+			}
+		} else {
+			ALOGE("LightSensor: unknown event (type=%d, code=%d)",
+					type, event->code);
+		}
+		mInputReader.next();
+	}
+
+	return numEventReceived;
+}
diff --git a/LightSensor.h b/LightSensor.h
new file mode 100644
index 0000000..c2a55c9
--- /dev/null
+++ b/LightSensor.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *		http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_LIGHT_SENSOR_H
+#define ANDROID_LIGHT_SENSOR_H
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include "SensorBase.h"
+#include "InputEventReader.h"
+
+/*****************************************************************************/
+
+struct input_event;
+
+class LightSensor : public SensorBase {
+	int mEnabled;
+	InputEventCircularReader mInputReader;
+	sensors_event_t mPendingEvent;
+	bool mHasPendingEvent;
+	char input_sysfs_path[PATH_MAX];
+	int input_sysfs_path_len;
+
+	int setInitialState();
+
+public:
+			LightSensor();
+	virtual ~LightSensor();
+	virtual int readEvents(sensors_event_t* data, int count);
+	virtual bool hasPendingEvents() const;
+	virtual int setDelay(int32_t handle, int64_t ns);
+	virtual int enable(int32_t handle, int enabled);
+};
+
+/*****************************************************************************/
+
+#endif  // ANDROID_LIGHT_SENSOR_H
diff --git a/Lis3dh.cpp b/Lis3dh.cpp
new file mode 100644
index 0000000..b8e2590
--- /dev/null
+++ b/Lis3dh.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *	  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <poll.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/select.h>
+#include <cutils/log.h>
+
+#include "AccelSensor.h"
+#include "sensors.h"
+
+#define FETCH_FULL_EVENT_BEFORE_RETURN	1
+#define IGNORE_EVENT_TIME				10000000
+
+#define	EVENT_TYPE_ACCEL_X	ABS_X
+#define	EVENT_TYPE_ACCEL_Y	ABS_Y
+#define	EVENT_TYPE_ACCEL_Z	ABS_Z
+
+#define LIS3DH_CONVERT		((GRAVITY_EARTH) / 1024)
+#define CONVERT_ACCEL_X		LIS3DH_CONVERT
+#define CONVERT_ACCEL_Y		LIS3DH_CONVERT
+#define CONVERT_ACCEL_Z		LIS3DH_CONVERT
+
+/*****************************************************************************/
+
+AccelSensor::AccelSensor()
+	: SensorBase(NULL, "lis3dh_acc"),
+	  mEnabled(0),
+	  mInputReader(4),
+	  mHasPendingEvent(false),
+	  mEnabledTime(0)
+{
+	mPendingEvent.version = sizeof(sensors_event_t);
+	mPendingEvent.sensor = SENSORS_ACCELERATION_HANDLE;
+	mPendingEvent.type = SENSOR_TYPE_ACCELEROMETER;
+	memset(mPendingEvent.data, 0, sizeof(mPendingEvent.data));
+
+	if (data_fd) {
+		strcpy(input_sysfs_path, "/sys/class/input/");
+		strcat(input_sysfs_path, input_name);
+		strcat(input_sysfs_path, "/device/device/");
+		input_sysfs_path_len = strlen(input_sysfs_path);
+		enable(0, 1);
+	}
+}
+
+AccelSensor::~AccelSensor() {
+	if (mEnabled) {
+		enable(0, 0);
+	}
+}
+
+int AccelSensor::setInitialState() {
+	struct input_absinfo absinfo_x;
+	struct input_absinfo absinfo_y;
+	struct input_absinfo absinfo_z;
+	float value;
+	if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_ACCEL_X), &absinfo_x) &&
+		!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_ACCEL_Y), &absinfo_y) &&
+		!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_ACCEL_Z), &absinfo_z)) {
+		value = absinfo_x.value;
+		mPendingEvent.data[0] = value * CONVERT_ACCEL_X;
+		value = absinfo_y.value;
+		mPendingEvent.data[1] = value * CONVERT_ACCEL_Y;
+		value = absinfo_z.value;
+		mPendingEvent.data[2] = value * CONVERT_ACCEL_Z;
+		mHasPendingEvent = true;
+	}
+	return 0;
+}
+
+int AccelSensor::enable(int32_t, int en) {
+	int flags = en ? 1 : 0;
+	if (flags != mEnabled) {
+#if 1
+		int fd;
+		strcpy(&input_sysfs_path[input_sysfs_path_len], "enable");
+		fd = open(input_sysfs_path, O_RDWR);
+		if (fd >= 0) {
+			char buf[2];
+			int err;
+			buf[1] = 0;
+			if (flags) {
+				buf[0] = '1';
+				mEnabledTime = getTimestamp() + IGNORE_EVENT_TIME;
+			} else {
+				buf[0] = '0';
+			}
+			err = write(fd, buf, sizeof(buf));
+			close(fd);
+			mEnabled = flags;
+			setInitialState();
+			return 0;
+		}
+		ALOGE("lis3dh: failed to open %s", input_sysfs_path);
+		return -1;
+#else
+		mEnabled = flags;
+		setInitialState();
+#endif
+	}
+	return 0;
+}
+
+bool AccelSensor::hasPendingEvents() const {
+	return mHasPendingEvent;
+}
+
+int AccelSensor::setDelay(int32_t handle, int64_t delay_ns)
+{
+	int fd;
+	int delay_ms = delay_ns / 1000000;
+	strcpy(&input_sysfs_path[input_sysfs_path_len], "pollrate_ms");
+	fd = open(input_sysfs_path, O_RDWR);
+	if (fd >= 0) {
+		char buf[80];
+		sprintf(buf, "%d", delay_ms);
+		write(fd, buf, strlen(buf)+1);
+		close(fd);
+		return 0;
+	}
+	return -1;
+}
+
+int AccelSensor::readEvents(sensors_event_t* data, int count)
+{
+	if (count < 1)
+		return -EINVAL;
+
+	if (mHasPendingEvent) {
+		mHasPendingEvent = false;
+		mPendingEvent.timestamp = getTimestamp();
+		*data = mPendingEvent;
+		return mEnabled ? 1 : 0;
+	}
+
+	ssize_t n = mInputReader.fill(data_fd);
+	if (n < 0)
+		return n;
+
+	int numEventReceived = 0;
+	input_event const* event;
+
+#if FETCH_FULL_EVENT_BEFORE_RETURN
+again:
+#endif
+	while (count && mInputReader.readEvent(&event)) {
+		int type = event->type;
+		if (type == EV_ABS) {
+			float value = event->value;
+			if (event->code == EVENT_TYPE_ACCEL_X) {
+				mPendingEvent.data[0] = value * CONVERT_ACCEL_X;
+			} else if (event->code == EVENT_TYPE_ACCEL_Y) {
+				mPendingEvent.data[1] = value * CONVERT_ACCEL_Y;
+			} else if (event->code == EVENT_TYPE_ACCEL_Z) {
+				mPendingEvent.data[2] = value * CONVERT_ACCEL_Z;
+			}
+		} else if (type == EV_SYN) {
+			mPendingEvent.timestamp = timevalToNano(event->time);
+			if (mEnabled) {
+				if (mPendingEvent.timestamp >= mEnabledTime) {
+					*data++ = mPendingEvent;
+					numEventReceived++;
+				}
+				count--;
+			}
+		} else {
+			ALOGE("AccelSensor: unknown event (type=%d, code=%d)",
+					type, event->code);
+		}
+		mInputReader.next();
+	}
+
+#if FETCH_FULL_EVENT_BEFORE_RETURN
+	/* if we didn't read a complete event, see if we can fill and
+	   try again instead of returning with nothing and redoing poll. */
+	if (numEventReceived == 0 && mEnabled == 1) {
+		n = mInputReader.fill(data_fd);
+		if (n)
+			goto again;
+	}
+#endif
+
+	return numEventReceived;
+}
+
diff --git a/Mpu3050.cpp b/Mpu3050.cpp
new file mode 100644
index 0000000..a9c5b14
--- /dev/null
+++ b/Mpu3050.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *	  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <poll.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/select.h>
+#include <cutils/log.h>
+
+#include "GyroSensor.h"
+#include "sensors.h"
+
+#define FETCH_FULL_EVENT_BEFORE_RETURN 	1
+#define IGNORE_EVENT_TIME 				350000000
+
+#define	EVENT_TYPE_GYRO_X	ABS_X
+#define	EVENT_TYPE_GYRO_Y	ABS_Y
+#define	EVENT_TYPE_GYRO_Z	ABS_Z
+
+#define MPU3050_CONVERT		(M_PI / (180 * 16.4))
+#define CONVERT_GYRO_X		(-MPU3050_CONVERT)
+#define CONVERT_GYRO_Y		( MPU3050_CONVERT)
+#define CONVERT_GYRO_Z		(-MPU3050_CONVERT)
+
+/*****************************************************************************/
+
+GyroSensor::GyroSensor()
+	: SensorBase(NULL, "MPU3050"),
+	  mEnabled(0),
+	  mInputReader(4),
+	  mHasPendingEvent(false),
+	  mEnabledTime(0)
+{
+	mPendingEvent.version = sizeof(sensors_event_t);
+	mPendingEvent.sensor = SENSORS_GYROSCOPE_HANDLE;
+	mPendingEvent.type = SENSOR_TYPE_GYROSCOPE;
+	memset(mPendingEvent.data, 0, sizeof(mPendingEvent.data));
+
+	if (data_fd) {
+		strcpy(input_sysfs_path, "/sys/class/input/");
+		strcat(input_sysfs_path, input_name);
+		strcat(input_sysfs_path, "/device/device/");
+		input_sysfs_path_len = strlen(input_sysfs_path);
+		enable(0, 1);
+	}
+}
+
+GyroSensor::~GyroSensor() {
+	if (mEnabled) {
+		enable(0, 0);
+	}
+}
+
+int GyroSensor::setInitialState() {
+	struct input_absinfo absinfo_x;
+	struct input_absinfo absinfo_y;
+	struct input_absinfo absinfo_z;
+	float value;
+	if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_GYRO_X), &absinfo_x) &&
+		!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_GYRO_Y), &absinfo_y) &&
+		!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_GYRO_Z), &absinfo_z)) {
+		value = absinfo_x.value;
+		mPendingEvent.data[0] = value * CONVERT_GYRO_X;
+		value = absinfo_y.value;
+		mPendingEvent.data[1] = value * CONVERT_GYRO_Y;
+		value = absinfo_z.value;
+		mPendingEvent.data[2] = value * CONVERT_GYRO_Z;
+		mHasPendingEvent = true;
+	}
+	return 0;
+}
+
+int GyroSensor::enable(int32_t, int en) {
+	int flags = en ? 1 : 0;
+	if (flags != mEnabled) {
+#if 0
+		int fd;
+		strcpy(&input_sysfs_path[input_sysfs_path_len], "enable");
+		fd = open(input_sysfs_path, O_RDWR);
+		if (fd >= 0) {
+			char buf[2];
+			int err;
+			buf[1] = 0;
+			if (flags) {
+				buf[0] = '1';
+				mEnabledTime = getTimestamp() + IGNORE_EVENT_TIME;
+			} else {
+				buf[0] = '0';
+			}
+			err = write(fd, buf, sizeof(buf));
+			close(fd);
+			mEnabled = flags;
+			setInitialState();
+			return 0;
+		}
+		return -1;
+#else
+		mEnabled = flags;
+		setInitialState();
+#endif
+	}
+	return 0;
+}
+
+bool GyroSensor::hasPendingEvents() const {
+	return mHasPendingEvent;
+}
+
+int GyroSensor::setDelay(int32_t handle, int64_t delay_ns)
+{
+	int fd;
+	int delay_ms = delay_ns / 1000000;
+	strcpy(&input_sysfs_path[input_sysfs_path_len], "pollrate_ms");
+	fd = open(input_sysfs_path, O_RDWR);
+	if (fd >= 0) {
+		char buf[80];
+		sprintf(buf, "%d", delay_ms);
+		write(fd, buf, strlen(buf)+1);
+		close(fd);
+		return 0;
+	}
+	return -1;
+}
+
+int GyroSensor::readEvents(sensors_event_t* data, int count)
+{
+	if (count < 1)
+		return -EINVAL;
+
+	if (mHasPendingEvent) {
+		mHasPendingEvent = false;
+		mPendingEvent.timestamp = getTimestamp();
+		*data = mPendingEvent;
+		return mEnabled ? 1 : 0;
+	}
+
+	ssize_t n = mInputReader.fill(data_fd);
+	if (n < 0)
+		return n;
+
+	int numEventReceived = 0;
+	input_event const* event;
+
+#if FETCH_FULL_EVENT_BEFORE_RETURN
+again:
+#endif
+	while (count && mInputReader.readEvent(&event)) {
+		int type = event->type;
+		if (type == EV_ABS) {
+			float value = event->value;
+			if (event->code == EVENT_TYPE_GYRO_X) {
+				mPendingEvent.data[0] = value * CONVERT_GYRO_X;
+			} else if (event->code == EVENT_TYPE_GYRO_Y) {
+				mPendingEvent.data[1] = value * CONVERT_GYRO_Y;
+			} else if (event->code == EVENT_TYPE_GYRO_Z) {
+				mPendingEvent.data[2] = value * CONVERT_GYRO_Z;
+			}
+		} else if (type == EV_SYN) {
+			mPendingEvent.timestamp = timevalToNano(event->time);
+			if (mEnabled) {
+				if (mPendingEvent.timestamp >= mEnabledTime) {
+					*data++ = mPendingEvent;
+					numEventReceived++;
+				}
+				count--;
+			}
+		} else {
+			ALOGE("GyroSensor: unknown event (type=%d, code=%d)",
+					type, event->code);
+		}
+		mInputReader.next();
+	}
+
+#if FETCH_FULL_EVENT_BEFORE_RETURN
+	/* if we didn't read a complete event, see if we can fill and
+	   try again instead of returning with nothing and redoing poll. */
+	if (numEventReceived == 0 && mEnabled == 1) {
+		n = mInputReader.fill(data_fd);
+		if (n)
+			goto again;
+	}
+#endif
+
+	return numEventReceived;
+}
+
diff --git a/PressureSensor.h b/PressureSensor.h
new file mode 100644
index 0000000..11b15d7
--- /dev/null
+++ b/PressureSensor.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *		http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_PRESSURE_SENSOR_H
+#define ANDROID_PRESSURE_SENSOR_H
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include "SensorBase.h"
+#include "InputEventReader.h"
+
+/*****************************************************************************/
+
+struct input_event;
+
+class PressureSensor : public SensorBase {
+	int mEnabled;
+	InputEventCircularReader mInputReader;
+	sensors_event_t mPendingEvent;
+	bool mHasPendingEvent;
+	char input_sysfs_path[PATH_MAX];
+	int input_sysfs_path_len;
+	int64_t mEnabledTime;
+
+	int setInitialState();
+
+public:
+	PressureSensor();
+	virtual ~PressureSensor();
+	virtual int readEvents(sensors_event_t* data, int count);
+	virtual bool hasPendingEvents() const;
+	virtual int setDelay(int32_t handle, int64_t ns);
+	virtual int enable(int32_t handle, int enabled);
+};
+
+/*****************************************************************************/
+
+#endif  // ANDROID_PRESSURE_SENSOR_H
diff --git a/ProximitySensor.cpp b/ProximitySensor.cpp
new file mode 100644
index 0000000..fbd4bb4
--- /dev/null
+++ b/ProximitySensor.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <poll.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/select.h>
+
+#include <cutils/log.h>
+
+#include "ProximitySensor.h"
+#include "sensors.h"
+
+#define EVENT_TYPE_PROXIMITY		ABS_DISTANCE
+
+#define PROXIMITY_THRESHOLD			5.0f
+/*****************************************************************************/
+
+ProximitySensor::ProximitySensor()
+    : SensorBase(NULL, "proximity"),
+      mEnabled(0),
+      mInputReader(4),
+      mHasPendingEvent(false)
+{
+    mPendingEvent.version = sizeof(sensors_event_t);
+    mPendingEvent.sensor = SENSORS_PROXIMITY_HANDLE;
+    mPendingEvent.type = SENSOR_TYPE_PROXIMITY;
+    memset(mPendingEvent.data, 0, sizeof(mPendingEvent.data));
+
+    if (data_fd) {
+        strcpy(input_sysfs_path, "/sys/class/input/");
+        strcat(input_sysfs_path, input_name);
+        strcat(input_sysfs_path, "/device/");
+        input_sysfs_path_len = strlen(input_sysfs_path);
+        enable(0, 1);
+    }
+}
+
+ProximitySensor::~ProximitySensor() {
+    if (mEnabled) {
+        enable(0, 0);
+    }
+}
+
+int ProximitySensor::setInitialState() {
+    struct input_absinfo absinfo;
+    if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_PROXIMITY), &absinfo)) {
+        // make sure to report an event immediately
+        mHasPendingEvent = true;
+        mPendingEvent.distance = indexToValue(absinfo.value);
+    }
+    return 0;
+}
+
+int ProximitySensor::enable(int32_t, int en) {
+    int flags = en ? 1 : 0;
+    if (flags != mEnabled) {
+        int fd;
+        strcpy(&input_sysfs_path[input_sysfs_path_len], "enable");
+        fd = open(input_sysfs_path, O_RDWR);
+        if (fd >= 0) {
+            char buf[2];
+            buf[1] = 0;
+            if (flags) {
+                buf[0] = '1';
+            } else {
+                buf[0] = '0';
+            }
+            write(fd, buf, sizeof(buf));
+            close(fd);
+            mEnabled = flags;
+            setInitialState();
+            return 0;
+        }
+        return -1;
+    }
+    return 0;
+}
+
+bool ProximitySensor::hasPendingEvents() const {
+    return mHasPendingEvent;
+}
+
+int ProximitySensor::readEvents(sensors_event_t* data, int count)
+{
+    if (count < 1)
+        return -EINVAL;
+
+    if (mHasPendingEvent) {
+        mHasPendingEvent = false;
+        mPendingEvent.timestamp = getTimestamp();
+        *data = mPendingEvent;
+        return mEnabled ? 1 : 0;
+    }
+
+    ssize_t n = mInputReader.fill(data_fd);
+    if (n < 0)
+        return n;
+
+    int numEventReceived = 0;
+    input_event const* event;
+
+    while (count && mInputReader.readEvent(&event)) {
+        int type = event->type;
+        if (type == EV_ABS) {
+            if (event->code == EVENT_TYPE_PROXIMITY) {
+                if (event->value != -1) {
+                    // FIXME: not sure why we're getting -1 sometimes
+                    mPendingEvent.distance = indexToValue(event->value);
+                }
+            }
+        } else if (type == EV_SYN) {
+            mPendingEvent.timestamp = timevalToNano(event->time);
+            if (mEnabled) {
+                *data++ = mPendingEvent;
+                count--;
+                numEventReceived++;
+            }
+        } else {
+            ALOGE("ProximitySensor: unknown event (type=%d, code=%d)",
+                    type, event->code);
+        }
+        mInputReader.next();
+    }
+
+    return numEventReceived;
+}
+
+float ProximitySensor::indexToValue(size_t index) const
+{
+    return index * PROXIMITY_THRESHOLD;
+}
diff --git a/ProximitySensor.h b/ProximitySensor.h
new file mode 100644
index 0000000..ff1cd46
--- /dev/null
+++ b/ProximitySensor.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_PROXIMITY_SENSOR_H
+#define ANDROID_PROXIMITY_SENSOR_H
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include "SensorBase.h"
+#include "InputEventReader.h"
+
+/*****************************************************************************/
+
+struct input_event;
+
+class ProximitySensor : public SensorBase {
+    int mEnabled;
+    InputEventCircularReader mInputReader;
+    sensors_event_t mPendingEvent;
+    bool mHasPendingEvent;
+    char input_sysfs_path[PATH_MAX];
+    int input_sysfs_path_len;
+
+    int setInitialState();
+    float indexToValue(size_t index) const;
+
+public:
+            ProximitySensor();
+    virtual ~ProximitySensor();
+    virtual int readEvents(sensors_event_t* data, int count);
+    virtual bool hasPendingEvents() const;
+    virtual int enable(int32_t handle, int enabled);
+};
+
+/*****************************************************************************/
+
+#endif  // ANDROID_PROXIMITY_SENSOR_H
diff --git a/SensorBase.cpp b/SensorBase.cpp
new file mode 100644
index 0000000..79b1ee2
--- /dev/null
+++ b/SensorBase.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <errno.h>
+#include <math.h>
+#include <poll.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/select.h>
+
+#include <cutils/log.h>
+
+#include <linux/input.h>
+
+#include "SensorBase.h"
+
+/*****************************************************************************/
+
+SensorBase::SensorBase(
+        const char* dev_name,
+        const char* data_name)
+    : dev_name(dev_name), data_name(data_name),
+      dev_fd(-1), data_fd(-1)
+{
+    if (data_name) {
+        data_fd = openInput(data_name);
+    }
+}
+
+SensorBase::~SensorBase() {
+    if (data_fd >= 0) {
+        close(data_fd);
+    }
+    if (dev_fd >= 0) {
+        close(dev_fd);
+    }
+}
+
+int SensorBase::open_device() {
+    if (dev_fd<0 && dev_name) {
+        dev_fd = open(dev_name, O_RDONLY);
+        ALOGE_IF(dev_fd<0, "Couldn't open %s (%s)", dev_name, strerror(errno));
+    }
+    return 0;
+}
+
+int SensorBase::close_device() {
+    if (dev_fd >= 0) {
+        close(dev_fd);
+        dev_fd = -1;
+    }
+    return 0;
+}
+
+int SensorBase::getFd() const {
+    if (!data_name) {
+        return dev_fd;
+    }
+    return data_fd;
+}
+
+int SensorBase::setDelay(int32_t handle, int64_t ns) {
+    return 0;
+}
+
+bool SensorBase::hasPendingEvents() const {
+    return false;
+}
+
+int64_t SensorBase::getTimestamp() {
+    struct timespec t;
+    t.tv_sec = t.tv_nsec = 0;
+    clock_gettime(CLOCK_MONOTONIC, &t);
+    return int64_t(t.tv_sec)*1000000000LL + t.tv_nsec;
+}
+
+int SensorBase::openInput(const char* inputName) {
+    int fd = -1;
+    const char *dirname = "/dev/input";
+    char devname[PATH_MAX];
+    char *filename;
+    DIR *dir;
+    struct dirent *de;
+    dir = opendir(dirname);
+    if(dir == NULL)
+        return -1;
+    strcpy(devname, dirname);
+    filename = devname + strlen(devname);
+    *filename++ = '/';
+    while((de = readdir(dir))) {
+        if(de->d_name[0] == '.' &&
+                (de->d_name[1] == '\0' ||
+                        (de->d_name[1] == '.' && de->d_name[2] == '\0')))
+            continue;
+        strcpy(filename, de->d_name);
+        fd = open(devname, O_RDONLY);
+        if (fd>=0) {
+            char name[80];
+            if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
+                name[0] = '\0';
+            }
+            if (!strcmp(name, inputName)) {
+                strcpy(input_name, filename);
+                break;
+            } else {
+                close(fd);
+                fd = -1;
+            }
+        }
+    }
+    closedir(dir);
+    ALOGE_IF(fd<0, "couldn't find '%s' input device", inputName);
+    return fd;
+}
diff --git a/SensorBase.h b/SensorBase.h
new file mode 100644
index 0000000..e7b69c8
--- /dev/null
+++ b/SensorBase.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SENSOR_BASE_H
+#define ANDROID_SENSOR_BASE_H
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <linux/input.h>
+
+#include <hardware/hardware.h>
+#include <hardware/sensors.h>
+
+/*****************************************************************************/
+
+struct sensors_event_t;
+
+class SensorBase {
+protected:
+	const char* dev_name;
+	const char* data_name;
+	char		input_name[PATH_MAX];
+	int		 dev_fd;
+	int		 data_fd;
+
+	int openInput(const char* inputName);
+	static int64_t getTimestamp();
+
+
+	static int64_t timevalToNano(timeval const& t) {
+		return t.tv_sec*1000000000LL + t.tv_usec*1000;
+	}
+
+	int open_device();
+	int close_device();
+
+public:
+			SensorBase(
+					const char* dev_name,
+					const char* data_name);
+
+	virtual ~SensorBase();
+
+	virtual int readEvents(sensors_event_t* data, int count) = 0;
+	virtual bool hasPendingEvents() const;
+	virtual int getFd() const;
+	virtual int setDelay(int32_t handle, int64_t ns);
+	virtual int enable(int32_t handle, int enabled) = 0;
+};
+
+/*****************************************************************************/
+
+#endif  // ANDROID_SENSOR_BASE_H
diff --git a/sensors.cpp b/sensors.cpp
new file mode 100644
index 0000000..0cc5447
--- /dev/null
+++ b/sensors.cpp
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Sensors"
+
+#include <hardware/sensors.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <dirent.h>
+#include <math.h>
+#include <poll.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <linux/input.h>
+#include <utils/Atomic.h>
+#include <utils/Log.h>
+
+#include "sensors.h"
+#include "AccelSensor.h"
+#include "LightSensor.h"
+#include "ProximitySensor.h"
+#include "AkmSensor.h"
+#include "GyroSensor.h"
+#include "PressureSensor.h"
+
+/*****************************************************************************/
+
+/* The SENSORS Module */
+static const struct sensor_t sSensorList[] = {
+	/* Accelerometer */
+	{
+		"lis3dh_acc",
+		"ST Micro",
+		1,	/* hw/sw version */
+		SENSORS_ACCELERATION_HANDLE,
+		SENSOR_TYPE_ACCELEROMETER,
+		(2.0f * 9.81f),
+		(9.81f / 1024),
+		0.2f,		/* mA */
+		2000,	/* microseconds */
+		{ }
+	},
+
+	/* magnetic field sensor */
+	{
+		"AK8975",
+		"Asahi Kasei Microdevices",
+		1,
+		SENSORS_MAGNETIC_FIELD_HANDLE,
+		SENSOR_TYPE_MAGNETIC_FIELD,
+		2000.0f,
+		(1.0f/16.0f),
+		6.8f,
+		16667,
+		{ }
+	},
+
+	/* orientation sensor */
+	{
+		"AK8975",
+		"Asahi Kasei Microdevices",
+		1,
+		SENSORS_ORIENTATION_HANDLE,
+		SENSOR_TYPE_ORIENTATION,
+		360.0f,
+		(1.0f/64.0f),
+		7.8f,
+		16667 ,
+		{ }
+	},
+
+	/* light sensor name */
+	{
+		"TSL27713FN",
+		"Taos",
+		1,
+		SENSORS_LIGHT_HANDLE,
+		SENSOR_TYPE_LIGHT,
+		(powf(10, (280.0f / 47.0f)) * 4),
+		1.0f,
+		0.75f,
+		0,
+		{ }
+	},
+
+	/* proximity sensor */
+	{
+		"TSL27713FN",
+		"Taos",
+		1,
+		SENSORS_PROXIMITY_HANDLE,
+		SENSOR_TYPE_PROXIMITY,
+		5.0f,
+		5.0f,
+		0.75f,
+		0,
+		{ }
+	},
+
+	/* gyro scope */
+	{
+		"MPU3050",
+		"Invensense",
+		1,
+		SENSORS_GYROSCOPE_HANDLE,
+		SENSOR_TYPE_GYROSCOPE,
+		35.0f,
+		0.06f,
+		0.2f,
+		2000,
+		{ }
+	},
+	
+	/* barometer */
+	{
+		"bmp180",
+		"Bosch",
+		1,
+		SENSORS_PRESSURE_HANDLE,
+		SENSOR_TYPE_PRESSURE,
+		1100.0f,
+		0.01f,
+		0.67f,
+		20000,
+		{ }
+	}
+};
+
+
+static int open_sensors(const struct hw_module_t* module, const char* id,
+						struct hw_device_t** device);
+
+
+static int sensors__get_sensors_list(struct sensors_module_t* module,
+									 struct sensor_t const** list) 
+{
+		*list = sSensorList;
+		return ARRAY_SIZE(sSensorList);
+}
+
+static struct hw_module_methods_t sensors_module_methods = {
+		open: open_sensors
+};
+
+struct sensors_module_t HAL_MODULE_INFO_SYM = {
+		common: {
+				tag: HARDWARE_MODULE_TAG,
+				version_major: 1,
+				version_minor: 0,
+				id: SENSORS_HARDWARE_MODULE_ID,
+				name: "Quic Sensor module",
+				author: "Quic",
+				methods: &sensors_module_methods,
+		},
+		get_sensors_list: sensors__get_sensors_list,
+};
+
+struct sensors_poll_context_t {
+	struct sensors_poll_device_t device; // must be first
+
+		sensors_poll_context_t();
+		~sensors_poll_context_t();
+	int activate(int handle, int enabled);
+	int setDelay(int handle, int64_t ns);
+	int pollEvents(sensors_event_t* data, int count);
+
+private:
+	enum {
+		light			= 0,
+		proximity		= 1,
+		compass			= 2,
+		gyro			= 3,
+		accel			= 4,
+		pressure		= 5,
+		numSensorDrivers,
+		numFds,
+	};
+
+	static const size_t wake = numFds - 1;
+	static const char WAKE_MESSAGE = 'W';
+	struct pollfd mPollFds[numFds];
+	int mWritePipeFd;
+	SensorBase* mSensors[numSensorDrivers];
+
+	int handleToDriver(int handle) const {
+		switch (handle) {
+			case SENSORS_ACCELERATION_HANDLE:
+				return accel;
+			case SENSORS_MAGNETIC_FIELD_HANDLE:
+			case SENSORS_ORIENTATION_HANDLE:
+				return compass;
+			case SENSORS_PROXIMITY_HANDLE:
+				return proximity;
+			case SENSORS_LIGHT_HANDLE:
+				return light;
+			case SENSORS_GYROSCOPE_HANDLE:
+				return gyro;
+			case SENSORS_PRESSURE_HANDLE:
+				return pressure;
+		}
+		return -EINVAL;
+	}
+};
+
+/*****************************************************************************/
+
+sensors_poll_context_t::sensors_poll_context_t()
+{
+	mSensors[light] = new LightSensor();
+	mPollFds[light].fd = mSensors[light]->getFd();
+	mPollFds[light].events = POLLIN;
+	mPollFds[light].revents = 0;
+
+	mSensors[proximity] = new ProximitySensor();
+	mPollFds[proximity].fd = mSensors[proximity]->getFd();
+	mPollFds[proximity].events = POLLIN;
+	mPollFds[proximity].revents = 0;
+
+	mSensors[compass] = new AkmSensor();
+	mPollFds[compass].fd = mSensors[compass]->getFd();
+	mPollFds[compass].events = POLLIN;
+	mPollFds[compass].revents = 0;
+
+	mSensors[gyro] = new GyroSensor();
+	mPollFds[gyro].fd = mSensors[gyro]->getFd();
+	mPollFds[gyro].events = POLLIN;
+	mPollFds[gyro].revents = 0;
+
+	mSensors[accel] = new AccelSensor();
+	mPollFds[accel].fd = mSensors[accel]->getFd();
+	mPollFds[accel].events = POLLIN;
+	mPollFds[accel].revents = 0;
+
+	mSensors[pressure] = new PressureSensor();
+	mPollFds[pressure].fd = mSensors[pressure]->getFd();
+	mPollFds[pressure].events = POLLIN;
+	mPollFds[pressure].revents = 0;
+
+	int wakeFds[2];
+	int result = pipe(wakeFds);
+	ALOGE_IF(result<0, "error creating wake pipe (%s)", strerror(errno));
+	fcntl(wakeFds[0], F_SETFL, O_NONBLOCK);
+	fcntl(wakeFds[1], F_SETFL, O_NONBLOCK);
+	mWritePipeFd = wakeFds[1];
+
+	mPollFds[wake].fd = wakeFds[0];
+	mPollFds[wake].events = POLLIN;
+	mPollFds[wake].revents = 0;
+}
+
+sensors_poll_context_t::~sensors_poll_context_t() {
+	for (int i=0 ; i<numSensorDrivers ; i++) {
+		delete mSensors[i];
+	}
+	close(mPollFds[wake].fd);
+	close(mWritePipeFd);
+}
+
+int sensors_poll_context_t::activate(int handle, int enabled) {
+	int index = handleToDriver(handle);
+	if (index < 0) return index;
+	int err =  mSensors[index]->enable(handle, enabled);
+	if (enabled && !err) {
+		const char wakeMessage(WAKE_MESSAGE);
+		int result = write(mWritePipeFd, &wakeMessage, 1);
+		ALOGE_IF(result<0, "error sending wake message (%s)", strerror(errno));
+	}
+	return err;
+}
+
+int sensors_poll_context_t::setDelay(int handle, int64_t ns) {
+
+	int index = handleToDriver(handle);
+	if (index < 0) return index;
+	return mSensors[index]->setDelay(handle, ns);
+}
+
+int sensors_poll_context_t::pollEvents(sensors_event_t* data, int count)
+{
+	int nbEvents = 0;
+	int n = 0;
+
+	do {
+		// see if we have some leftover from the last poll()
+		for (int i=0 ; count && i<numSensorDrivers ; i++) {
+			SensorBase* const sensor(mSensors[i]);
+			if ((mPollFds[i].revents & POLLIN) || (sensor->hasPendingEvents())) {
+				int nb = sensor->readEvents(data, count);
+				if (nb < count) {
+					// no more data for this sensor
+					mPollFds[i].revents = 0;
+				}
+				count -= nb;
+				nbEvents += nb;
+				data += nb;
+			}
+		}
+
+		if (count) {
+			// we still have some room, so try to see if we can get
+			// some events immediately or just wait if we don't have
+			// anything to return
+			do {
+				n = poll(mPollFds, numFds, nbEvents ? 0 : -1);
+			} while (n < 0 && errno == EINTR);
+			if (n<0) {
+				ALOGE("poll() failed (%s)", strerror(errno));
+				return -errno;
+			}
+			if (mPollFds[wake].revents & POLLIN) {
+				char msg;
+				int result = read(mPollFds[wake].fd, &msg, 1);
+				ALOGE_IF(result<0, "error reading from wake pipe (%s)", strerror(errno));
+				ALOGE_IF(msg != WAKE_MESSAGE, "unknown message on wake queue (0x%02x)", int(msg));
+				mPollFds[wake].revents = 0;
+			}
+		}
+		// if we have events and space, go read them
+	} while (n && count);
+
+	return nbEvents;
+}
+
+/*****************************************************************************/
+
+static int poll__close(struct hw_device_t *dev)
+{
+	sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev;
+	if (ctx) {
+		delete ctx;
+	}
+	return 0;
+}
+
+static int poll__activate(struct sensors_poll_device_t *dev,
+		int handle, int enabled) {
+	sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev;
+	return ctx->activate(handle, enabled);
+}
+
+static int poll__setDelay(struct sensors_poll_device_t *dev,
+		int handle, int64_t ns) {
+	sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev;
+	return ctx->setDelay(handle, ns);
+}
+
+static int poll__poll(struct sensors_poll_device_t *dev,
+		sensors_event_t* data, int count) {
+	sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev;
+	return ctx->pollEvents(data, count);
+}
+
+/*****************************************************************************/
+
+/** Open a new instance of a sensor device using name */
+static int open_sensors(const struct hw_module_t* module, const char* id,
+						struct hw_device_t** device)
+{
+		int status = -EINVAL;
+		sensors_poll_context_t *dev = new sensors_poll_context_t();
+
+		memset(&dev->device, 0, sizeof(sensors_poll_device_t));
+
+		dev->device.common.tag = HARDWARE_DEVICE_TAG;
+		dev->device.common.version  = 0;
+		dev->device.common.module   = const_cast<hw_module_t*>(module);
+		dev->device.common.close	= poll__close;
+		dev->device.activate		= poll__activate;
+		dev->device.setDelay		= poll__setDelay;
+		dev->device.poll			= poll__poll;
+
+		*device = &dev->device.common;
+		status = 0;
+
+		return status;
+}
+
diff --git a/sensors.h b/sensors.h
new file mode 100644
index 0000000..b2210e1
--- /dev/null
+++ b/sensors.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SENSORS_H
+#define ANDROID_SENSORS_H
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <linux/input.h>
+
+#include <hardware/hardware.h>
+#include <hardware/sensors.h>
+
+__BEGIN_DECLS
+
+/*****************************************************************************/
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+#define SENSORS_ACCELERATION_HANDLE		0
+#define SENSORS_MAGNETIC_FIELD_HANDLE		1
+#define SENSORS_ORIENTATION_HANDLE		2
+#define SENSORS_LIGHT_HANDLE			3
+#define SENSORS_PROXIMITY_HANDLE		4
+#define SENSORS_GYROSCOPE_HANDLE		5
+#define SENSORS_PRESSURE_HANDLE			6
+
+/*****************************************************************************/
+
+__END_DECLS
+
+#endif  // ANDROID_SENSORS_H