5 * Copyright (C) 2011-2013 The Android-x86 Open Source Project
7 * by Chih-Wei Huang <cwhuang@linux.org.tw>
9 * Licensed under GPLv2 or later
13 #define LOG_TAG "KbdSensor"
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>
29 struct KbdSensorKeys {
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 } },
42 const int ID_ACCELERATION = (SENSORS_HANDLE_BASE + 0);
44 template <typename T> struct SensorFd : T {
45 SensorFd(const struct hw_module_t *module, struct hw_device_t **device);
48 template <typename T> SensorFd<T>::SensorFd(const struct hw_module_t *module, struct hw_device_t **device)
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);
57 struct SensorPollContext : SensorFd<sensors_poll_device_t> {
59 SensorPollContext(const struct hw_module_t *module, struct hw_device_t **device);
63 static int poll_close(struct hw_device_t *dev);
64 static int poll_activate(struct sensors_poll_device_t *dev, int handle, int enabled);
65 static int poll_setDelay(struct sensors_poll_device_t *dev, int handle, int64_t ns);
66 static int poll_poll(struct sensors_poll_device_t *dev, sensors_event_t *data, int count);
68 int doPoll(sensors_event_t *data, int count);
79 struct timespec delay;
81 sensors_event_t orients[4];
85 SensorPollContext::SensorPollContext(const struct hw_module_t *module, struct hw_device_t **device)
86 : SensorFd<sensors_poll_device_t>(module, device), enabled(false), rotation(ROT_0), ktype(KeysType)
88 common.close = poll_close;
89 activate = poll_activate;
90 setDelay = poll_setDelay;
94 const char *dirname = "/dev/input";
95 char prop[PROPERTY_VALUE_MAX];
96 if (property_get("hal.sensors.kbd.keys", prop, 0))
97 sscanf(prop, "%s,%d,%d,%d,%d,%d,%d,%d,%d", ktype->name, ktype->keys,
98 ktype->keys + 1, ktype->keys + 2, ktype->keys + 3, ktype->keys + 4, ktype->keys + 5, ktype->keys + 6, ktype->keys + 7);
99 else if (property_get("hal.sensors.kbd.type", prop, 0))
100 ktype = &KeysType[atoi(prop)];
103 if (DIR *dir = opendir(dirname)) {
105 while (struct dirent *de = readdir(dir)) {
106 if (de->d_name[0] != 'e') // not eventX
108 snprintf(name, PATH_MAX, "%s/%s", dirname, de->d_name);
109 fd = open(name, O_RDWR);
111 ALOGE("could not open %s, %s", name, strerror(errno));
114 name[sizeof(name) - 1] = '\0';
115 if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
116 ALOGE("could not get device name for %s, %s\n", name, strerror(errno));
121 if (!strcmp(name, ktype->name))
124 ktype = KeysType + (sizeof(KeysType) / sizeof(KeysType[0]));
125 while (--ktype != KeysType)
126 if (!strcmp(name, ktype->name))
128 if (ktype != KeysType)
136 ALOGI_IF(fd >= 0, "Open %s ok, fd=%d", name, fd);
141 orients[ROT_0].version = sizeof(sensors_event_t);
142 orients[ROT_0].sensor = ID_ACCELERATION;
143 orients[ROT_0].type = SENSOR_TYPE_ACCELEROMETER;
144 orients[ROT_0].acceleration.status = SENSOR_STATUS_ACCURACY_HIGH;
145 orients[ROT_270] = orients[ROT_180] = orients[ROT_90] = orients[ROT_0];
146 const double angle = 20.0;
147 const double cos_angle = GRAVITY_EARTH * cos(angle / M_PI);
148 const double sin_angle = GRAVITY_EARTH * sin(angle / M_PI);
149 orients[ROT_0].acceleration.x = 0.0;
150 orients[ROT_0].acceleration.y = cos_angle;
151 orients[ROT_0].acceleration.z = sin_angle;
152 orients[ROT_90].acceleration.x = cos_angle;
153 orients[ROT_90].acceleration.y = 0.0;
154 orients[ROT_90].acceleration.z = sin_angle;
155 orients[ROT_180].acceleration.x = 0.0;
156 orients[ROT_180].acceleration.y = -cos_angle;
157 orients[ROT_180].acceleration.z = -sin_angle;
158 orients[ROT_270].acceleration.x = -cos_angle;
159 orients[ROT_270].acceleration.y = 0.0;
160 orients[ROT_270].acceleration.z = -sin_angle;
163 delay.tv_nsec = 200000000L;
165 ALOGD("%s: dev=%p fd=%d", __FUNCTION__, this, fd);
168 SensorPollContext::~SensorPollContext()
173 int SensorPollContext::poll_close(struct hw_device_t *dev)
175 ALOGD("%s: dev=%p", __FUNCTION__, dev);
176 delete reinterpret_cast<SensorPollContext *>(dev);
180 int SensorPollContext::poll_activate(struct sensors_poll_device_t *dev, int handle, int enabled)
182 ALOGD("%s: dev=%p handle=%d enabled=%d", __FUNCTION__, dev, handle, enabled);
183 SensorPollContext *ctx = reinterpret_cast<SensorPollContext *>(dev);
184 ctx->enabled = enabled;
188 int SensorPollContext::poll_setDelay(struct sensors_poll_device_t *dev, int handle, int64_t ns)
190 ALOGD("%s: dev=%p delay-ns=%lld", __FUNCTION__, dev, ns);
194 int SensorPollContext::poll_poll(struct sensors_poll_device_t *dev, sensors_event_t *data, int count)
196 ALOGV("%s: dev=%p data=%p count=%d", __FUNCTION__, dev, data, count);
197 SensorPollContext *ctx = reinterpret_cast<SensorPollContext *>(dev);
198 return ctx->doPoll(data, count);
201 int SensorPollContext::doPoll(sensors_event_t *data, int count)
203 nanosleep(&delay, 0);
204 int *keys = ktype->keys;
205 while (int pollres = ::poll(&pfd, 1, -1)) {
207 ALOGE("%s: poll %d error: %s", __FUNCTION__, pfd.fd, strerror(errno));
210 if (!(pfd.revents & POLLIN)) {
211 ALOGW("%s: ignore revents %d", __FUNCTION__, pfd.revents);
215 struct input_event iev;
216 size_t res = ::read(pfd.fd, &iev, sizeof(iev));
217 if (res < sizeof(iev)) {
218 ALOGW("insufficient input data(%d)? fd=%d", res, pfd.fd);
221 ALOGV("type=%d scancode=%d value=%d from fd=%d", iev.type, iev.code, iev.value, pfd.fd);
222 if (iev.type == keys[0]) {
224 int input = (keys[0] == EV_MSC) ? iev.value : iev.code;
225 if (input == keys[1])
227 else if (input == keys[2])
229 else if (input == keys[3])
231 else if (input == keys[4])
233 else if (input == keys[5] || input == keys[6])
239 if (rot != rotation) {
240 ALOGI("orientation changed from %d to %d", rotation * 90, rot * 90);
243 if (enabled && count > 0)
246 } else if (iev.type == EV_KEY && iev.code == keys[1] && iev.value) {
247 if (rotation == ROT_270)
252 } else if (iev.type == EV_SW && iev.code == SW_TABLET_MODE) {
255 else if (rotation == ROT_0)
263 data[0] = orients[rotation];
264 t.tv_sec = t.tv_nsec = 0;
265 clock_gettime(CLOCK_MONOTONIC, &t);
266 data[0].timestamp = int64_t(t.tv_sec) * 1000000000LL + t.tv_nsec;
267 for (cnt = 1; cnt < keys[7] && cnt < count; ++cnt) {
268 data[cnt] = data[cnt - 1];
269 data[cnt].timestamp += delay.tv_nsec;
270 nanosleep(&delay, 0);
272 ALOGV("%s: dev=%p fd=%d rotation=%d cnt=%d", __FUNCTION__, this, pfd.fd, rotation * 90, cnt);
276 static int open_kbd_sensor(const struct hw_module_t *module, const char *id, struct hw_device_t **device)
278 ALOGD("%s: id=%s", __FUNCTION__, id);
279 return new SensorPollContext(module, device) ? 0 : -EINVAL;
282 static struct sensor_t sSensorListInit[] = {
284 name: "Kbd Orientation Sensor",
285 vendor: "Android-x86 Open Source Project",
287 handle: ID_ACCELERATION,
288 type: SENSOR_TYPE_ACCELEROMETER,
290 resolution: 1.0f/4032.0f,
293 fifoReservedEventCount: 0,
294 fifoMaxEventCount: 0,
299 static int sensors_get_sensors_list(struct sensors_module_t *module, struct sensor_t const **list)
301 *list = sSensorListInit;
302 return sizeof(sSensorListInit) / sizeof(struct sensor_t);
305 static struct hw_module_methods_t sensors_methods = {
306 open: open_kbd_sensor
309 struct sensors_module_t HAL_MODULE_INFO_SYM = {
311 tag: HARDWARE_MODULE_TAG,
314 id: SENSORS_HARDWARE_MODULE_ID,
315 name: "Kbd Orientation Sensor",
316 author: "Chih-Wei Huang",
317 methods: &sensors_methods,
321 get_sensors_list: sensors_get_sensors_list