1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <fcntl.h>
18#include <errno.h>
19#include <math.h>
20#include <poll.h>
21#include <unistd.h>
22#include <dirent.h>
23#include <sys/select.h>
24#include <cutils/log.h>
25#include <linux/kxtf9.h>
26
27#include "KionixSensor.h"
28
29#define KIONIX_IOCTL_ENABLE_OUTPUT	KXTF9_IOCTL_ENABLE_OUTPUT
30#define KIONIX_IOCTL_DISABLE_OUTPUT	KXTF9_IOCTL_DISABLE_OUTPUT
31#define KIONIX_IOCTL_GET_ENABLE		KXTF9_IOCTL_GET_ENABLE
32#define KIONIX_IOCTL_UPDATE_ODR		KXTF9_IOCTL_UPDATE_ODR
33
34#define KIONIX_UNIT_CONVERSION(value) ((value) * GRAVITY_EARTH / (1024.0f))
35
36/*****************************************************************************/
37
38KionixSensor::KionixSensor()
39    : SensorBase(DIR_DEV, INPUT_NAME_ACC),
40      mEnabled(0),
41      mDelay(-1),
42      mInputReader(32),
43      mHasPendingEvent(false)
44{
45    mPendingEvent.version = sizeof(sensors_event_t);
46    mPendingEvent.sensor = ID_A;
47    mPendingEvent.type = SENSOR_TYPE_ACCELEROMETER;
48    memset(mPendingEvent.data, 0, sizeof(mPendingEvent.data));
49
50	open_device();
51}
52
53KionixSensor::~KionixSensor() {
54    if (mEnabled) {
55        setEnable(0, 0);
56    }
57
58	close_device();
59}
60
61int KionixSensor::setInitialState() {
62    struct input_absinfo absinfo;
63
64	if (mEnabled) {
65    	if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_ACCEL_X), &absinfo)) {
66			mPendingEvent.acceleration.x = KIONIX_UNIT_CONVERSION(absinfo.value);
67		}
68    	if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_ACCEL_Y), &absinfo)) {
69			mPendingEvent.acceleration.y = KIONIX_UNIT_CONVERSION(absinfo.value);
70		}
71		if (!ioctl(data_fd, EVIOCGABS(EVENT_TYPE_ACCEL_Z), &absinfo)) {
72			mPendingEvent.acceleration.z = KIONIX_UNIT_CONVERSION(absinfo.value);
73		}
74	}
75    return 0;
76}
77
78bool KionixSensor::hasPendingEvents() const {
79    return mHasPendingEvent;
80}
81
82int KionixSensor::setEnable(int32_t handle, int enabled) {
83    int err = 0;
84	int opDone = 0;
85
86	/* handle check */
87	if (handle != ID_A) {
88		ALOGE("KionixSensor: Invalid handle (%d)", handle);
89		return -EINVAL;
90	}
91
92	if (mEnabled <= 0) {
93		if (enabled) {
94			err = ioctl(dev_fd, KIONIX_IOCTL_ENABLE_OUTPUT);
95			opDone = 1;
96		}
97	} else if (mEnabled == 1) {
98		if (!enabled) {
99			err = ioctl(dev_fd, KIONIX_IOCTL_DISABLE_OUTPUT);
100			opDone = 1;
101		}
102	}
103	if (err != 0) {
104		ALOGE("KionixSensor: IOCTL failed (%s)", strerror(errno));
105		return err;
106	}
107	if (opDone) {
108		ALOGD("KionixSensor: Control set %d", enabled);
109		setInitialState();
110	}
111
112	if (enabled) {
113		mEnabled++;
114		if (mEnabled > 32767) mEnabled = 32767;
115	} else {
116		mEnabled--;
117		if (mEnabled < 0) mEnabled = 0;
118	}
119	ALOGD("KionixSensor: mEnabled = %d", mEnabled);
120
121    return err;
122}
123
124int KionixSensor::setDelay(int32_t handle, int64_t delay_ns)
125{
126	int err = 0;
127	int ms;
128
129	/* handle check */
130	if (handle != ID_A) {
131		ALOGE("KionixSensor: Invalid handle (%d)", handle);
132		return -EINVAL;
133	}
134
135	if (mDelay != delay_ns) {
136		ms = delay_ns / 1000000;
137        if (ioctl(dev_fd, KIONIX_IOCTL_UPDATE_ODR, &ms)) {
138			return -errno;
139		}
140		mDelay = delay_ns;
141	}
142
143	return err;
144}
145
146int64_t KionixSensor::getDelay(int32_t handle)
147{
148	return (handle == ID_A) ? mDelay : 0;
149}
150
151int KionixSensor::getEnable(int32_t handle)
152{
153	return (handle == ID_A) ? mEnabled : 0;
154}
155
156int KionixSensor::readEvents(sensors_event_t* data, int count)
157{
158    if (count < 1)
159        return -EINVAL;
160
161    if (mHasPendingEvent) {
162        mHasPendingEvent = false;
163        mPendingEvent.timestamp = getTimestamp();
164        *data = mPendingEvent;
165        return mEnabled ? 1 : 0;
166    }
167
168    ssize_t n = mInputReader.fill(data_fd);
169    if (n < 0)
170        return n;
171
172    int numEventReceived = 0;
173    input_event const* event;
174
175    while (count && mInputReader.readEvent(&event)) {
176        int type = event->type;
177        if (type == EV_ABS) {
178            float value = event->value;
179            if (event->code == EVENT_TYPE_ACCEL_X) {
180                mPendingEvent.acceleration.x = KIONIX_UNIT_CONVERSION(value);
181            } else if (event->code == EVENT_TYPE_ACCEL_Y) {
182                mPendingEvent.acceleration.y = KIONIX_UNIT_CONVERSION(value);
183            } else if (event->code == EVENT_TYPE_ACCEL_Z) {
184                mPendingEvent.acceleration.z = KIONIX_UNIT_CONVERSION(value);
185            }
186        } else if (type == EV_SYN) {
187            mPendingEvent.timestamp = timevalToNano(event->time);
188            if (mEnabled) {
189                *data++ = mPendingEvent;
190                count--;
191                numEventReceived++;
192            }
193        } else {
194            ALOGE("KionixSensor: unknown event (type=%d, code=%d)",
195                    type, event->code);
196        }
197        mInputReader.next();
198    }
199
200    return numEventReceived;
201}
202
203