blob: 9c7e7f4e96b559b802b29b1bda23eecc0a3fd925 [file] [log] [blame]
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001//
2// Copyright 2005 The Android Open Source Project
3//
4// Handle events, like key input and vsync.
5//
6// The goal is to provide an optimized solution for Linux, not an
7// implementation that works well across all platforms. We expect
8// events to arrive on file descriptors, so that we can use a select()
9// select() call to sleep.
10//
11// We can't select() on anything but network sockets in Windows, so we
12// provide an alternative implementation of waitEvent for that platform.
13//
14#define LOG_TAG "EventHub"
15
16//#define LOG_NDEBUG 0
17
18#include <ui/EventHub.h>
Dianne Hackbornc5917362009-08-04 05:49:43 -070019#include <ui/KeycodeLabels.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080020#include <hardware_legacy/power.h>
21
22#include <cutils/properties.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080023#include <utils/Log.h>
24#include <utils/Timers.h>
Mathias Agopiane0c32202009-05-31 19:13:00 -070025#include <utils/threads.h>
Mathias Agopiane0c32202009-05-31 19:13:00 -070026#include <utils/Errors.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080027
28#include <stdlib.h>
29#include <stdio.h>
30#include <unistd.h>
31#include <fcntl.h>
32#include <memory.h>
33#include <errno.h>
34#include <assert.h>
35
36#include "KeyLayoutMap.h"
37
38#include <string.h>
39#include <stdint.h>
40#include <dirent.h>
41#ifdef HAVE_INOTIFY
42# include <sys/inotify.h>
43#endif
44#ifdef HAVE_ANDROID_OS
45# include <sys/limits.h> /* not part of Linux */
46#endif
47#include <sys/poll.h>
48#include <sys/ioctl.h>
49
50/* this macro is used to tell if "bit" is set in "array"
51 * it selects a byte from the array, and does a boolean AND
52 * operation with a byte that only has the relevant bit set.
53 * eg. to check for the 12th bit, we do (array[1] & 1<<4)
54 */
55#define test_bit(bit, array) (array[bit/8] & (1<<(bit%8)))
56
Jeff Brown8575a872010-06-30 16:10:35 -070057/* this macro computes the number of bytes needed to represent a bit array of the specified size */
58#define sizeof_bit_array(bits) ((bits + 7) / 8)
59
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080060#define ID_MASK 0x0000ffff
61#define SEQ_MASK 0x7fff0000
62#define SEQ_SHIFT 16
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080063
Dianne Hackbornc5917362009-08-04 05:49:43 -070064#ifndef ABS_MT_TOUCH_MAJOR
65#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
66#endif
67
68#ifndef ABS_MT_POSITION_X
69#define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */
70#endif
71
72#ifndef ABS_MT_POSITION_Y
73#define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */
74#endif
75
Jeff Brown2806e382010-10-01 17:46:21 -070076#define INDENT " "
77#define INDENT2 " "
78#define INDENT3 " "
79
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080080namespace android {
81
82static const char *WAKE_LOCK_ID = "KeyEvents";
83static const char *device_path = "/dev/input";
84
85/* return the larger integer */
86static inline int max(int v1, int v2)
87{
88 return (v1 > v2) ? v1 : v2;
89}
90
Jeff Brown2806e382010-10-01 17:46:21 -070091static inline const char* toString(bool value) {
92 return value ? "true" : "false";
93}
94
Iliyan Malchev34193b32009-08-06 14:50:08 -070095EventHub::device_t::device_t(int32_t _id, const char* _path, const char* name)
96 : id(_id), path(_path), name(name), classes(0)
Jeff Brown6a817e22010-09-12 17:55:08 -070097 , keyBitmask(NULL), layoutMap(new KeyLayoutMap()), defaultKeyMap(false), fd(-1), next(NULL) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080098}
99
100EventHub::device_t::~device_t() {
101 delete [] keyBitmask;
102 delete layoutMap;
103}
104
105EventHub::EventHub(void)
Jeff Brown6a817e22010-09-12 17:55:08 -0700106 : mError(NO_INIT), mHaveFirstKeyboard(false), mFirstKeyboardId(-1)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800107 , mDevicesById(0), mNumDevicesById(0)
108 , mOpeningDevices(0), mClosingDevices(0)
Jeff Brown1ad00e92010-10-01 18:55:43 -0700109 , mDevices(0), mFDs(0), mFDCount(0), mOpened(false), mNeedToSendFinishedDeviceScan(false)
Jeff Brown82763072010-08-17 16:48:25 -0700110 , mInputBufferIndex(0), mInputBufferCount(0), mInputDeviceIndex(0)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800111{
112 acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
113#ifdef EV_SW
114 memset(mSwitches, 0, sizeof(mSwitches));
115#endif
116}
117
118/*
119 * Clean up.
120 */
121EventHub::~EventHub(void)
122{
123 release_wake_lock(WAKE_LOCK_ID);
124 // we should free stuff here...
125}
126
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800127status_t EventHub::errorCheck() const
128{
129 return mError;
130}
131
132String8 EventHub::getDeviceName(int32_t deviceId) const
133{
134 AutoMutex _l(mLock);
Jeff Brown2806e382010-10-01 17:46:21 -0700135 device_t* device = getDeviceLocked(deviceId);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800136 if (device == NULL) return String8();
137 return device->name;
138}
139
140uint32_t EventHub::getDeviceClasses(int32_t deviceId) const
141{
142 AutoMutex _l(mLock);
Jeff Brown2806e382010-10-01 17:46:21 -0700143 device_t* device = getDeviceLocked(deviceId);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800144 if (device == NULL) return 0;
145 return device->classes;
146}
147
Jeff Browne57e8952010-07-23 21:28:06 -0700148status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis,
149 RawAbsoluteAxisInfo* outAxisInfo) const {
Jeff Brown38a7fab2010-08-30 03:02:23 -0700150 outAxisInfo->clear();
Jeff Browne57e8952010-07-23 21:28:06 -0700151
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800152 AutoMutex _l(mLock);
Jeff Brown2806e382010-10-01 17:46:21 -0700153 device_t* device = getDeviceLocked(deviceId);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800154 if (device == NULL) return -1;
155
156 struct input_absinfo info;
157
Jens Gulin7dcaa582010-06-22 22:21:57 +0200158 if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
Jeff Browne57e8952010-07-23 21:28:06 -0700159 LOGW("Error reading absolute controller %d for device %s fd %d\n",
Jens Gulin7dcaa582010-06-22 22:21:57 +0200160 axis, device->name.string(), device->fd);
Jeff Browne57e8952010-07-23 21:28:06 -0700161 return -errno;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800162 }
Jeff Browne57e8952010-07-23 21:28:06 -0700163
164 if (info.minimum != info.maximum) {
165 outAxisInfo->valid = true;
166 outAxisInfo->minValue = info.minimum;
167 outAxisInfo->maxValue = info.maximum;
168 outAxisInfo->flat = info.flat;
169 outAxisInfo->fuzz = info.fuzz;
170 }
171 return OK;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800172}
173
Jeff Browne57e8952010-07-23 21:28:06 -0700174int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const {
Jeff Browne839a582010-04-22 18:58:52 -0700175 if (scanCode >= 0 && scanCode <= KEY_MAX) {
176 AutoMutex _l(mLock);
177
Jeff Brown2806e382010-10-01 17:46:21 -0700178 device_t* device = getDeviceLocked(deviceId);
Jeff Browne57e8952010-07-23 21:28:06 -0700179 if (device != NULL) {
180 return getScanCodeStateLocked(device, scanCode);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800181 }
182 }
Jeff Brown5c1ed842010-07-14 18:48:53 -0700183 return AKEY_STATE_UNKNOWN;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800184}
185
Jeff Browne839a582010-04-22 18:58:52 -0700186int32_t EventHub::getScanCodeStateLocked(device_t* device, int32_t scanCode) const {
Jeff Brown8575a872010-06-30 16:10:35 -0700187 uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
Jeff Browne839a582010-04-22 18:58:52 -0700188 memset(key_bitmask, 0, sizeof(key_bitmask));
Jens Gulin7dcaa582010-06-22 22:21:57 +0200189 if (ioctl(device->fd,
Jeff Browne839a582010-04-22 18:58:52 -0700190 EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
Jeff Brown5c1ed842010-07-14 18:48:53 -0700191 return test_bit(scanCode, key_bitmask) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
Jeff Browne839a582010-04-22 18:58:52 -0700192 }
Jeff Brown5c1ed842010-07-14 18:48:53 -0700193 return AKEY_STATE_UNKNOWN;
Jeff Browne839a582010-04-22 18:58:52 -0700194}
195
Jeff Browne57e8952010-07-23 21:28:06 -0700196int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const {
197 AutoMutex _l(mLock);
Jeff Browne839a582010-04-22 18:58:52 -0700198
Jeff Brown2806e382010-10-01 17:46:21 -0700199 device_t* device = getDeviceLocked(deviceId);
Jeff Browne57e8952010-07-23 21:28:06 -0700200 if (device != NULL) {
201 return getKeyCodeStateLocked(device, keyCode);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800202 }
Jeff Brown5c1ed842010-07-14 18:48:53 -0700203 return AKEY_STATE_UNKNOWN;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800204}
205
Jeff Browne839a582010-04-22 18:58:52 -0700206int32_t EventHub::getKeyCodeStateLocked(device_t* device, int32_t keyCode) const {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800207 Vector<int32_t> scanCodes;
Jeff Browne839a582010-04-22 18:58:52 -0700208 device->layoutMap->findScancodes(keyCode, &scanCodes);
209
Jeff Brown8575a872010-06-30 16:10:35 -0700210 uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800211 memset(key_bitmask, 0, sizeof(key_bitmask));
Jens Gulin7dcaa582010-06-22 22:21:57 +0200212 if (ioctl(device->fd, EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800213 #if 0
214 for (size_t i=0; i<=KEY_MAX; i++) {
215 LOGI("(Scan code %d: down=%d)", i, test_bit(i, key_bitmask));
216 }
217 #endif
218 const size_t N = scanCodes.size();
219 for (size_t i=0; i<N && i<=KEY_MAX; i++) {
220 int32_t sc = scanCodes.itemAt(i);
221 //LOGI("Code %d: down=%d", sc, test_bit(sc, key_bitmask));
222 if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, key_bitmask)) {
Jeff Brown5c1ed842010-07-14 18:48:53 -0700223 return AKEY_STATE_DOWN;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800224 }
225 }
Jeff Brown5c1ed842010-07-14 18:48:53 -0700226 return AKEY_STATE_UP;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800227 }
Jeff Brown5c1ed842010-07-14 18:48:53 -0700228 return AKEY_STATE_UNKNOWN;
Jeff Browne839a582010-04-22 18:58:52 -0700229}
230
Jeff Browne57e8952010-07-23 21:28:06 -0700231int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const {
Jeff Browne839a582010-04-22 18:58:52 -0700232#ifdef EV_SW
233 if (sw >= 0 && sw <= SW_MAX) {
234 AutoMutex _l(mLock);
235
Jeff Brown2806e382010-10-01 17:46:21 -0700236 device_t* device = getDeviceLocked(deviceId);
Jeff Browne57e8952010-07-23 21:28:06 -0700237 if (device != NULL) {
238 return getSwitchStateLocked(device, sw);
Jeff Browne839a582010-04-22 18:58:52 -0700239 }
Jeff Browne839a582010-04-22 18:58:52 -0700240 }
241#endif
Jeff Brown5c1ed842010-07-14 18:48:53 -0700242 return AKEY_STATE_UNKNOWN;
Jeff Browne839a582010-04-22 18:58:52 -0700243}
244
245int32_t EventHub::getSwitchStateLocked(device_t* device, int32_t sw) const {
Jeff Brown8575a872010-06-30 16:10:35 -0700246 uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)];
Jeff Browne839a582010-04-22 18:58:52 -0700247 memset(sw_bitmask, 0, sizeof(sw_bitmask));
Jens Gulin7dcaa582010-06-22 22:21:57 +0200248 if (ioctl(device->fd,
Jeff Browne839a582010-04-22 18:58:52 -0700249 EVIOCGSW(sizeof(sw_bitmask)), sw_bitmask) >= 0) {
Jeff Brown5c1ed842010-07-14 18:48:53 -0700250 return test_bit(sw, sw_bitmask) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
Jeff Browne839a582010-04-22 18:58:52 -0700251 }
Jeff Brown5c1ed842010-07-14 18:48:53 -0700252 return AKEY_STATE_UNKNOWN;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800253}
254
Jeff Browne57e8952010-07-23 21:28:06 -0700255bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes,
256 const int32_t* keyCodes, uint8_t* outFlags) const {
257 AutoMutex _l(mLock);
258
Jeff Brown2806e382010-10-01 17:46:21 -0700259 device_t* device = getDeviceLocked(deviceId);
Jeff Browne57e8952010-07-23 21:28:06 -0700260 if (device != NULL) {
261 return markSupportedKeyCodesLocked(device, numCodes, keyCodes, outFlags);
262 }
263 return false;
264}
265
266bool EventHub::markSupportedKeyCodesLocked(device_t* device, size_t numCodes,
267 const int32_t* keyCodes, uint8_t* outFlags) const {
268 if (device->layoutMap == NULL || device->keyBitmask == NULL) {
269 return false;
270 }
271
272 Vector<int32_t> scanCodes;
273 for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) {
274 scanCodes.clear();
275
276 status_t err = device->layoutMap->findScancodes(keyCodes[codeIndex], &scanCodes);
277 if (! err) {
278 // check the possible scan codes identified by the layout map against the
279 // map of codes actually emitted by the driver
280 for (size_t sc = 0; sc < scanCodes.size(); sc++) {
281 if (test_bit(scanCodes[sc], device->keyBitmask)) {
282 outFlags[codeIndex] = 1;
283 break;
284 }
285 }
286 }
287 }
288 return true;
289}
290
Dianne Hackbornc968c3a2009-07-14 12:06:54 -0700291status_t EventHub::scancodeToKeycode(int32_t deviceId, int scancode,
292 int32_t* outKeycode, uint32_t* outFlags) const
293{
294 AutoMutex _l(mLock);
Jeff Brown2806e382010-10-01 17:46:21 -0700295 device_t* device = getDeviceLocked(deviceId);
Dianne Hackbornc968c3a2009-07-14 12:06:54 -0700296
297 if (device != NULL && device->layoutMap != NULL) {
298 status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
299 if (err == NO_ERROR) {
300 return NO_ERROR;
301 }
302 }
303
304 if (mHaveFirstKeyboard) {
Jeff Brown2806e382010-10-01 17:46:21 -0700305 device = getDeviceLocked(mFirstKeyboardId);
Dianne Hackbornc968c3a2009-07-14 12:06:54 -0700306
307 if (device != NULL && device->layoutMap != NULL) {
308 status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
309 if (err == NO_ERROR) {
310 return NO_ERROR;
311 }
312 }
313 }
314
315 *outKeycode = 0;
316 *outFlags = 0;
317 return NAME_NOT_FOUND;
318}
319
Mike Lockwoodb4411062009-07-16 11:11:18 -0400320void EventHub::addExcludedDevice(const char* deviceName)
321{
Jeff Brown2806e382010-10-01 17:46:21 -0700322 AutoMutex _l(mLock);
323
Mike Lockwoodb4411062009-07-16 11:11:18 -0400324 String8 name(deviceName);
325 mExcludedDevices.push_back(name);
326}
327
Jeff Brown6a817e22010-09-12 17:55:08 -0700328bool EventHub::hasLed(int32_t deviceId, int32_t led) const {
329 AutoMutex _l(mLock);
330 device_t* device = getDeviceLocked(deviceId);
331 if (device) {
332 uint8_t bitmask[sizeof_bit_array(LED_MAX + 1)];
333 memset(bitmask, 0, sizeof(bitmask));
334 if (ioctl(device->fd, EVIOCGBIT(EV_LED, sizeof(bitmask)), bitmask) >= 0) {
335 if (test_bit(led, bitmask)) {
336 return true;
337 }
338 }
339 }
340 return false;
341}
342
343void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) {
344 AutoMutex _l(mLock);
345 device_t* device = getDeviceLocked(deviceId);
346 if (device) {
347 struct input_event ev;
348 ev.time.tv_sec = 0;
349 ev.time.tv_usec = 0;
350 ev.type = EV_LED;
351 ev.code = led;
352 ev.value = on ? 1 : 0;
353
354 ssize_t nWrite;
355 do {
356 nWrite = write(device->fd, &ev, sizeof(struct input_event));
357 } while (nWrite == -1 && errno == EINTR);
358 }
359}
360
Jeff Brown2806e382010-10-01 17:46:21 -0700361EventHub::device_t* EventHub::getDeviceLocked(int32_t deviceId) const
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800362{
363 if (deviceId == 0) deviceId = mFirstKeyboardId;
364 int32_t id = deviceId & ID_MASK;
365 if (id >= mNumDevicesById || id < 0) return NULL;
366 device_t* dev = mDevicesById[id].device;
Dianne Hackbornc3aa00b2009-03-25 16:21:55 -0700367 if (dev == NULL) return NULL;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800368 if (dev->id == deviceId) {
369 return dev;
370 }
371 return NULL;
372}
373
Jeff Browne57e8952010-07-23 21:28:06 -0700374bool EventHub::getEvent(RawEvent* outEvent)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800375{
Jeff Browne57e8952010-07-23 21:28:06 -0700376 outEvent->deviceId = 0;
377 outEvent->type = 0;
378 outEvent->scanCode = 0;
379 outEvent->keyCode = 0;
380 outEvent->flags = 0;
381 outEvent->value = 0;
382 outEvent->when = 0;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800383
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800384 // Note that we only allow one caller to getEvent(), so don't need
385 // to do locking here... only when adding/removing devices.
Mike Lockwoodb4411062009-07-16 11:11:18 -0400386
387 if (!mOpened) {
388 mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
389 mOpened = true;
Jeff Brown1ad00e92010-10-01 18:55:43 -0700390 mNeedToSendFinishedDeviceScan = true;
Mike Lockwoodb4411062009-07-16 11:11:18 -0400391 }
392
Jeff Brown82763072010-08-17 16:48:25 -0700393 for (;;) {
394 // Report any devices that had last been added/removed.
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800395 if (mClosingDevices != NULL) {
396 device_t* device = mClosingDevices;
397 LOGV("Reporting device closed: id=0x%x, name=%s\n",
398 device->id, device->path.string());
399 mClosingDevices = device->next;
Jeff Browne57e8952010-07-23 21:28:06 -0700400 if (device->id == mFirstKeyboardId) {
401 outEvent->deviceId = 0;
402 } else {
403 outEvent->deviceId = device->id;
404 }
405 outEvent->type = DEVICE_REMOVED;
Jeff Brown3c3cc622010-10-20 15:33:38 -0700406 outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800407 delete device;
Jeff Brown1ad00e92010-10-01 18:55:43 -0700408 mNeedToSendFinishedDeviceScan = true;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800409 return true;
410 }
Jeff Browne57e8952010-07-23 21:28:06 -0700411
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800412 if (mOpeningDevices != NULL) {
413 device_t* device = mOpeningDevices;
414 LOGV("Reporting device opened: id=0x%x, name=%s\n",
415 device->id, device->path.string());
416 mOpeningDevices = device->next;
Jeff Browne57e8952010-07-23 21:28:06 -0700417 if (device->id == mFirstKeyboardId) {
418 outEvent->deviceId = 0;
419 } else {
420 outEvent->deviceId = device->id;
421 }
422 outEvent->type = DEVICE_ADDED;
Jeff Brown3c3cc622010-10-20 15:33:38 -0700423 outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
Jeff Brown1ad00e92010-10-01 18:55:43 -0700424 mNeedToSendFinishedDeviceScan = true;
425 return true;
426 }
427
428 if (mNeedToSendFinishedDeviceScan) {
429 mNeedToSendFinishedDeviceScan = false;
430 outEvent->type = FINISHED_DEVICE_SCAN;
Jeff Brown3c3cc622010-10-20 15:33:38 -0700431 outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800432 return true;
433 }
434
Jeff Brown82763072010-08-17 16:48:25 -0700435 // Grab the next input event.
436 for (;;) {
437 // Consume buffered input events, if any.
438 if (mInputBufferIndex < mInputBufferCount) {
439 const struct input_event& iev = mInputBufferData[mInputBufferIndex++];
440 const device_t* device = mDevices[mInputDeviceIndex];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800441
Jeff Brown82763072010-08-17 16:48:25 -0700442 LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d", device->path.string(),
443 (int) iev.time.tv_sec, (int) iev.time.tv_usec, iev.type, iev.code, iev.value);
444 if (device->id == mFirstKeyboardId) {
445 outEvent->deviceId = 0;
446 } else {
447 outEvent->deviceId = device->id;
448 }
449 outEvent->type = iev.type;
450 outEvent->scanCode = iev.code;
451 if (iev.type == EV_KEY) {
452 status_t err = device->layoutMap->map(iev.code,
453 & outEvent->keyCode, & outEvent->flags);
454 LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
455 iev.code, outEvent->keyCode, outEvent->flags, err);
456 if (err != 0) {
457 outEvent->keyCode = AKEYCODE_UNKNOWN;
458 outEvent->flags = 0;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800459 }
Jeff Brown82763072010-08-17 16:48:25 -0700460 } else {
461 outEvent->keyCode = iev.code;
462 }
463 outEvent->value = iev.value;
464
465 // Use an event timestamp in the same timebase as
466 // java.lang.System.nanoTime() and android.os.SystemClock.uptimeMillis()
467 // as expected by the rest of the system.
468 outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
469 return true;
470 }
471
472 // Finish reading all events from devices identified in previous poll().
473 // This code assumes that mInputDeviceIndex is initially 0 and that the
474 // revents member of pollfd is initialized to 0 when the device is first added.
475 // Since mFDs[0] is used for inotify, we process regular events starting at index 1.
476 mInputDeviceIndex += 1;
477 if (mInputDeviceIndex >= mFDCount) {
Jeff Brown82763072010-08-17 16:48:25 -0700478 break;
479 }
480
Jeff Brown7e40f362010-10-14 02:23:43 -0700481 const struct pollfd& pfd = mFDs[mInputDeviceIndex];
Jeff Brown82763072010-08-17 16:48:25 -0700482 if (pfd.revents & POLLIN) {
483 int32_t readSize = read(pfd.fd, mInputBufferData,
484 sizeof(struct input_event) * INPUT_BUFFER_SIZE);
485 if (readSize < 0) {
486 if (errno != EAGAIN && errno != EINTR) {
487 LOGW("could not get event (errno=%d)", errno);
488 }
489 } else if ((readSize % sizeof(struct input_event)) != 0) {
490 LOGE("could not get event (wrong size: %d)", readSize);
491 } else {
492 mInputBufferCount = readSize / sizeof(struct input_event);
493 mInputBufferIndex = 0;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800494 }
495 }
496 }
Jeff Brown82763072010-08-17 16:48:25 -0700497
Jeff Brown7e40f362010-10-14 02:23:43 -0700498#if HAVE_INOTIFY
Jeff Brown1ad00e92010-10-01 18:55:43 -0700499 // readNotify() will modify mFDs and mFDCount, so this must be done after
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800500 // processing all other events.
501 if(mFDs[0].revents & POLLIN) {
Jeff Brown1ad00e92010-10-01 18:55:43 -0700502 readNotify(mFDs[0].fd);
Jeff Brown7e40f362010-10-14 02:23:43 -0700503 mFDs[0].revents = 0;
504 continue; // report added or removed devices immediately
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800505 }
Jeff Brown7e40f362010-10-14 02:23:43 -0700506#endif
507
508 mInputDeviceIndex = 0;
Jeff Brown82763072010-08-17 16:48:25 -0700509
510 // Poll for events. Mind the wake lock dance!
511 // We hold a wake lock at all times except during poll(). This works due to some
512 // subtle choreography. When a device driver has pending (unread) events, it acquires
513 // a kernel wake lock. However, once the last pending event has been read, the device
514 // driver will release the kernel wake lock. To prevent the system from going to sleep
515 // when this happens, the EventHub holds onto its own user wake lock while the client
516 // is processing events. Thus the system can only sleep if there are no events
517 // pending or currently being processed.
518 release_wake_lock(WAKE_LOCK_ID);
519
520 int pollResult = poll(mFDs, mFDCount, -1);
521
522 acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
523
524 if (pollResult <= 0) {
525 if (errno != EINTR) {
Jeff Brown7e40f362010-10-14 02:23:43 -0700526 LOGW("poll failed (errno=%d)\n", errno);
Jeff Brown82763072010-08-17 16:48:25 -0700527 usleep(100000);
528 }
529 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800530 }
531}
532
533/*
534 * Open the platform-specific input device.
535 */
536bool EventHub::openPlatformInput(void)
537{
538 /*
539 * Open platform-specific input device(s).
540 */
541 int res;
542
543 mFDCount = 1;
544 mFDs = (pollfd *)calloc(1, sizeof(mFDs[0]));
545 mDevices = (device_t **)calloc(1, sizeof(mDevices[0]));
546 mFDs[0].events = POLLIN;
Jeff Brown82763072010-08-17 16:48:25 -0700547 mFDs[0].revents = 0;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800548 mDevices[0] = NULL;
549#ifdef HAVE_INOTIFY
550 mFDs[0].fd = inotify_init();
551 res = inotify_add_watch(mFDs[0].fd, device_path, IN_DELETE | IN_CREATE);
552 if(res < 0) {
553 LOGE("could not add watch for %s, %s\n", device_path, strerror(errno));
554 }
555#else
556 /*
557 * The code in EventHub::getEvent assumes that mFDs[0] is an inotify fd.
558 * We allocate space for it and set it to something invalid.
559 */
560 mFDs[0].fd = -1;
561#endif
562
Jeff Brown1ad00e92010-10-01 18:55:43 -0700563 res = scanDir(device_path);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800564 if(res < 0) {
565 LOGE("scan dir failed for %s\n", device_path);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800566 }
567
568 return true;
569}
570
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800571// ----------------------------------------------------------------------------
572
Jeff Brown8575a872010-06-30 16:10:35 -0700573static bool containsNonZeroByte(const uint8_t* array, uint32_t startIndex, uint32_t endIndex) {
574 const uint8_t* end = array + endIndex;
575 array += startIndex;
576 while (array != end) {
577 if (*(array++) != 0) {
578 return true;
579 }
580 }
581 return false;
582}
583
584static const int32_t GAMEPAD_KEYCODES[] = {
585 AKEYCODE_BUTTON_A, AKEYCODE_BUTTON_B, AKEYCODE_BUTTON_C,
586 AKEYCODE_BUTTON_X, AKEYCODE_BUTTON_Y, AKEYCODE_BUTTON_Z,
587 AKEYCODE_BUTTON_L1, AKEYCODE_BUTTON_R1,
588 AKEYCODE_BUTTON_L2, AKEYCODE_BUTTON_R2,
589 AKEYCODE_BUTTON_THUMBL, AKEYCODE_BUTTON_THUMBR,
590 AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE
591};
592
Jeff Brown1ad00e92010-10-01 18:55:43 -0700593int EventHub::openDevice(const char *deviceName) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800594 int version;
595 int fd;
596 struct pollfd *new_mFDs;
597 device_t **new_devices;
598 char **new_device_names;
599 char name[80];
600 char location[80];
601 char idstr[80];
602 struct input_id id;
603
604 LOGV("Opening device: %s", deviceName);
605
606 AutoMutex _l(mLock);
Nick Pellyc81bb202010-01-20 19:36:49 -0800607
Nick Pelly1b5cf322010-01-26 10:27:15 -0800608 fd = open(deviceName, O_RDWR);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800609 if(fd < 0) {
610 LOGE("could not open %s, %s\n", deviceName, strerror(errno));
611 return -1;
612 }
613
614 if(ioctl(fd, EVIOCGVERSION, &version)) {
615 LOGE("could not get driver version for %s, %s\n", deviceName, strerror(errno));
616 return -1;
617 }
618 if(ioctl(fd, EVIOCGID, &id)) {
619 LOGE("could not get driver id for %s, %s\n", deviceName, strerror(errno));
620 return -1;
621 }
622 name[sizeof(name) - 1] = '\0';
623 location[sizeof(location) - 1] = '\0';
624 idstr[sizeof(idstr) - 1] = '\0';
625 if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
626 //fprintf(stderr, "could not get device name for %s, %s\n", deviceName, strerror(errno));
627 name[0] = '\0';
628 }
Mike Lockwood24a7e042009-07-17 00:10:10 -0400629
630 // check to see if the device is on our excluded list
631 List<String8>::iterator iter = mExcludedDevices.begin();
632 List<String8>::iterator end = mExcludedDevices.end();
633 for ( ; iter != end; iter++) {
634 const char* test = *iter;
635 if (strcmp(name, test) == 0) {
636 LOGI("ignoring event id %s driver %s\n", deviceName, test);
637 close(fd);
Mike Lockwood24a7e042009-07-17 00:10:10 -0400638 return -1;
639 }
640 }
641
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800642 if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
643 //fprintf(stderr, "could not get location for %s, %s\n", deviceName, strerror(errno));
644 location[0] = '\0';
645 }
646 if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
647 //fprintf(stderr, "could not get idstring for %s, %s\n", deviceName, strerror(errno));
648 idstr[0] = '\0';
649 }
650
Jeff Brown82763072010-08-17 16:48:25 -0700651 if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
652 LOGE("Error %d making device file descriptor non-blocking.", errno);
653 close(fd);
654 return -1;
655 }
656
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800657 int devid = 0;
658 while (devid < mNumDevicesById) {
659 if (mDevicesById[devid].device == NULL) {
660 break;
661 }
662 devid++;
663 }
664 if (devid >= mNumDevicesById) {
665 device_ent* new_devids = (device_ent*)realloc(mDevicesById,
666 sizeof(mDevicesById[0]) * (devid + 1));
667 if (new_devids == NULL) {
668 LOGE("out of memory");
669 return -1;
670 }
671 mDevicesById = new_devids;
672 mNumDevicesById = devid+1;
673 mDevicesById[devid].device = NULL;
674 mDevicesById[devid].seq = 0;
675 }
676
677 mDevicesById[devid].seq = (mDevicesById[devid].seq+(1<<SEQ_SHIFT))&SEQ_MASK;
678 if (mDevicesById[devid].seq == 0) {
679 mDevicesById[devid].seq = 1<<SEQ_SHIFT;
680 }
681
682 new_mFDs = (pollfd*)realloc(mFDs, sizeof(mFDs[0]) * (mFDCount + 1));
683 new_devices = (device_t**)realloc(mDevices, sizeof(mDevices[0]) * (mFDCount + 1));
684 if (new_mFDs == NULL || new_devices == NULL) {
685 LOGE("out of memory");
686 return -1;
687 }
688 mFDs = new_mFDs;
689 mDevices = new_devices;
690
691#if 0
692 LOGI("add device %d: %s\n", mFDCount, deviceName);
693 LOGI(" bus: %04x\n"
694 " vendor %04x\n"
695 " product %04x\n"
696 " version %04x\n",
697 id.bustype, id.vendor, id.product, id.version);
698 LOGI(" name: \"%s\"\n", name);
699 LOGI(" location: \"%s\"\n"
700 " id: \"%s\"\n", location, idstr);
701 LOGI(" version: %d.%d.%d\n",
702 version >> 16, (version >> 8) & 0xff, version & 0xff);
703#endif
704
Iliyan Malchev34193b32009-08-06 14:50:08 -0700705 device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName, name);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800706 if (device == NULL) {
707 LOGE("out of memory");
708 return -1;
709 }
710
Jens Gulin7dcaa582010-06-22 22:21:57 +0200711 device->fd = fd;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800712 mFDs[mFDCount].fd = fd;
713 mFDs[mFDCount].events = POLLIN;
Jeff Brown82763072010-08-17 16:48:25 -0700714 mFDs[mFDCount].revents = 0;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800715
Jeff Brown8575a872010-06-30 16:10:35 -0700716 // Figure out the kinds of events the device reports.
Dianne Hackbornc5917362009-08-04 05:49:43 -0700717
Jeff Brown8575a872010-06-30 16:10:35 -0700718 uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800719 memset(key_bitmask, 0, sizeof(key_bitmask));
Jeff Brown8575a872010-06-30 16:10:35 -0700720
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800721 LOGV("Getting keys...");
722 if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) {
723 //LOGI("MAP\n");
Jeff Brown8575a872010-06-30 16:10:35 -0700724 //for (int i = 0; i < sizeof(key_bitmask); i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800725 // LOGI("%d: 0x%02x\n", i, key_bitmask[i]);
726 //}
Jeff Brown8575a872010-06-30 16:10:35 -0700727
728 // See if this is a keyboard. Ignore everything in the button range except for
729 // gamepads which are also considered keyboards.
730 if (containsNonZeroByte(key_bitmask, 0, sizeof_bit_array(BTN_MISC))
731 || containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_GAMEPAD),
732 sizeof_bit_array(BTN_DIGI))
733 || containsNonZeroByte(key_bitmask, sizeof_bit_array(KEY_OK),
734 sizeof_bit_array(KEY_MAX + 1))) {
735 device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
736
Dianne Hackbornc5917362009-08-04 05:49:43 -0700737 device->keyBitmask = new uint8_t[sizeof(key_bitmask)];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800738 if (device->keyBitmask != NULL) {
739 memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
740 } else {
741 delete device;
742 LOGE("out of memory allocating key bitmask");
743 return -1;
744 }
745 }
746 }
Dianne Hackbornc5917362009-08-04 05:49:43 -0700747
Jeff Brown8575a872010-06-30 16:10:35 -0700748 // See if this is a trackball (or mouse).
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800749 if (test_bit(BTN_MOUSE, key_bitmask)) {
Jeff Brown8575a872010-06-30 16:10:35 -0700750 uint8_t rel_bitmask[sizeof_bit_array(REL_MAX + 1)];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800751 memset(rel_bitmask, 0, sizeof(rel_bitmask));
752 LOGV("Getting relative controllers...");
Jeff Brown8575a872010-06-30 16:10:35 -0700753 if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800754 if (test_bit(REL_X, rel_bitmask) && test_bit(REL_Y, rel_bitmask)) {
Jeff Browne839a582010-04-22 18:58:52 -0700755 device->classes |= INPUT_DEVICE_CLASS_TRACKBALL;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800756 }
757 }
758 }
Jeff Brown8575a872010-06-30 16:10:35 -0700759
760 // See if this is a touch pad.
761 uint8_t abs_bitmask[sizeof_bit_array(ABS_MAX + 1)];
Dianne Hackbornc5917362009-08-04 05:49:43 -0700762 memset(abs_bitmask, 0, sizeof(abs_bitmask));
763 LOGV("Getting absolute controllers...");
Jeff Brown8575a872010-06-30 16:10:35 -0700764 if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0) {
765 // Is this a new modern multi-touch driver?
Jeff Brown38a7fab2010-08-30 03:02:23 -0700766 if (test_bit(ABS_MT_POSITION_X, abs_bitmask)
Jeff Brown8575a872010-06-30 16:10:35 -0700767 && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) {
768 device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT;
769
770 // Is this an old style single-touch driver?
771 } else if (test_bit(BTN_TOUCH, key_bitmask)
772 && test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {
773 device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN;
774 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800775 }
776
777#ifdef EV_SW
778 // figure out the switches this device reports
Jeff Brown8575a872010-06-30 16:10:35 -0700779 uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800780 memset(sw_bitmask, 0, sizeof(sw_bitmask));
Jeff Browne57e8952010-07-23 21:28:06 -0700781 bool hasSwitches = false;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800782 if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask) >= 0) {
783 for (int i=0; i<EV_SW; i++) {
784 //LOGI("Device 0x%x sw %d: has=%d", device->id, i, test_bit(i, sw_bitmask));
785 if (test_bit(i, sw_bitmask)) {
Jeff Browne57e8952010-07-23 21:28:06 -0700786 hasSwitches = true;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800787 if (mSwitches[i] == 0) {
788 mSwitches[i] = device->id;
789 }
790 }
791 }
792 }
Jeff Browne57e8952010-07-23 21:28:06 -0700793 if (hasSwitches) {
794 device->classes |= INPUT_DEVICE_CLASS_SWITCH;
795 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800796#endif
797
Jeff Browne839a582010-04-22 18:58:52 -0700798 if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800799 // a more descriptive name
Iliyan Malchev34193b32009-08-06 14:50:08 -0700800 device->name = name;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800801
Jeff Brown6a817e22010-09-12 17:55:08 -0700802 // Configure the keymap for the device.
803 configureKeyMap(device);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800804
Jeff Brown6a817e22010-09-12 17:55:08 -0700805 // Tell the world about the devname (the descriptive name)
806 if (!mHaveFirstKeyboard && !device->defaultKeyMap && strstr(name, "-keypad")) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800807 // the built-in keyboard has a well-known device ID of 0,
808 // this device better not go away.
809 mHaveFirstKeyboard = true;
810 mFirstKeyboardId = device->id;
Jeff Brown6a817e22010-09-12 17:55:08 -0700811 setKeyboardProperties(device, true);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800812 } else {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800813 // ensure mFirstKeyboardId is set to -something-.
Jeff Brown6a817e22010-09-12 17:55:08 -0700814 if (mFirstKeyboardId == -1) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800815 mFirstKeyboardId = device->id;
Jeff Brown6a817e22010-09-12 17:55:08 -0700816 setKeyboardProperties(device, true);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800817 }
818 }
Jeff Brown6a817e22010-09-12 17:55:08 -0700819 setKeyboardProperties(device, false);
820
821 // Load the keylayout.
822 if (!device->keyLayoutFilename.isEmpty()) {
823 status_t status = device->layoutMap->load(device->keyLayoutFilename);
824 if (status) {
825 LOGE("Error %d loading key layout file '%s'.", status,
826 device->keyLayoutFilename.string());
827 }
828 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800829
Dianne Hackbornc5917362009-08-04 05:49:43 -0700830 // 'Q' key support = cheap test of whether this is an alpha-capable kbd
Jeff Brown2806e382010-10-01 17:46:21 -0700831 if (hasKeycodeLocked(device, AKEYCODE_Q)) {
Jeff Browne839a582010-04-22 18:58:52 -0700832 device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY;
Dianne Hackbornc5917362009-08-04 05:49:43 -0700833 }
Jeff Brown6a817e22010-09-12 17:55:08 -0700834
Jeff Brown8575a872010-06-30 16:10:35 -0700835 // See if this device has a DPAD.
Jeff Brown2806e382010-10-01 17:46:21 -0700836 if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) &&
837 hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) &&
838 hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) &&
839 hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) &&
840 hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) {
Jeff Browne839a582010-04-22 18:58:52 -0700841 device->classes |= INPUT_DEVICE_CLASS_DPAD;
Dianne Hackbornc5917362009-08-04 05:49:43 -0700842 }
Jeff Brown6a817e22010-09-12 17:55:08 -0700843
Jeff Brown8575a872010-06-30 16:10:35 -0700844 // See if this device has a gamepad.
Kenny Rootbc9c82f2010-10-21 15:46:03 -0700845 for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) {
Jeff Brown2806e382010-10-01 17:46:21 -0700846 if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) {
Jeff Brown8575a872010-06-30 16:10:35 -0700847 device->classes |= INPUT_DEVICE_CLASS_GAMEPAD;
848 break;
849 }
850 }
851
Jeff Brown6a817e22010-09-12 17:55:08 -0700852 LOGI("New keyboard: device->id=0x%x devname='%s' keylayout='%s' keycharactermap='%s'\n",
853 device->id, name,
854 device->keyLayoutFilename.string(), device->keyCharacterMapFilename.string());
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800855 }
856
Sean McNeil2e7a5302010-06-23 16:00:37 +0700857 // If the device isn't recognized as something we handle, don't monitor it.
858 if (device->classes == 0) {
859 LOGV("Dropping device %s %p, id = %d\n", deviceName, device, devid);
860 close(fd);
861 delete device;
862 return -1;
863 }
864
Dianne Hackbornc5917362009-08-04 05:49:43 -0700865 LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
866 deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes);
867
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800868 LOGV("Adding device %s %p at %d, id = %d, classes = 0x%x\n",
869 deviceName, device, mFDCount, devid, device->classes);
870
871 mDevicesById[devid].device = device;
872 device->next = mOpeningDevices;
873 mOpeningDevices = device;
874 mDevices[mFDCount] = device;
875
876 mFDCount++;
877 return 0;
878}
879
Jeff Brown6a817e22010-09-12 17:55:08 -0700880void EventHub::configureKeyMap(device_t* device) {
881 // As an initial key map name, try using the device name.
882 String8 keyMapName(device->name);
883 char* p = keyMapName.lockBuffer(keyMapName.size());
884 while (*p) {
885 if (*p == ' ') *p = '_';
886 p++;
887 }
888 keyMapName.unlockBuffer();
889
890 if (probeKeyMap(device, keyMapName, false)) return;
891
892 // TODO Consider allowing the user to configure a specific key map somehow.
893
894 // Try the Generic key map.
895 // TODO Apply some additional heuristics here to figure out what kind of
896 // generic key map to use (US English, etc.).
897 keyMapName.setTo("Generic");
898 if (probeKeyMap(device, keyMapName, true)) return;
899
900 // Fall back on the old style catchall qwerty key map.
901 keyMapName.setTo("qwerty");
902 if (probeKeyMap(device, keyMapName, true)) return;
903
904 // Give up!
905 keyMapName.setTo("unknown");
906 selectKeyMap(device, keyMapName, true);
907 LOGE("Could not determine key map for device '%s'.", device->name.string());
908}
909
910bool EventHub::probeKeyMap(device_t* device, const String8& keyMapName, bool defaultKeyMap) {
911 const char* root = getenv("ANDROID_ROOT");
912
913 // TODO Consider also looking somewhere in a writeable partition like /data for a
914 // custom keymap supplied by the user for this device.
915 bool haveKeyLayout = !device->keyLayoutFilename.isEmpty();
916 if (!haveKeyLayout) {
917 device->keyLayoutFilename.setTo(root);
918 device->keyLayoutFilename.append("/usr/keylayout/");
919 device->keyLayoutFilename.append(keyMapName);
920 device->keyLayoutFilename.append(".kl");
921 if (access(device->keyLayoutFilename.string(), R_OK)) {
922 device->keyLayoutFilename.clear();
923 } else {
924 haveKeyLayout = true;
925 }
926 }
927
928 bool haveKeyCharacterMap = !device->keyCharacterMapFilename.isEmpty();
929 if (!haveKeyCharacterMap) {
930 device->keyCharacterMapFilename.setTo(root);
931 device->keyCharacterMapFilename.append("/usr/keychars/");
932 device->keyCharacterMapFilename.append(keyMapName);
933 device->keyCharacterMapFilename.append(".kcm.bin");
934 if (access(device->keyCharacterMapFilename.string(), R_OK)) {
935 device->keyCharacterMapFilename.clear();
936 } else {
937 haveKeyCharacterMap = true;
938 }
939 }
940
941 if (haveKeyLayout || haveKeyCharacterMap) {
942 selectKeyMap(device, keyMapName, defaultKeyMap);
943 }
944 return haveKeyLayout && haveKeyCharacterMap;
945}
946
947void EventHub::selectKeyMap(device_t* device,
948 const String8& keyMapName, bool defaultKeyMap) {
949 if (device->keyMapName.isEmpty()) {
950 device->keyMapName.setTo(keyMapName);
951 device->defaultKeyMap = defaultKeyMap;
952 }
953}
954
955void EventHub::setKeyboardProperties(device_t* device, bool firstKeyboard) {
956 int32_t id = firstKeyboard ? 0 : device->id;
957
958 char propName[100];
959 sprintf(propName, "hw.keyboards.%u.devname", id);
960 property_set(propName, device->name.string());
961 sprintf(propName, "hw.keyboards.%u.keymap", id);
962 property_set(propName, device->keyMapName.string());
963 sprintf(propName, "hw.keyboards.%u.klfile", id);
964 property_set(propName, device->keyLayoutFilename.string());
965 sprintf(propName, "hw.keyboards.%u.kcmfile", id);
966 property_set(propName, device->keyCharacterMapFilename.string());
967}
968
969void EventHub::clearKeyboardProperties(device_t* device, bool firstKeyboard) {
970 int32_t id = firstKeyboard ? 0 : device->id;
971
972 char propName[100];
973 sprintf(propName, "hw.keyboards.%u.devname", id);
974 property_set(propName, "");
975 sprintf(propName, "hw.keyboards.%u.keymap", id);
976 property_set(propName, "");
977 sprintf(propName, "hw.keyboards.%u.klfile", id);
978 property_set(propName, "");
979 sprintf(propName, "hw.keyboards.%u.kcmfile", id);
980 property_set(propName, "");
981}
982
Jeff Brown2806e382010-10-01 17:46:21 -0700983bool EventHub::hasKeycodeLocked(device_t* device, int keycode) const
Dianne Hackbornc5917362009-08-04 05:49:43 -0700984{
985 if (device->keyBitmask == NULL || device->layoutMap == NULL) {
986 return false;
987 }
988
989 Vector<int32_t> scanCodes;
990 device->layoutMap->findScancodes(keycode, &scanCodes);
991 const size_t N = scanCodes.size();
992 for (size_t i=0; i<N && i<=KEY_MAX; i++) {
993 int32_t sc = scanCodes.itemAt(i);
994 if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, device->keyBitmask)) {
995 return true;
996 }
997 }
998
999 return false;
1000}
1001
Jeff Brown1ad00e92010-10-01 18:55:43 -07001002int EventHub::closeDevice(const char *deviceName) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001003 AutoMutex _l(mLock);
Jeff Brown1ad00e92010-10-01 18:55:43 -07001004
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001005 int i;
1006 for(i = 1; i < mFDCount; i++) {
1007 if(strcmp(mDevices[i]->path.string(), deviceName) == 0) {
1008 //LOGD("remove device %d: %s\n", i, deviceName);
1009 device_t* device = mDevices[i];
Dianne Hackborn39bf9182009-09-01 19:01:50 -07001010
1011 LOGI("Removed device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
1012 device->path.string(), device->name.string(), device->id,
1013 mNumDevicesById, mFDCount, mFDs[i].fd, device->classes);
1014
1015 // Clear this device's entry.
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001016 int index = (device->id&ID_MASK);
1017 mDevicesById[index].device = NULL;
Dianne Hackborn39bf9182009-09-01 19:01:50 -07001018
1019 // Close the file descriptor and compact the fd array.
Mike Lockwood07549f92009-08-28 13:29:06 -07001020 close(mFDs[i].fd);
Dianne Hackborn39bf9182009-09-01 19:01:50 -07001021 int count = mFDCount - i - 1;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001022 memmove(mDevices + i, mDevices + i + 1, sizeof(mDevices[0]) * count);
1023 memmove(mFDs + i, mFDs + i + 1, sizeof(mFDs[0]) * count);
Dianne Hackborn39bf9182009-09-01 19:01:50 -07001024 mFDCount--;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001025
1026#ifdef EV_SW
1027 for (int j=0; j<EV_SW; j++) {
1028 if (mSwitches[j] == device->id) {
1029 mSwitches[j] = 0;
1030 }
1031 }
1032#endif
1033
1034 device->next = mClosingDevices;
1035 mClosingDevices = device;
1036
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001037 if (device->id == mFirstKeyboardId) {
1038 LOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
1039 device->path.string(), mFirstKeyboardId);
Jeff Brown6a817e22010-09-12 17:55:08 -07001040 mFirstKeyboardId = -1;
1041 clearKeyboardProperties(device, true);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001042 }
Jeff Brown6a817e22010-09-12 17:55:08 -07001043 clearKeyboardProperties(device, false);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001044 return 0;
1045 }
1046 }
Dianne Hackborn39bf9182009-09-01 19:01:50 -07001047 LOGE("remove device: %s not found\n", deviceName);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001048 return -1;
1049}
1050
Jeff Brown1ad00e92010-10-01 18:55:43 -07001051int EventHub::readNotify(int nfd) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001052#ifdef HAVE_INOTIFY
1053 int res;
1054 char devname[PATH_MAX];
1055 char *filename;
1056 char event_buf[512];
1057 int event_size;
1058 int event_pos = 0;
1059 struct inotify_event *event;
1060
Jeff Brown1ad00e92010-10-01 18:55:43 -07001061 LOGV("EventHub::readNotify nfd: %d\n", nfd);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001062 res = read(nfd, event_buf, sizeof(event_buf));
1063 if(res < (int)sizeof(*event)) {
1064 if(errno == EINTR)
1065 return 0;
1066 LOGW("could not get event, %s\n", strerror(errno));
1067 return 1;
1068 }
1069 //printf("got %d bytes of event information\n", res);
1070
1071 strcpy(devname, device_path);
1072 filename = devname + strlen(devname);
1073 *filename++ = '/';
1074
1075 while(res >= (int)sizeof(*event)) {
1076 event = (struct inotify_event *)(event_buf + event_pos);
1077 //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
1078 if(event->len) {
1079 strcpy(filename, event->name);
1080 if(event->mask & IN_CREATE) {
Jeff Brown1ad00e92010-10-01 18:55:43 -07001081 openDevice(devname);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001082 }
1083 else {
Jeff Brown1ad00e92010-10-01 18:55:43 -07001084 closeDevice(devname);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001085 }
1086 }
1087 event_size = sizeof(*event) + event->len;
1088 res -= event_size;
1089 event_pos += event_size;
1090 }
1091#endif
1092 return 0;
1093}
1094
1095
Jeff Brown1ad00e92010-10-01 18:55:43 -07001096int EventHub::scanDir(const char *dirname)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001097{
1098 char devname[PATH_MAX];
1099 char *filename;
1100 DIR *dir;
1101 struct dirent *de;
1102 dir = opendir(dirname);
1103 if(dir == NULL)
1104 return -1;
1105 strcpy(devname, dirname);
1106 filename = devname + strlen(devname);
1107 *filename++ = '/';
1108 while((de = readdir(dir))) {
1109 if(de->d_name[0] == '.' &&
1110 (de->d_name[1] == '\0' ||
1111 (de->d_name[1] == '.' && de->d_name[2] == '\0')))
1112 continue;
1113 strcpy(filename, de->d_name);
Jeff Brown1ad00e92010-10-01 18:55:43 -07001114 openDevice(devname);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001115 }
1116 closedir(dir);
1117 return 0;
1118}
1119
Jeff Brown2806e382010-10-01 17:46:21 -07001120void EventHub::dump(String8& dump) {
1121 dump.append("Event Hub State:\n");
1122
1123 { // acquire lock
1124 AutoMutex _l(mLock);
1125
1126 dump.appendFormat(INDENT "HaveFirstKeyboard: %s\n", toString(mHaveFirstKeyboard));
1127 dump.appendFormat(INDENT "FirstKeyboardId: 0x%x\n", mFirstKeyboardId);
1128
1129 dump.append(INDENT "Devices:\n");
1130
1131 for (int i = 0; i < mNumDevicesById; i++) {
1132 const device_t* device = mDevicesById[i].device;
1133 if (device) {
1134 if (mFirstKeyboardId == device->id) {
1135 dump.appendFormat(INDENT2 "0x%x: %s (aka device 0 - first keyboard)\n",
1136 device->id, device->name.string());
1137 } else {
1138 dump.appendFormat(INDENT2 "0x%x: %s\n", device->id, device->name.string());
1139 }
1140 dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes);
1141 dump.appendFormat(INDENT3 "Path: %s\n", device->path.string());
Jeff Brown6a817e22010-09-12 17:55:08 -07001142 dump.appendFormat(INDENT3 "KeyMapName: %s\n", device->keyMapName.string());
1143 dump.appendFormat(INDENT3 "KeyLayoutFilename: %s\n",
1144 device->keyLayoutFilename.string());
1145 dump.appendFormat(INDENT3 "KeyCharacterMapFilename: %s\n",
1146 device->keyCharacterMapFilename.string());
Jeff Brown2806e382010-10-01 17:46:21 -07001147 }
1148 }
1149 } // release lock
1150}
1151
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001152}; // namespace android