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"
24 #include <cutils/log.h>
25 #include <linux/input.h>
26 #include <linux/uinput.h>
27 #include <hardware/sensors.h>
28 #include <cutils/properties.h>
30 struct KbdSensorKeys {
35 { "AT Translated Set 2 keyboard", { EV_KEY, KEY_UP, KEY_RIGHT, KEY_DOWN, KEY_LEFT, KEY_LEFTALT, KEY_LEFTCTRL, 1 } },
36 { "AT Translated Set 2 keyboard", { EV_MSC, 91, 115, 123, 109, KEY_LEFTALT, KEY_LEFTCTRL, 3 } },
37 { "AT Translated Set 2 keyboard", { EV_KEY, KEY_F5, KEY_F8, KEY_F6, KEY_F7, KEY_LEFTALT, KEY_LEFTCTRL, 1 } },
38 { "AT Translated Set 2 keyboard", { EV_KEY, KEY_F9, KEY_F12, KEY_F10, KEY_F11, KEY_LEFTALT, KEY_LEFTCTRL, 1 } },
39 { "Asus Laptop extra buttons", { EV_KEY, KEY_F9, KEY_F12, KEY_F10, KEY_F11, KEY_LEFTALT, KEY_LEFTCTRL, 2 } },
40 { "HP WMI hotkeys", { -1, KEY_DIRECTION, 0, 0, 0, 0, 0, 3 } },
43 const int ID_ACCELERATION = (SENSORS_HANDLE_BASE + 0);
45 template <typename T> struct SensorFd : T {
46 SensorFd(const struct hw_module_t *module);
49 template <typename T> SensorFd<T>::SensorFd(const struct hw_module_t *module)
51 memset(this, 0, sizeof(*this));
52 this->common.tag = HARDWARE_DEVICE_TAG;
53 this->common.version = SENSORS_DEVICE_API_VERSION_1_3;
54 this->common.module = const_cast<struct hw_module_t *>(module);
57 struct SensorPollContext : SensorFd<sensors_poll_device_1> {
59 SensorPollContext(const struct hw_module_t *module, struct hw_device_t **device);
61 bool isValid() const { return (pfd.fd >= 0); }
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 static int poll_batch(struct sensors_poll_device_1* dev, int sensor_handle, int flags, int64_t sampling_period_ns, int64_t max_report_latency_ns);
69 static int poll_flush(struct sensors_poll_device_1* dev, int sensor_handle);
71 int doPoll(sensors_event_t *data, int count);
82 int64_t sampling_period_ns;
84 sensors_event_t orients[4];
88 void parse_kbd_keys_from_prop(char *prop, KbdSensorKeys *ktype)
90 strlcpy(ktype->name, strsep(&prop, ","), sizeof(ktype->name));
91 sscanf(prop, "%d,%d,%d,%d,%d,%d,%d,%d", ktype->keys,
92 ktype->keys + 1, ktype->keys + 2, ktype->keys + 3, ktype->keys + 4, ktype->keys + 5, ktype->keys + 6, ktype->keys + 7);
93 ALOGD("[%s]: %d,%d,%d,...", ktype->name, ktype->keys[0], ktype->keys[1], ktype->keys[2]);
96 SensorPollContext::SensorPollContext(const struct hw_module_t *module, struct hw_device_t **device)
97 : SensorFd<sensors_poll_device_1>(module), enabled(false), rotation(ROT_0), ktype(KeysType)
99 common.close = poll_close;
100 activate = poll_activate;
101 setDelay = poll_setDelay;
108 const char *dirname = "/dev/input";
109 char prop[PROPERTY_VALUE_MAX];
110 if (property_get("hal.sensors.kbd.keys", prop, 0))
111 parse_kbd_keys_from_prop(prop, ktype);
112 else if (property_get("hal.sensors.kbd.type", prop, 0))
113 ktype = &KeysType[atoi(prop)];
116 if (DIR *dir = opendir(dirname)) {
118 while (struct dirent *de = readdir(dir)) {
119 if (de->d_name[0] != 'e') // not eventX
121 snprintf(name, PATH_MAX, "%s/%s", dirname, de->d_name);
122 fd = open(name, O_RDWR);
124 ALOGE("could not open %s, %s", name, strerror(errno));
127 name[sizeof(name) - 1] = '\0';
128 if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
129 ALOGE("could not get device name for %s, %s\n", name, strerror(errno));
134 if (!strcmp(name, ktype->name))
137 ktype = KeysType + (sizeof(KeysType) / sizeof(KeysType[0]));
138 while (--ktype != KeysType)
139 if (!strcmp(name, ktype->name))
141 if (ktype != KeysType)
151 ALOGW("could not find any kbdsensor device");
155 ALOGI("Open %s ok, fd=%d", name, fd);
159 orients[ROT_0].version = sizeof(sensors_event_t);
160 orients[ROT_0].sensor = ID_ACCELERATION;
161 orients[ROT_0].type = SENSOR_TYPE_ACCELEROMETER;
162 orients[ROT_0].acceleration.status = SENSOR_STATUS_ACCURACY_HIGH;
163 orients[ROT_270] = orients[ROT_180] = orients[ROT_90] = orients[ROT_0];
164 const double angle = 20.0;
165 const double cos_angle = GRAVITY_EARTH * cos(angle / M_PI);
166 const double sin_angle = GRAVITY_EARTH * sin(angle / M_PI);
167 orients[ROT_0].acceleration.x = 0.0;
168 orients[ROT_0].acceleration.y = cos_angle;
169 orients[ROT_0].acceleration.z = sin_angle;
170 orients[ROT_90].acceleration.x = cos_angle;
171 orients[ROT_90].acceleration.y = 0.0;
172 orients[ROT_90].acceleration.z = sin_angle;
173 orients[ROT_180].acceleration.x = 0.0;
174 orients[ROT_180].acceleration.y = -cos_angle;
175 orients[ROT_180].acceleration.z = -sin_angle;
176 orients[ROT_270].acceleration.x = -cos_angle;
177 orients[ROT_270].acceleration.y = 0.0;
178 orients[ROT_270].acceleration.z = -sin_angle;
180 ALOGD("%s: module=%p dev=%p fd=%d", __FUNCTION__, module, this, fd);
183 SensorPollContext::~SensorPollContext()
188 int SensorPollContext::poll_close(struct hw_device_t *dev)
190 ALOGD("%s: dev=%p", __FUNCTION__, dev);
191 delete reinterpret_cast<SensorPollContext *>(dev);
195 int SensorPollContext::poll_activate(struct sensors_poll_device_t *dev, int handle, int enabled)
197 ALOGD("%s: dev=%p handle=%d enabled=%d", __FUNCTION__, dev, handle, enabled);
198 SensorPollContext *ctx = reinterpret_cast<SensorPollContext *>(dev);
199 ctx->enabled = enabled;
203 int SensorPollContext::poll_setDelay(struct sensors_poll_device_t *dev, int handle, int64_t ns)
205 ALOGD("%s: dev=%p handle=%d ns=%" PRId64, __FUNCTION__, dev, handle, ns);
206 SensorPollContext *ctx = reinterpret_cast<SensorPollContext *>(dev);
207 ctx->sampling_period_ns = ns;
211 int SensorPollContext::poll_poll(struct sensors_poll_device_t *dev, sensors_event_t *data, int count)
213 ALOGV("%s: dev=%p data=%p count=%d", __FUNCTION__, dev, data, count);
214 SensorPollContext *ctx = reinterpret_cast<SensorPollContext *>(dev);
215 return ctx->doPoll(data, count);
218 int SensorPollContext::poll_batch(struct sensors_poll_device_1* dev, int sensor_handle, int flags, int64_t sampling_period_ns, int64_t max_report_latency_ns)
220 ALOGD("%s: dev=%p sensor_handle=%d flags=%d sampling_period_ns=%" PRId64 " max_report_latency_ns=%" PRId64,
221 __FUNCTION__, dev, sensor_handle, flags, sampling_period_ns, max_report_latency_ns);
222 return poll_setDelay(&dev->v0, sensor_handle, sampling_period_ns);
225 int SensorPollContext::poll_flush(struct sensors_poll_device_1* dev, int sensor_handle)
227 ALOGD("%s: dev=%p sensor_handle=%d", __FUNCTION__, dev, sensor_handle);
231 int SensorPollContext::doPoll(sensors_event_t *data, int count)
236 int *keys = ktype->keys;
237 while (int pollres = ::poll(&pfd, 1, -1)) {
239 ALOGE("%s: poll %d error: %s", __FUNCTION__, pfd.fd, strerror(errno));
242 if (!(pfd.revents & POLLIN)) {
243 ALOGW("%s: ignore revents %d", __FUNCTION__, pfd.revents);
247 struct input_event iev;
248 size_t res = ::read(pfd.fd, &iev, sizeof(iev));
249 if (res < sizeof(iev)) {
250 ALOGW("insufficient input data(%zu)? fd=%d", res, pfd.fd);
253 ALOGV("type=%d scancode=%d value=%d from fd=%d", iev.type, iev.code, iev.value, pfd.fd);
254 if (iev.type == keys[0]) {
256 int input = (keys[0] == EV_MSC) ? iev.value : iev.code;
257 if (input == keys[1])
259 else if (input == keys[2])
261 else if (input == keys[3])
263 else if (input == keys[4])
265 else if (input == keys[5] || input == keys[6])
271 if (rot != rotation) {
272 ALOGI("orientation changed from %d to %d", rotation * 90, rot * 90);
275 if (enabled && count > 0)
278 } else if (iev.type == EV_KEY) {
279 if (iev.code == keys[1] && iev.value) {
280 if (rotation == ROT_270)
285 if (iev.code == keys[2] && iev.value) {
286 if (rotation == ROT_0)
292 } else if (iev.type == EV_SW && iev.code == SW_TABLET_MODE) {
295 else if (rotation == ROT_0)
302 struct timespec t = { 0, 0 };
303 data[0] = orients[rotation];
304 clock_gettime(CLOCK_MONOTONIC, &t);
305 data[0].timestamp = int64_t(t.tv_sec) * 1000000000LL + t.tv_nsec;
306 struct timespec delay = { 0, static_cast<long>(sampling_period_ns) };
307 for (cnt = 1; !nanosleep(&delay, 0) && cnt < keys[7] && cnt < count; ++cnt) {
308 data[cnt] = data[cnt - 1];
309 data[cnt].timestamp += sampling_period_ns;
311 ALOGV("%s: dev=%p fd=%d rotation=%d cnt=%d", __FUNCTION__, this, pfd.fd, rotation * 90, cnt);
315 static int open_kbd_sensor(const struct hw_module_t *module, const char *id, struct hw_device_t **device)
317 ALOGD("%s: id=%s", __FUNCTION__, id);
318 SensorPollContext *ctx = new SensorPollContext(module, device);
319 return (ctx && ctx->isValid()) ? 0 : -EINVAL;
322 static struct sensor_t sSensorListInit[] = {
324 .name = "Kbd Orientation Sensor",
325 .vendor = "Android-x86 Open Source Project",
327 .handle = ID_ACCELERATION,
328 .type = SENSOR_TYPE_ACCELEROMETER,
330 .resolution = 1.0f/4032.0f,
333 .fifoReservedEventCount = 0,
334 .fifoMaxEventCount = 0,
336 .requiredPermission = 0,
338 .flags = SENSOR_FLAG_CONTINUOUS_MODE,
343 static int sensors_get_sensors_list(struct sensors_module_t *, struct sensor_t const **list)
345 *list = sSensorListInit;
346 return sizeof(sSensorListInit) / sizeof(struct sensor_t);
349 static struct hw_module_methods_t sensors_methods = {
350 .open = open_kbd_sensor
353 struct sensors_module_t HAL_MODULE_INFO_SYM = {
355 .tag = HARDWARE_MODULE_TAG,
356 .module_api_version = 2,
357 .hal_api_version = 0,
358 .id = SENSORS_HARDWARE_MODULE_ID,
359 .name = "Kbd Orientation Sensor",
360 .author = "Chih-Wei Huang",
361 .methods = &sensors_methods,
365 .get_sensors_list = sensors_get_sensors_list