initial commit, taken and modified from linaro/insignal
diff --git a/exynos4/hal/libsensors/AkmSensor.cpp b/exynos4/hal/libsensors/AkmSensor.cpp
new file mode 100644
index 0000000..c147bd6
--- /dev/null
+++ b/exynos4/hal/libsensors/AkmSensor.cpp
@@ -0,0 +1,310 @@
+/*
+ * 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 <dlfcn.h>
+
+#include "ak8973b.h"
+
+#include <cutils/log.h>
+#include "AkmSensor.h"
+
+//#define LOG_NDEBUG 0
+
+/*****************************************************************************/
+
+int (*akm_is_sensor_enabled)(uint32_t sensor_type);
+int (*akm_enable_sensor)(uint32_t sensor_type);
+int (*akm_disable_sensor)(uint32_t sensor_type);
+int (*akm_set_delay)(uint32_t sensor_type, uint64_t delay);
+
+int stub_is_sensor_enabled(uint32_t sensor_type) {
+    return 0;
+}
+
+int stub_enable_disable_sensor(uint32_t sensor_type) {
+    return -ENODEV;
+}
+
+int stub_set_delay(uint32_t sensor_type, uint64_t delay) {
+    return -ENODEV;
+}
+
+AkmSensor::AkmSensor()
+: SensorBase(NULL, NULL),
+      mEnabled(0),
+      mPendingMask(0),
+      mInputReader(32)
+{
+    /* Open the library before opening the input device.  The library
+     * creates a uinput device.
+     */
+    if (loadAKMLibrary() == 0) {
+        data_name = "compass_sensor";
+        data_fd = openInput("compass_sensor");
+    }
+
+    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;
+
+    // read the actual value of all sensors if they're enabled already
+    struct input_absinfo absinfo;
+    short flags = 0;
+
+    if (akm_is_sensor_enabled(SENSOR_TYPE_ACCELEROMETER))  {
+        mEnabled |= 1<<Accelerometer;
+        if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_ACCEL_X), &absinfo)) {
+            mPendingEvents[Accelerometer].acceleration.x = absinfo.value * CONVERT_A_X;
+        }
+        if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_ACCEL_Y), &absinfo)) {
+            mPendingEvents[Accelerometer].acceleration.y = absinfo.value * CONVERT_A_Y;
+        }
+        if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_ACCEL_Z), &absinfo)) {
+            mPendingEvents[Accelerometer].acceleration.z = absinfo.value * CONVERT_A_Z;
+        }
+    }
+    if (akm_is_sensor_enabled(SENSOR_TYPE_MAGNETIC_FIELD))  {
+        mEnabled |= 1<<MagneticField;
+        if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_MAGV_X), &absinfo)) {
+            mPendingEvents[MagneticField].magnetic.x = absinfo.value * CONVERT_M_X;
+        }
+        if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_MAGV_Y), &absinfo)) {
+            mPendingEvents[MagneticField].magnetic.y = absinfo.value * CONVERT_M_Y;
+        }
+        if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_MAGV_Z), &absinfo)) {
+            mPendingEvents[MagneticField].magnetic.z = absinfo.value * CONVERT_M_Z;
+        }
+    }
+    if (akm_is_sensor_enabled(SENSOR_TYPE_ORIENTATION))  {
+        mEnabled |= 1<<Orientation;
+        if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_YAW), &absinfo)) {
+            mPendingEvents[Orientation].orientation.azimuth = absinfo.value;
+        }
+        if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_PITCH), &absinfo)) {
+            mPendingEvents[Orientation].orientation.pitch = absinfo.value;
+        }
+        if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_ROLL), &absinfo)) {
+            mPendingEvents[Orientation].orientation.roll = -absinfo.value;
+        }
+        if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_ORIENT_STATUS), &absinfo)) {
+            mPendingEvents[Orientation].orientation.status = uint8_t(absinfo.value & SENSOR_STATE_MASK);
+        }
+    }
+
+    // disable temperature sensor, since it is not supported
+    akm_disable_sensor(SENSOR_TYPE_TEMPERATURE);
+}
+
+AkmSensor::~AkmSensor()
+{
+    if (mLibAKM) {
+        unsigned ref = ::dlclose(mLibAKM);
+    }
+}
+
+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))) {
+        uint32_t sensor_type;
+        switch (what) {
+            case Accelerometer: sensor_type = SENSOR_TYPE_ACCELEROMETER;  break;
+            case MagneticField: sensor_type = SENSOR_TYPE_MAGNETIC_FIELD; break;
+            case Orientation:   sensor_type = SENSOR_TYPE_ORIENTATION;  break;
+        }
+        short flags = newState;
+        if (en)
+            err = akm_enable_sensor(sensor_type);
+        else
+            err = akm_disable_sensor(sensor_type);
+
+        LOGE_IF(err, "Could not change sensor state (%s)", strerror(-err));
+        if (!err) {
+            mEnabled &= ~(1<<what);
+            mEnabled |= (uint32_t(flags)<<what);
+        }
+    }
+    return err;
+}
+
+int AkmSensor::setDelay(int32_t handle, int64_t ns)
+{
+    uint32_t sensor_type = 0;
+
+    if (ns < 0)
+        return -EINVAL;
+
+    switch (handle) {
+        case ID_A: sensor_type = SENSOR_TYPE_ACCELEROMETER; break;
+        case ID_M: sensor_type = SENSOR_TYPE_MAGNETIC_FIELD; break;
+        case ID_O: sensor_type = SENSOR_TYPE_ORIENTATION; break;
+    }
+
+    if (sensor_type == 0)
+        return -EINVAL;
+
+    return akm_set_delay(sensor_type, ns);
+}
+
+int AkmSensor::loadAKMLibrary()
+{
+    mLibAKM = dlopen("libakm.so", RTLD_NOW);
+
+    if (!mLibAKM) {
+        akm_is_sensor_enabled = stub_is_sensor_enabled;
+        akm_enable_sensor = stub_enable_disable_sensor;
+        akm_disable_sensor = stub_enable_disable_sensor;
+        akm_set_delay = stub_set_delay;
+        LOGE("AkmSensor: unable to load AKM Library, %s", dlerror());
+        return -ENOENT;
+    }
+
+    *(void **)&akm_is_sensor_enabled = dlsym(mLibAKM, "akm_is_sensor_enabled");
+    *(void **)&akm_enable_sensor = dlsym(mLibAKM, "akm_enable_sensor");
+    *(void **)&akm_disable_sensor = dlsym(mLibAKM, "akm_disable_sensor");
+    *(void **)&akm_set_delay = dlsym(mLibAKM, "akm_set_delay");
+
+    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 {
+            LOGE("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:
+            LOGV("AkmSensor: EVENT_TYPE_MAGV_X value =%d", value);
+            mPendingMask |= 1<<MagneticField;
+            mPendingEvents[MagneticField].magnetic.x = value * CONVERT_M_X;
+            break;
+        case EVENT_TYPE_MAGV_Y:
+            LOGV("AkmSensor: EVENT_TYPE_MAGV_Y value =%d", value);
+            mPendingMask |= 1<<MagneticField;
+            mPendingEvents[MagneticField].magnetic.y = value * CONVERT_M_Y;
+            break;
+        case EVENT_TYPE_MAGV_Z:
+            LOGV("AkmSensor: EVENT_TYPE_MAGV_Z value =%d", value);
+            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_A;
+            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:
+            uint8_t status = uint8_t(value & SENSOR_STATE_MASK);
+            if (status == 4)
+                status = 0;
+            mPendingMask |= 1<<Orientation;
+            mPendingEvents[Orientation].orientation.status = status;
+            break;
+    }
+}
diff --git a/exynos4/hal/libsensors/AkmSensor.h b/exynos4/hal/libsensors/AkmSensor.h
new file mode 100644
index 0000000..44214e0
--- /dev/null
+++ b/exynos4/hal/libsensors/AkmSensor.h
@@ -0,0 +1,62 @@
+/*
+ * 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 "sensors.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 loadAKMLibrary();
+    void *mLibAKM;
+    uint32_t mEnabled;
+    uint32_t mPendingMask;
+    InputEventCircularReader mInputReader;
+    sensors_event_t mPendingEvents[numSensors];
+};
+
+/*****************************************************************************/
+
+#endif  // ANDROID_AKM_SENSOR_H
diff --git a/exynos4/hal/libsensors/Android.mk b/exynos4/hal/libsensors/Android.mk
new file mode 100644
index 0000000..15c29a2
--- /dev/null
+++ b/exynos4/hal/libsensors/Android.mk
@@ -0,0 +1,45 @@
+# 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.
+
+
+LOCAL_PATH := $(call my-dir)
+
+ifneq ($(TARGET_SIMULATOR),true)
+
+# HAL module implemenation, not prelinked, and stored in
+# hw/<SENSORS_HARDWARE_MODULE_ID>.<ro.product.board>.so
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := sensors.$(TARGET_BOARD_PLATFORM)
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS := -DLOG_TAG=\"Sensors\"
+LOCAL_SRC_FILES := 						\
+				sensors.cpp 			\
+				SensorBase.cpp			\
+				LightSensor.cpp			\
+				ProximitySensor.cpp		\
+				AkmSensor.cpp                   \
+				GyroSensor.cpp                  \
+                                InputEventReader.cpp
+
+LOCAL_SHARED_LIBRARIES := liblog libcutils libdl
+LOCAL_PRELINK_MODULE := false
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif # !TARGET_SIMULATOR
diff --git a/exynos4/hal/libsensors/GyroSensor.cpp b/exynos4/hal/libsensors/GyroSensor.cpp
new file mode 100644
index 0000000..ef0c01c
--- /dev/null
+++ b/exynos4/hal/libsensors/GyroSensor.cpp
@@ -0,0 +1,185 @@
+/*
+ * 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"
+
+#define FETCH_FULL_EVENT_BEFORE_RETURN 1
+#define IGNORE_EVENT_TIME 350000000
+/*****************************************************************************/
+
+GyroSensor::GyroSensor()
+    : SensorBase(NULL, "gyro_sensor"),
+      mEnabled(0),
+      mInputReader(4),
+      mHasPendingEvent(false),
+      mEnabledTime(0)
+{
+    mPendingEvent.version = sizeof(sensors_event_t);
+    mPendingEvent.sensor = ID_GY;
+    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/");
+        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_X), &absinfo_y) &&
+        !ioctl(data_fd, EVIOCGABS(EVENT_TYPE_GYRO_X), &absinfo_z)) {
+        value = absinfo_x.value;
+        mPendingEvent.data[0] = value * CONVERT_GYRO_X;
+        value = absinfo_x.value;
+        mPendingEvent.data[1] = value * CONVERT_GYRO_Y;
+        value = absinfo_x.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) {
+        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 GyroSensor::hasPendingEvents() const {
+    return mHasPendingEvent;
+}
+
+int GyroSensor::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 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_REL) {
+            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 {
+            LOGE("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/exynos4/hal/libsensors/GyroSensor.h b/exynos4/hal/libsensors/GyroSensor.h
new file mode 100644
index 0000000..e8997de
--- /dev/null
+++ b/exynos4/hal/libsensors/GyroSensor.h
@@ -0,0 +1,55 @@
+/*
+ * 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 "sensors.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/exynos4/hal/libsensors/InputEventReader.cpp b/exynos4/hal/libsensors/InputEventReader.cpp
new file mode 100644
index 0000000..1014f29
--- /dev/null
+++ b/exynos4/hal/libsensors/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/exynos4/hal/libsensors/InputEventReader.h b/exynos4/hal/libsensors/InputEventReader.h
new file mode 100644
index 0000000..180aade
--- /dev/null
+++ b/exynos4/hal/libsensors/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/exynos4/hal/libsensors/LightSensor.cpp b/exynos4/hal/libsensors/LightSensor.cpp
new file mode 100644
index 0000000..1d4f0e4
--- /dev/null
+++ b/exynos4/hal/libsensors/LightSensor.cpp
@@ -0,0 +1,160 @@
+/*
+ * 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/lightsensor.h>
+
+#include <cutils/log.h>
+
+#include "LightSensor.h"
+
+// #define LOG_NDEBUG 0
+
+/*****************************************************************************/
+
+LightSensor::LightSensor()
+    : SensorBase(NULL, "light_sensor"),
+      mEnabled(0),
+      mInputReader(4),
+      mHasPendingEvent(false)
+{
+    mPendingEvent.version = sizeof(sensors_event_t);
+    mPendingEvent.sensor = ID_L;
+    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::setInitialState() {
+    struct input_absinfo absinfo;
+    if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_LIGHT), &absinfo)) {
+        // make sure to report an event immediately
+        mHasPendingEvent = true;
+        mPendingEvent.light = absinfo.value;
+    }
+    return 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) {
+                if (event->value != -1) {
+                    LOGV("LightSensor: event (value=%d)", event->value);
+                    // FIXME: not sure why we're getting -1 sometimes
+                    mPendingEvent.light = event->value;
+                }
+            }
+        } else if (type == EV_SYN) {
+            mPendingEvent.timestamp = timevalToNano(event->time);
+            if (mEnabled) {
+                *data++ = mPendingEvent;
+                count--;
+                numEventReceived++;
+            }
+        } else {
+            LOGE("LightSensor: unknown event (type=%d, code=%d)",
+                    type, event->code);
+        }
+        mInputReader.next();
+    }
+
+    return numEventReceived;
+}
diff --git a/exynos4/hal/libsensors/LightSensor.h b/exynos4/hal/libsensors/LightSensor.h
new file mode 100644
index 0000000..85e65d9
--- /dev/null
+++ b/exynos4/hal/libsensors/LightSensor.h
@@ -0,0 +1,55 @@
+/*
+ * 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 "sensors.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;
+
+    float indexToValue(size_t index) const;
+    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/exynos4/hal/libsensors/MODULE_LICENSE_APACHE2 b/exynos4/hal/libsensors/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/exynos4/hal/libsensors/MODULE_LICENSE_APACHE2
diff --git a/exynos4/hal/libsensors/ProximitySensor.cpp b/exynos4/hal/libsensors/ProximitySensor.cpp
new file mode 100644
index 0000000..46424a5
--- /dev/null
+++ b/exynos4/hal/libsensors/ProximitySensor.cpp
@@ -0,0 +1,144 @@
+/*
+ * 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/capella_cm3602.h>
+
+#include <cutils/log.h>
+
+#include "ProximitySensor.h"
+
+/*****************************************************************************/
+
+ProximitySensor::ProximitySensor()
+    : SensorBase(NULL, "proximity_sensor"),
+      mEnabled(0),
+      mInputReader(4),
+      mHasPendingEvent(false)
+{
+    mPendingEvent.version = sizeof(sensors_event_t);
+    mPendingEvent.sensor = ID_P;
+    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) {
+                mPendingEvent.distance = indexToValue(event->value);
+            }
+        } else if (type == EV_SYN) {
+            mPendingEvent.timestamp = timevalToNano(event->time);
+            if (mEnabled) {
+                *data++ = mPendingEvent;
+                count--;
+                numEventReceived++;
+            }
+        } else {
+            LOGE("ProximitySensor: unknown event (type=%d, code=%d)",
+                    type, event->code);
+        }
+        mInputReader.next();
+    }
+
+    return numEventReceived;
+}
+
+float ProximitySensor::indexToValue(size_t index) const
+{
+    LOGV("ProximitySensor: Index = %zu", index);
+    return index * PROXIMITY_THRESHOLD_CM;
+}
diff --git a/exynos4/hal/libsensors/ProximitySensor.h b/exynos4/hal/libsensors/ProximitySensor.h
new file mode 100644
index 0000000..08ea49c
--- /dev/null
+++ b/exynos4/hal/libsensors/ProximitySensor.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_PROXIMITY_SENSOR_H
+#define ANDROID_PROXIMITY_SENSOR_H
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include "sensors.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/exynos4/hal/libsensors/SensorBase.cpp b/exynos4/hal/libsensors/SensorBase.cpp
new file mode 100644
index 0000000..d448eb2
--- /dev/null
+++ b/exynos4/hal/libsensors/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);
+        LOGE_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);
+    LOGE_IF(fd<0, "couldn't find '%s' input device", inputName);
+    return fd;
+}
diff --git a/exynos4/hal/libsensors/SensorBase.h b/exynos4/hal/libsensors/SensorBase.h
new file mode 100644
index 0000000..bb4d055
--- /dev/null
+++ b/exynos4/hal/libsensors/SensorBase.h
@@ -0,0 +1,65 @@
+/*
+ * 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>
+
+
+/*****************************************************************************/
+
+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/exynos4/hal/libsensors/ak8973b.h b/exynos4/hal/libsensors/ak8973b.h
new file mode 100644
index 0000000..9b7ab60
--- /dev/null
+++ b/exynos4/hal/libsensors/ak8973b.h
@@ -0,0 +1,51 @@
+/*
+ * Definitions for akm8973 compass chip.
+ */
+#ifndef AKM8973_H
+#define AKM8973_H
+
+#include <linux/ioctl.h>
+
+#define AKM8973_I2C_NAME "ak8973b"
+
+#define AKMIO                   0xA1
+
+/* IOCTLs for AKM library */
+#define ECS_IOCTL_WRITE         _IOW(AKMIO, 0x01, char*)
+#define ECS_IOCTL_READ          _IOWR(AKMIO, 0x02, char*)
+#define ECS_IOCTL_RESET         _IO(AKMIO, 0x03)
+#define ECS_IOCTL_SET_MODE      _IOW(AKMIO, 0x04, short)
+#define ECS_IOCTL_GETDATA       _IOR(AKMIO, 0x05, char[SENSOR_DATA_SIZE])
+#define ECS_IOCTL_SET_YPR               _IOW(AKMIO, 0x06, short[12])
+#define ECS_IOCTL_GET_OPEN_STATUS       _IOR(AKMIO, 0x07, int)
+#define ECS_IOCTL_GET_CLOSE_STATUS      _IOR(AKMIO, 0x08, int)
+#define ECS_IOCTL_GET_DELAY             _IOR(AKMIO, 0x30, int64_t)
+#define ECS_IOCTL_GET_PROJECT_NAME      _IOR(AKMIO, 0x0D, char[64])
+#define ECS_IOCTL_GET_MATRIX            _IOR(AKMIO, 0x0E, short [4][3][3])
+
+/* IOCTLs for APPs */
+#define ECS_IOCTL_APP_SET_MODE          _IOW(AKMIO, 0x10, short)
+#define ECS_IOCTL_APP_SET_MFLAG         _IOW(AKMIO, 0x11, short)
+#define ECS_IOCTL_APP_GET_MFLAG         _IOW(AKMIO, 0x12, short)
+#define ECS_IOCTL_APP_SET_AFLAG         _IOW(AKMIO, 0x13, short)
+#define ECS_IOCTL_APP_GET_AFLAG         _IOR(AKMIO, 0x14, short)
+#define ECS_IOCTL_APP_SET_TFLAG         _IOR(AKMIO, 0x15, short)
+#define ECS_IOCTL_APP_GET_TFLAG         _IOR(AKMIO, 0x16, short)
+#define ECS_IOCTL_APP_RESET_PEDOMETER   _IO(AKMIO, 0x17)
+#define ECS_IOCTL_APP_SET_DELAY         _IOW(AKMIO, 0x18, int64_t)
+#define ECS_IOCTL_APP_GET_DELAY         ECS_IOCTL_GET_DELAY
+
+/* Set raw magnetic vector flag */
+#define ECS_IOCTL_APP_SET_MVFLAG        _IOW(AKMIO, 0x19, short)
+
+/* Get raw magnetic vector flag */
+#define ECS_IOCTL_APP_GET_MVFLAG        _IOR(AKMIO, 0x1A, short)
+
+struct akm8973_platform_data {
+        short layouts[4][3][3];
+        char project_name[64];
+        int gpio_RST;
+        int gpio_INT;
+};
+
+#endif
diff --git a/exynos4/hal/libsensors/sensors.cpp b/exynos4/hal/libsensors/sensors.cpp
new file mode 100644
index 0000000..6f0bdad
--- /dev/null
+++ b/exynos4/hal/libsensors/sensors.cpp
@@ -0,0 +1,326 @@
+/*
+ * 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 "LightSensor.h"
+#include "ProximitySensor.h"
+#include "AkmSensor.h"
+#include "GyroSensor.h"
+
+/*****************************************************************************/
+
+#define DELAY_OUT_TIME 0x7FFFFFFF
+
+#define LIGHT_SENSOR_POLLTIME    2000000000
+
+
+#define SENSORS_ACCELERATION     (1<<ID_A)
+#define SENSORS_MAGNETIC_FIELD   (1<<ID_M)
+#define SENSORS_ORIENTATION      (1<<ID_O)
+#define SENSORS_LIGHT            (1<<ID_L)
+#define SENSORS_PROXIMITY        (1<<ID_P)
+#define SENSORS_GYROSCOPE        (1<<ID_GY)
+
+#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 AKM_FTRACE 0
+#define AKM_DEBUG 0
+#define AKM_DATA 0
+
+/*****************************************************************************/
+
+/* The SENSORS Module */
+static const struct sensor_t sSensorList[] = {
+        { "KR3DM 3-axis Accelerometer",
+          "STMicroelectronics",
+          1, SENSORS_ACCELERATION_HANDLE,
+          SENSOR_TYPE_ACCELEROMETER, RANGE_A, CONVERT_A, 0.23f, 20000, { } },
+        { "AK8975 3-axis Magnetic field sensor",
+          "Asahi Kasei Microdevices",
+          1, SENSORS_MAGNETIC_FIELD_HANDLE,
+          SENSOR_TYPE_MAGNETIC_FIELD, 2000.0f, CONVERT_M, 6.8f, 16667, { } },
+        { "AK8973 Orientation sensor",
+          "Asahi Kasei Microdevices",
+          1, SENSORS_ORIENTATION_HANDLE,
+          SENSOR_TYPE_ORIENTATION, 360.0f, CONVERT_O, 7.8f, 16667, { } },
+        { "CM3663 Light sensor",
+          "Capella Microsystems",
+          1, SENSORS_LIGHT_HANDLE,
+          SENSOR_TYPE_LIGHT, 10240.0f, 1.0f, 0.75f, 0, { } },
+        { "CM3663 Proximity sensor",
+          "Capella Microsystems",
+          1, SENSORS_PROXIMITY_HANDLE,
+          SENSOR_TYPE_PROXIMITY, 5.0f, 5.0f, 0.75f, 0, { } },
+        { "K3G Gyroscope sensor",
+          "STMicroelectronics",
+          1, SENSORS_GYROSCOPE_HANDLE,
+          SENSOR_TYPE_GYROSCOPE, RANGE_GYRO, CONVERT_GYRO, 6.1f, 1190, { } },
+};
+
+
+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: "Samsung Sensor module",
+                author: "Samsung Electronic Company",
+                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,
+        akm             = 2,
+        gyro            = 3,
+        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 ID_A:
+            case ID_M:
+            case ID_O:
+                return akm;
+            case ID_P:
+                return proximity;
+            case ID_L:
+                return light;
+            case ID_GY:
+                return gyro;
+        }
+        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[akm] = new AkmSensor();
+    mPollFds[akm].fd = mSensors[akm]->getFd();
+    mPollFds[akm].events = POLLIN;
+    mPollFds[akm].revents = 0;
+
+    mSensors[gyro] = new GyroSensor();
+    mPollFds[gyro].fd = mSensors[gyro]->getFd();
+    mPollFds[gyro].events = POLLIN;
+    mPollFds[gyro].revents = 0;
+
+    int wakeFds[2];
+    int result = pipe(wakeFds);
+    LOGE_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);
+        LOGE_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
+            n = poll(mPollFds, numFds, nbEvents ? 0 : -1);
+            if (n<0) {
+                LOGE("poll() failed (%s)", strerror(errno));
+                return -errno;
+            }
+            if (mPollFds[wake].revents & POLLIN) {
+                char msg;
+                int result = read(mPollFds[wake].fd, &msg, 1);
+                LOGE_IF(result<0, "error reading from wake pipe (%s)", strerror(errno));
+                LOGE_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/exynos4/hal/libsensors/sensors.h b/exynos4/hal/libsensors/sensors.h
new file mode 100644
index 0000000..ecc6fed
--- /dev/null
+++ b/exynos4/hal/libsensors/sensors.h
@@ -0,0 +1,144 @@
+/*
+ * 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 ID_A  (0)
+#define ID_M  (1)
+#define ID_O  (2)
+#define ID_L  (3)
+#define ID_P  (4)
+#define ID_GY (5)
+
+/*****************************************************************************/
+
+/*
+ * The SENSORS Module
+ */
+
+/* the CM3663 is a binary proximity sensor that triggers around 6 cm on
+ * this hardware */
+#define PROXIMITY_THRESHOLD_CM  6.0f
+
+/*****************************************************************************/
+
+#define AKM_DEVICE_NAME     "/dev/akm8975"
+#define CM_DEVICE_NAME      "/dev/i2c11" // FIXME Proximity
+#define LS_DEVICE_NAME      "/dev/i2c11" // FIXME Lig
+
+/*
+    E/Sensors ( 2656): AkmSensor: processing event (type=0, code=0)
+    E/Sensors ( 2656): AkmSensor: processing event (type=2, code=8)
+    E/Sensors ( 2656): AkmSensor: processing event (type=2, code=3)
+    E/Sensors ( 2656): AkmSensor: processing event (type=2, code=4)
+    E/Sensors ( 2656): AkmSensor: processing event (type=2, code=5)
+    E/Sensors ( 2656): AkmSensor: processing event (type=2, code=0)
+    E/Sensors ( 2656): AkmSensor: processing event (type=2, code=1)
+    E/Sensors ( 2656): AkmSensor: processing event (type=2, code=2)
+    E/Sensors ( 2656): AkmSensor: processing event (type=2, code=6)
+    E/Sensors ( 2656): AkmSensor: processing event (type=2, code=7)
+    E/Sensors ( 2656): AkmSensor: processing event (type=2, code=9)
+    E/Sensors ( 2656): AkmSensor: processing event (type=0, code=0)
+    E/Sensors ( 2656): AkmSensor: processing event (type=2, code=8)
+    E/Sensors ( 2656): AkmSensor: processing event (type=2, code=3)
+    E/Sensors ( 2656): AkmSensor: processing event (type=2, code=4)
+    E/Sensors ( 2656): AkmSensor: processing event (type=2, code=5)
+    E/Sensors ( 2656): AkmSensor: processing event (type=2, code=0)
+    E/Sensors ( 2656): AkmSensor: processing event (type=2, code=1)
+    E/Sensors ( 2656): AkmSensor: processing event (type=2, code=2)
+    E/Sensors ( 2656): AkmSensor: processing event (type=2, code=6)
+    E/Sensors ( 2656): AkmSensor: processing event (type=2, code=7)
+    E/Sensors ( 2656): AkmSensor: processing event (type=2, code=9)
+*/
+
+// for akm8975
+#define EVENT_TYPE_ACCEL_X          ABS_Y  //1
+#define EVENT_TYPE_ACCEL_Y          ABS_X  //0
+#define EVENT_TYPE_ACCEL_Z          ABS_Z  //2
+//#define EVENT_TYPE_ACCEL_STATUS     ABS_WHEEL //8
+
+#define EVENT_TYPE_YAW              ABS_RX  //3
+#define EVENT_TYPE_PITCH            ABS_RY  //4
+#define EVENT_TYPE_ROLL             ABS_RZ  //5
+#define EVENT_TYPE_ORIENT_STATUS    ABS_WHEEL //8
+
+#define EVENT_TYPE_MAGV_X           ABS_RUDDER  // 6
+#define EVENT_TYPE_MAGV_Y           ABS_THROTTLE  // 7
+#define EVENT_TYPE_MAGV_Z           ABS_GAS  // 9
+
+#define EVENT_TYPE_TEMPERATURE      ABS_THROTTLE
+#define EVENT_TYPE_STEP_COUNT       ABS_GAS
+#define EVENT_TYPE_PROXIMITY        ABS_DISTANCE
+#define EVENT_TYPE_LIGHT            ABS_MISC
+
+#define EVENT_TYPE_GYRO_X           REL_RY
+#define EVENT_TYPE_GYRO_Y           REL_RX
+#define EVENT_TYPE_GYRO_Z           REL_RZ
+
+// 90 LSB = 1G for KR3DM
+#define LSB                         (90.0f)
+#define NUMOFACCDATA                (8.0f)
+
+// conversion of acceleration data to SI units (m/s^2)
+#define RANGE_A                     (2*GRAVITY_EARTH)
+#define CONVERT_A                   (GRAVITY_EARTH / LSB / NUMOFACCDATA)
+#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)
+
+/* conversion of orientation data to degree units */
+#define CONVERT_O                   (1.0f/64.0f)
+#define CONVERT_O_A                 (CONVERT_O)
+#define CONVERT_O_P                 (CONVERT_O)
+#define CONVERT_O_R                 (-CONVERT_O)
+
+// conversion of gyro data to SI units (radian/sec)
+#define RANGE_GYRO                  (2000.0f*(float)M_PI/180.0f)
+#define CONVERT_GYRO                ((70.0f / 1000.0f) * ((float)M_PI / 180.0f))
+#define CONVERT_GYRO_X              (CONVERT_GYRO)
+#define CONVERT_GYRO_Y              (-CONVERT_GYRO)
+#define CONVERT_GYRO_Z              (CONVERT_GYRO)
+
+#define SENSOR_STATE_MASK           (0x7FFF)
+
+/*****************************************************************************/
+
+__END_DECLS
+
+#endif  // ANDROID_SENSORS_H