OSDN Git Service

iio-sensors: add the missing closedir
[android-x86/hardware-libsensors.git] / kbdsensor.cpp
1 /**
2  *
3  * Atkbd style sensor
4  *
5  * Copyright (C) 2011-2013 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 <cstdlib>
18 #include <cstring>
19 #include <sys/stat.h>
20 #include <poll.h>
21 #include <fcntl.h>
22 #include <dirent.h>
23 #include <cutils/log.h>
24 #include <linux/input.h>
25 #include <linux/uinput.h>
26 #include <hardware/sensors.h>
27 #include <cutils/properties.h>
28
29 struct KbdSensorKeys {
30         char name[64];
31         int keys[8];
32 } KeysType[] = {
33         { "", { } },
34         { "AT Translated Set 2 keyboard", { EV_KEY, KEY_UP, KEY_RIGHT, KEY_DOWN, KEY_LEFT, KEY_LEFTALT, KEY_LEFTCTRL, 1 } },
35         { "AT Translated Set 2 keyboard", { EV_MSC, 91, 115, 123, 109, KEY_LEFTALT, KEY_LEFTCTRL, 3 } },
36         { "AT Translated Set 2 keyboard", { EV_KEY, KEY_F5, KEY_F8, KEY_F6, KEY_F7, KEY_LEFTALT, KEY_LEFTCTRL, 1 } },
37         { "AT Translated Set 2 keyboard", { EV_KEY, KEY_F9, KEY_F12, KEY_F10, KEY_F11, KEY_LEFTALT, KEY_LEFTCTRL, 1 } },
38         { "Asus Laptop extra buttons", { EV_KEY, KEY_F9, KEY_F12, KEY_F10, KEY_F11, KEY_LEFTALT, KEY_LEFTCTRL, 2 } },
39         { "HP WMI hotkeys", { -1, KEY_DIRECTION, 0, 0, 0, 0, 0, 3 } },
40 };
41
42 const int ID_ACCELERATION = (SENSORS_HANDLE_BASE + 0);
43
44 template <typename T> struct SensorFd : T {
45         SensorFd(const struct hw_module_t *module, struct hw_device_t **device);
46 };
47
48 template <typename T> SensorFd<T>::SensorFd(const struct hw_module_t *module, struct hw_device_t **device)
49 {
50         this->common.tag     = HARDWARE_DEVICE_TAG;
51         this->common.version = 0;
52         this->common.module  = const_cast<struct hw_module_t *>(module);
53         *device              = &this->common;
54         ALOGD("%s: module=%p dev=%p", __FUNCTION__, module, *device);
55 }
56
57 struct SensorPollContext : SensorFd<sensors_poll_device_t> {
58   public:
59         SensorPollContext(const struct hw_module_t *module, struct hw_device_t **device);
60         ~SensorPollContext();
61         bool isValid() const { return (pfd.fd >= 0); }
62
63   private:
64         static int poll_close(struct hw_device_t *dev);
65         static int poll_activate(struct sensors_poll_device_t *dev, int handle, int enabled);
66         static int poll_setDelay(struct sensors_poll_device_t *dev, int handle, int64_t ns);
67         static int poll_poll(struct sensors_poll_device_t *dev, sensors_event_t *data, int count);
68
69         int doPoll(sensors_event_t *data, int count);
70
71         enum {
72                 ROT_0,
73                 ROT_90,
74                 ROT_180,
75                 ROT_270
76         };
77
78         bool enabled;
79         int rotation;
80         struct timespec delay;
81         struct pollfd pfd;
82         sensors_event_t orients[4];
83         KbdSensorKeys *ktype;
84 };
85
86 SensorPollContext::SensorPollContext(const struct hw_module_t *module, struct hw_device_t **device)
87       : SensorFd<sensors_poll_device_t>(module, device), enabled(false), rotation(ROT_0), ktype(KeysType)
88 {
89         common.close = poll_close;
90         activate     = poll_activate;
91         setDelay     = poll_setDelay;
92         poll         = poll_poll;
93
94         int &fd = pfd.fd;
95         fd = -1;
96         const char *dirname = "/dev/input";
97         char prop[PROPERTY_VALUE_MAX];
98         if (property_get("hal.sensors.kbd.keys", prop, 0))
99                 sscanf(prop, "%s,%d,%d,%d,%d,%d,%d,%d,%d", ktype->name, ktype->keys,
100                                 ktype->keys + 1, ktype->keys + 2, ktype->keys + 3, ktype->keys + 4, ktype->keys + 5, ktype->keys + 6, ktype->keys + 7);
101         else if (property_get("hal.sensors.kbd.type", prop, 0))
102                 ktype = &KeysType[atoi(prop)];
103         else
104                 ktype = 0;
105         if (DIR *dir = opendir(dirname)) {
106                 char name[PATH_MAX];
107                 while (struct dirent *de = readdir(dir)) {
108                         if (de->d_name[0] != 'e') // not eventX
109                                 continue;
110                         snprintf(name, PATH_MAX, "%s/%s", dirname, de->d_name);
111                         fd = open(name, O_RDWR);
112                         if (fd < 0) {
113                                 ALOGE("could not open %s, %s", name, strerror(errno));
114                                 continue;
115                         }
116                         name[sizeof(name) - 1] = '\0';
117                         if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
118                                 ALOGE("could not get device name for %s, %s\n", name, strerror(errno));
119                                 name[0] = '\0';
120                         }
121
122                         if (ktype) {
123                                 if (!strcmp(name, ktype->name))
124                                         break;
125                         } else {
126                                 ktype = KeysType + (sizeof(KeysType) / sizeof(KeysType[0]));
127                                 while (--ktype != KeysType)
128                                         if (!strcmp(name, ktype->name))
129                                                 break;
130                                 if (ktype != KeysType)
131                                         break;
132                                 else
133                                         ktype = 0;
134                         }
135                         close(fd);
136                         fd = -1;
137                 }
138                 ALOGI_IF(fd >= 0, "Open %s ok, fd=%d", name, fd);
139                 closedir(dir);
140         }
141
142         pfd.events = POLLIN;
143         orients[ROT_0].version = sizeof(sensors_event_t);
144         orients[ROT_0].sensor = ID_ACCELERATION;
145         orients[ROT_0].type = SENSOR_TYPE_ACCELEROMETER;
146         orients[ROT_0].acceleration.status = SENSOR_STATUS_ACCURACY_HIGH;
147         orients[ROT_270] = orients[ROT_180] = orients[ROT_90] = orients[ROT_0];
148         const double angle = 20.0;
149         const double cos_angle = GRAVITY_EARTH * cos(angle / M_PI);
150         const double sin_angle = GRAVITY_EARTH * sin(angle / M_PI);
151         orients[ROT_0].acceleration.x   = 0.0;
152         orients[ROT_0].acceleration.y   = cos_angle;
153         orients[ROT_0].acceleration.z   = sin_angle;
154         orients[ROT_90].acceleration.x  = cos_angle;
155         orients[ROT_90].acceleration.y  = 0.0;
156         orients[ROT_90].acceleration.z  = sin_angle;
157         orients[ROT_180].acceleration.x = 0.0;
158         orients[ROT_180].acceleration.y = -cos_angle;
159         orients[ROT_180].acceleration.z = -sin_angle;
160         orients[ROT_270].acceleration.x = -cos_angle;
161         orients[ROT_270].acceleration.y = 0.0;
162         orients[ROT_270].acceleration.z = -sin_angle;
163
164         delay.tv_sec = 0;
165         delay.tv_nsec = 200000000L;
166
167         ALOGD("%s: dev=%p fd=%d", __FUNCTION__, this, fd);
168 }
169
170 SensorPollContext::~SensorPollContext()
171 {
172         close(pfd.fd);
173 }
174
175 int SensorPollContext::poll_close(struct hw_device_t *dev)
176 {
177         ALOGD("%s: dev=%p", __FUNCTION__, dev);
178         delete reinterpret_cast<SensorPollContext *>(dev);
179         return 0;
180 }
181
182 int SensorPollContext::poll_activate(struct sensors_poll_device_t *dev, int handle, int enabled)
183 {
184         ALOGD("%s: dev=%p handle=%d enabled=%d", __FUNCTION__, dev, handle, enabled);
185         SensorPollContext *ctx = reinterpret_cast<SensorPollContext *>(dev);
186         ctx->enabled = enabled;
187         return 0;
188 }
189
190 int SensorPollContext::poll_setDelay(struct sensors_poll_device_t *dev, int handle, int64_t ns)
191 {
192         ALOGD("%s: dev=%p delay-ns=%lld", __FUNCTION__, dev, ns);
193         return 0;
194 }
195
196 int SensorPollContext::poll_poll(struct sensors_poll_device_t *dev, sensors_event_t *data, int count)
197 {
198         ALOGV("%s: dev=%p data=%p count=%d", __FUNCTION__, dev, data, count);
199         SensorPollContext *ctx = reinterpret_cast<SensorPollContext *>(dev);
200         return ctx->doPoll(data, count);
201 }
202
203 int SensorPollContext::doPoll(sensors_event_t *data, int count)
204 {
205         nanosleep(&delay, 0);
206         if (!isValid())
207                 return 0;
208
209         int *keys = ktype->keys;
210         while (int pollres = ::poll(&pfd, 1, -1)) {
211                 if (pollres < 0) {
212                         ALOGE("%s: poll %d error: %s", __FUNCTION__, pfd.fd, strerror(errno));
213                         break;
214                 }
215                 if (!(pfd.revents & POLLIN)) {
216                         ALOGW("%s: ignore revents %d", __FUNCTION__, pfd.revents);
217                         continue;
218                 }
219
220                 struct input_event iev;
221                 size_t res = ::read(pfd.fd, &iev, sizeof(iev));
222                 if (res < sizeof(iev)) {
223                         ALOGW("insufficient input data(%d)? fd=%d", res, pfd.fd);
224                         continue;
225                 }
226                 ALOGV("type=%d scancode=%d value=%d from fd=%d", iev.type, iev.code, iev.value, pfd.fd);
227                 if (iev.type == keys[0]) {
228                         int rot;
229                         int input = (keys[0] == EV_MSC) ? iev.value : iev.code;
230                         if (input == keys[1])
231                                 rot = ROT_0;
232                         else if (input == keys[2])
233                                 rot = ROT_90;
234                         else if (input == keys[3])
235                                 rot = ROT_180;
236                         else if (input == keys[4])
237                                 rot = ROT_270;
238                         else if (input == keys[5] || input == keys[6])
239                                 rot = rotation;
240                         else
241                                 rot = -1;
242
243                         if (rot >= 0) {
244                                 if (rot != rotation) {
245                                         ALOGI("orientation changed from %d to %d", rotation * 90, rot * 90);
246                                         rotation = rot;
247                                 }
248                                 if (enabled && count > 0)
249                                         break;
250                         }
251                 } else if (iev.type == EV_KEY) {
252                         if (iev.code == keys[1] && iev.value) {
253                                 if (rotation == ROT_270)
254                                         rotation = ROT_0;
255                                 else
256                                         rotation++;
257                         }
258                         if (iev.code == keys[2] && iev.value) {
259                                 if (rotation == ROT_0)
260                                         rotation = ROT_270;
261                                 else
262                                         rotation--;
263                         }
264                         break;
265                 } else if (iev.type == EV_SW && iev.code == SW_TABLET_MODE) {
266                         if (!iev.value)
267                                 rotation = ROT_0;
268                         else if (rotation == ROT_0)
269                                 rotation = ROT_90;
270                         break;
271                 }
272         }
273
274         int cnt;
275         struct timespec t;
276         data[0] = orients[rotation];
277         t.tv_sec = t.tv_nsec = 0;
278         clock_gettime(CLOCK_MONOTONIC, &t);
279         data[0].timestamp = int64_t(t.tv_sec) * 1000000000LL + t.tv_nsec;
280         for (cnt = 1; cnt < keys[7] && cnt < count; ++cnt) {
281                 data[cnt] = data[cnt - 1];
282                 data[cnt].timestamp += delay.tv_nsec;
283                 nanosleep(&delay, 0);
284         }
285         ALOGV("%s: dev=%p fd=%d rotation=%d cnt=%d", __FUNCTION__, this, pfd.fd, rotation * 90, cnt);
286         return cnt;
287 }
288
289 static int open_kbd_sensor(const struct hw_module_t *module, const char *id, struct hw_device_t **device)
290 {
291         ALOGD("%s: id=%s", __FUNCTION__, id);
292         SensorPollContext *ctx = new SensorPollContext(module, device);
293         return (ctx && ctx->isValid()) ? 0 : -EINVAL;
294 }
295
296 static struct sensor_t sSensorListInit[] = {
297         {
298                 name: "Kbd Orientation Sensor",
299                 vendor: "Android-x86 Open Source Project",
300                 version: 1,
301                 handle: ID_ACCELERATION,
302                 type: SENSOR_TYPE_ACCELEROMETER,
303                 maxRange: 2.8f,
304                 resolution: 1.0f/4032.0f,
305                 power: 3.0f,
306                 minDelay: 0,
307                 fifoReservedEventCount: 0,
308                 fifoMaxEventCount: 0,
309                 stringType: SENSOR_STRING_TYPE_ACCELEROMETER,
310                 requiredPermission: "",
311                 maxDelay: 0,
312                 flags: SENSOR_FLAG_ONE_SHOT_MODE,
313                 reserved: { }
314         }
315 };
316
317 static int sensors_get_sensors_list(struct sensors_module_t *module, struct sensor_t const **list)
318 {
319         *list = sSensorListInit;
320         return sizeof(sSensorListInit) / sizeof(struct sensor_t);
321 }
322
323 static struct hw_module_methods_t sensors_methods = {
324         open: open_kbd_sensor
325 };
326
327 struct sensors_module_t HAL_MODULE_INFO_SYM = {
328         common: {
329                 tag: HARDWARE_MODULE_TAG,
330                 version_major: 2,
331                 version_minor: 3,
332                 id: SENSORS_HARDWARE_MODULE_ID,
333                 name: "Kbd Orientation Sensor",
334                 author: "Chih-Wei Huang",
335                 methods: &sensors_methods,
336                 dso: 0,
337                 reserved: { }
338         },
339         get_sensors_list: sensors_get_sensors_list
340 };