OSDN Git Service

add module for HDAPS accelerometer found in many IBM Thinkpads
[android-x86/hardware-libsensors.git] / kbdsensor.cpp
1 /**
2  *
3  * Atkbd style sensor
4  *
5  * Copyright (C) 2011 The Android-x86 Open Source Project
6  *
7  * by Chih-Wei Huang <cwhuang@linux.org.tw>
8  *
9  * Licensed under GPLv2 or later
10  *
11  **/
12
13 #define LOG_TAG "KbdSensor"
14
15 #include <cmath>
16 #include <cerrno>
17 #include <cstring>
18 #include <sys/stat.h>
19 #include <poll.h>
20 #include <fcntl.h>
21 #include <dirent.h>
22 #include <cutils/log.h>
23 #include <linux/input.h>
24 #include <linux/uinput.h>
25 #include <hardware/sensors.h>
26
27 const int ID_ACCELERATION = (SENSORS_HANDLE_BASE + 0);
28
29 template <typename T> struct SensorFd : T {
30         SensorFd(const struct hw_module_t *module, struct hw_device_t **device);
31 };
32
33 template <typename T> SensorFd<T>::SensorFd(const struct hw_module_t *module, struct hw_device_t **device)
34 {
35         this->common.tag     = HARDWARE_DEVICE_TAG;
36         this->common.version = 0;
37         this->common.module  = const_cast<struct hw_module_t *>(module);
38         *device              = &this->common;
39         LOGD("%s: module=%p dev=%p", __FUNCTION__, module, *device);
40 }
41
42 struct SensorPollContext : SensorFd<sensors_poll_device_t> {
43   public:
44         SensorPollContext(const struct hw_module_t *module, struct hw_device_t **device);
45         ~SensorPollContext();
46
47   private:
48         static int poll_close(struct hw_device_t *dev);
49         static int poll_activate(struct sensors_poll_device_t *dev, int handle, int enabled);
50         static int poll_setDelay(struct sensors_poll_device_t *dev, int handle, int64_t ns);
51         static int poll_poll(struct sensors_poll_device_t *dev, sensors_event_t *data, int count);
52
53         enum {
54                 ROT_0,
55                 ROT_90,
56                 ROT_180,
57                 ROT_270
58         };
59
60         bool enabled;
61         int rotation;
62         struct timespec delay;
63         struct pollfd pfd;
64         sensors_event_t orients[4];
65 };
66
67 SensorPollContext::SensorPollContext(const struct hw_module_t *module, struct hw_device_t **device)
68       : SensorFd<sensors_poll_device_t>(module, device), enabled(false), rotation(ROT_0)
69 {
70         common.close = poll_close;
71         activate     = poll_activate;
72         setDelay     = poll_setDelay;
73         poll         = poll_poll;
74
75         int &fd = pfd.fd;
76         const char *dirname = "/dev/input";
77         if (DIR *dir = opendir(dirname)) {
78                 while (struct dirent *de = readdir(dir)) {
79                         if (de->d_name[0] != 'e') // eventX
80                                 continue;
81                         char name[PATH_MAX];
82                         snprintf(name, PATH_MAX, "%s/%s", dirname, de->d_name);
83                         fd = open(name, O_RDWR);
84                         if (fd < 0) {
85                                 LOGE("could not open %s, %s", name, strerror(errno));
86                                 continue;
87                         }
88                         name[sizeof(name) - 1] = '\0';
89                         if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
90                                 LOGE("could not get device name for %s, %s\n", name, strerror(errno));
91                                 name[0] = '\0';
92                         }
93
94                         // TODO: parse /etc/excluded-input-devices.xml
95                         if (!strcmp(name, "AT Translated Set 2 keyboard")) {
96                                 LOGI("open %s ok", name);
97                                 break;
98                         }
99                         close(fd);
100                 }
101                 closedir(dir);
102         }
103
104         pfd.events = POLLIN;
105         orients[ROT_0].version = sizeof(sensors_event_t);
106         orients[ROT_0].sensor = ID_ACCELERATION;
107         orients[ROT_0].type = SENSOR_TYPE_ACCELEROMETER;
108         orients[ROT_0].acceleration.status = SENSOR_STATUS_ACCURACY_HIGH;
109         orients[ROT_270] = orients[ROT_180] = orients[ROT_90] = orients[ROT_0];
110         const double angle = 20.0;
111         const double cos_angle = GRAVITY_EARTH * cos(angle / M_PI);
112         const double sin_angle = GRAVITY_EARTH * sin(angle / M_PI);
113         orients[ROT_0].acceleration.x   = 0.0;
114         orients[ROT_0].acceleration.y   = cos_angle;
115         orients[ROT_0].acceleration.z   = sin_angle;
116         orients[ROT_90].acceleration.x  = cos_angle;
117         orients[ROT_90].acceleration.y  = 0.0;
118         orients[ROT_90].acceleration.z  = sin_angle;
119         orients[ROT_180].acceleration.x = 0.0;
120         orients[ROT_180].acceleration.y = -cos_angle;
121         orients[ROT_180].acceleration.z = -sin_angle;
122         orients[ROT_270].acceleration.x = -cos_angle;
123         orients[ROT_270].acceleration.y = 0.0;
124         orients[ROT_270].acceleration.z = -sin_angle;
125
126         delay.tv_sec = 0;
127         delay.tv_nsec = 200000000L;
128
129         LOGV("%s: dev=%p fd=%d", __FUNCTION__, this, fd);
130 }
131
132 SensorPollContext::~SensorPollContext()
133 {
134         close(pfd.fd);
135 }
136
137 int SensorPollContext::poll_close(struct hw_device_t *dev)
138 {
139         LOGD("%s: dev=%p", __FUNCTION__, dev);
140         delete reinterpret_cast<SensorPollContext *>(dev);
141         return 0;
142 }
143 int SensorPollContext::poll_activate(struct sensors_poll_device_t *dev, int handle, int enabled)
144 {
145         LOGD("%s: dev=%p handle=%d enabled=%d", __FUNCTION__, dev, handle, enabled);
146         SensorPollContext *ctx = reinterpret_cast<SensorPollContext *>(dev);
147         ctx->enabled = enabled;
148         return 0;
149 }
150 int SensorPollContext::poll_setDelay(struct sensors_poll_device_t *dev, int handle, int64_t ns)
151 {
152         LOGD("%s: dev=%p delay-ns=%lld", __FUNCTION__, dev, ns);
153         return 0;
154 }
155 int SensorPollContext::poll_poll(struct sensors_poll_device_t *dev, sensors_event_t *data, int count)
156 {
157         LOGD("%s: dev=%p data=%p count=%d", __FUNCTION__, dev, data, count);
158         SensorPollContext *ctx = reinterpret_cast<SensorPollContext *>(dev);
159         struct timespec t;
160
161         struct pollfd &pfd = ctx->pfd;
162         nanosleep(&ctx->delay, 0);
163         while (int pollres = ::poll(&pfd, 1, -1)) {
164                 if (pollres < 0) {
165                         LOGE("%s: poll %d error: %s", __FUNCTION__, pfd.fd, strerror(errno));
166                         break;
167                 }
168                 if (!(pfd.revents & POLLIN)) {
169                         LOGW("%s: ignore revents %d", __FUNCTION__, pfd.revents);
170                         continue;
171                 }
172
173                 struct input_event iev;
174                 size_t res = ::read(pfd.fd, &iev, sizeof(iev));
175                 if (res < sizeof(iev)) {
176                         LOGW("insufficient input data(%d)? fd=%d", res, pfd.fd);
177                         continue;
178                 }
179                 LOGD("type=%d scancode=%d value=%d from fd=%d", iev.type, iev.code, iev.value, pfd.fd);
180                 if (iev.type == EV_KEY) {
181                         int rot = -1;
182                         switch (iev.code)
183                         {
184                                 case KEY_LEFTCTRL:
185                                 case KEY_LEFTALT:
186                                         if (iev.value)
187                                                 continue;
188                                         rot = ctx->rotation;
189                                         break;
190                                 case FN_ROT_0:
191                                         rot = ROT_0;
192                                         break;
193                                 case FN_ROT_90:
194                                         rot = ROT_90;
195                                         break;
196                                 case FN_ROT_180:
197                                         rot = ROT_180;
198                                         break;
199                                 case FN_ROT_270:
200                                         rot = ROT_270;
201                                         break;
202 #if 0
203                                 case KEY_ESC:
204                                         iev.code = KEY_LEFTMETA;
205                                         break;
206                                 case KEY_COMPOSE:
207                                         iev.code = KEY_ESC;
208                                         break;
209 #endif
210                         }
211                         if (rot >= 0) {
212                                 if (rot != ctx->rotation) {
213                                         LOGI("orientation changed from %d to %d", ctx->rotation * 90, rot * 90);
214                                         ctx->rotation = rot;
215                                 }
216                                 if (ctx->enabled && count > 0)
217                                         break;
218                         }
219                 }
220         }
221
222         LOGV("%s: dev=%p fd=%d rotation=%d", __FUNCTION__, dev, pfd.fd, ctx->rotation * 90);
223         data[0] = ctx->orients[ctx->rotation];
224         t.tv_sec = t.tv_nsec = 0;
225         clock_gettime(CLOCK_MONOTONIC, &t);
226         data[0].timestamp = int64_t(t.tv_sec) * 1000000000LL + t.tv_nsec;
227         return 1;
228 }
229
230 static int open_kbd_sensor(const struct hw_module_t *module, const char *id, struct hw_device_t **device)
231 {
232         LOGD("%s: id=%s", __FUNCTION__, id);
233         return new SensorPollContext(module, device) ? 0 : -EINVAL;
234 }
235
236 static struct sensor_t sSensorListInit[] = {
237         {
238                 name: "Kbd Orientation Sensor",
239                 vendor: "Android-x86 Open Source Project",
240                 version: 1,
241                 handle: ID_ACCELERATION,
242                 type: SENSOR_TYPE_ACCELEROMETER,
243                 maxRange: 2.8f,
244                 resolution: 1.0f/4032.0f,
245                 power: 3.0f,
246                 minDelay: 0,
247                 reserved: { }
248         }
249 };
250
251 static int sensors_get_sensors_list(struct sensors_module_t *module, struct sensor_t const **list)
252 {
253         *list = sSensorListInit;
254         return sizeof(sSensorListInit) / sizeof(struct sensor_t);
255 }
256
257 static struct hw_module_methods_t sensors_methods = {
258         open: open_kbd_sensor
259 };
260
261 struct sensors_module_t HAL_MODULE_INFO_SYM = {
262         common: {
263                 tag: HARDWARE_MODULE_TAG,
264                 version_major: 2,
265                 version_minor: 3,
266                 id: SENSORS_HARDWARE_MODULE_ID,
267                 name: "Kbd Orientation Sensor",
268                 author: "Chih-Wei Huang",
269                 methods: &sensors_methods,
270                 dso: 0,
271                 reserved: { }
272         },
273         get_sensors_list: sensors_get_sensors_list
274 };