blob: 124f7b3cd217efede0e7867973a56a32a687548e [file] [log] [blame]
The Android Open Source Project9066cfe2009-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 Hackborn0dd7cb42009-08-04 05:49:43 -070019#include <ui/KeycodeLabels.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020#include <hardware_legacy/power.h>
21
22#include <cutils/properties.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023#include <utils/Log.h>
24#include <utils/Timers.h>
Mathias Agopian3b4062e2009-05-31 19:13:00 -070025#include <utils/threads.h>
Mathias Agopian3b4062e2009-05-31 19:13:00 -070026#include <utils/Errors.h>
The Android Open Source Project9066cfe2009-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 Brownfd035822010-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 Project9066cfe2009-03-03 19:31:44 -080060#define ID_MASK 0x0000ffff
61#define SEQ_MASK 0x7fff0000
62#define SEQ_SHIFT 16
63#define id_to_index(id) ((id&ID_MASK)+1)
64
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070065#ifndef ABS_MT_TOUCH_MAJOR
66#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
67#endif
68
69#ifndef ABS_MT_POSITION_X
70#define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */
71#endif
72
73#ifndef ABS_MT_POSITION_Y
74#define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */
75#endif
76
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077namespace android {
78
79static const char *WAKE_LOCK_ID = "KeyEvents";
80static const char *device_path = "/dev/input";
81
82/* return the larger integer */
83static inline int max(int v1, int v2)
84{
85 return (v1 > v2) ? v1 : v2;
86}
87
Iliyan Malchevfc2ebc42009-08-06 14:50:08 -070088EventHub::device_t::device_t(int32_t _id, const char* _path, const char* name)
89 : id(_id), path(_path), name(name), classes(0)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 , keyBitmask(NULL), layoutMap(new KeyLayoutMap()), next(NULL) {
91}
92
93EventHub::device_t::~device_t() {
94 delete [] keyBitmask;
95 delete layoutMap;
96}
97
98EventHub::EventHub(void)
99 : mError(NO_INIT), mHaveFirstKeyboard(false), mFirstKeyboardId(0)
100 , mDevicesById(0), mNumDevicesById(0)
101 , mOpeningDevices(0), mClosingDevices(0)
Mike Lockwood1d9dfc52009-07-16 11:11:18 -0400102 , mDevices(0), mFDs(0), mFDCount(0), mOpened(false)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103{
104 acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
105#ifdef EV_SW
106 memset(mSwitches, 0, sizeof(mSwitches));
107#endif
108}
109
110/*
111 * Clean up.
112 */
113EventHub::~EventHub(void)
114{
115 release_wake_lock(WAKE_LOCK_ID);
116 // we should free stuff here...
117}
118
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119status_t EventHub::errorCheck() const
120{
121 return mError;
122}
123
124String8 EventHub::getDeviceName(int32_t deviceId) const
125{
126 AutoMutex _l(mLock);
127 device_t* device = getDevice(deviceId);
128 if (device == NULL) return String8();
129 return device->name;
130}
131
132uint32_t EventHub::getDeviceClasses(int32_t deviceId) const
133{
134 AutoMutex _l(mLock);
135 device_t* device = getDevice(deviceId);
136 if (device == NULL) return 0;
137 return device->classes;
138}
139
Jeff Brown6d0fec22010-07-23 21:28:06 -0700140status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis,
141 RawAbsoluteAxisInfo* outAxisInfo) const {
142 outAxisInfo->valid = false;
143 outAxisInfo->minValue = 0;
144 outAxisInfo->maxValue = 0;
145 outAxisInfo->flat = 0;
146 outAxisInfo->fuzz = 0;
147
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148 AutoMutex _l(mLock);
149 device_t* device = getDevice(deviceId);
150 if (device == NULL) return -1;
151
152 struct input_absinfo info;
153
154 if(ioctl(mFDs[id_to_index(device->id)].fd, EVIOCGABS(axis), &info)) {
Jeff Brown6d0fec22010-07-23 21:28:06 -0700155 LOGW("Error reading absolute controller %d for device %s fd %d\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156 axis, device->name.string(), mFDs[id_to_index(device->id)].fd);
Jeff Brown6d0fec22010-07-23 21:28:06 -0700157 return -errno;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158 }
Jeff Brown6d0fec22010-07-23 21:28:06 -0700159
160 if (info.minimum != info.maximum) {
161 outAxisInfo->valid = true;
162 outAxisInfo->minValue = info.minimum;
163 outAxisInfo->maxValue = info.maximum;
164 outAxisInfo->flat = info.flat;
165 outAxisInfo->fuzz = info.fuzz;
166 }
167 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168}
169
Jeff Brown6d0fec22010-07-23 21:28:06 -0700170int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700171 if (scanCode >= 0 && scanCode <= KEY_MAX) {
172 AutoMutex _l(mLock);
173
Jeff Brown6d0fec22010-07-23 21:28:06 -0700174 device_t* device = getDevice(deviceId);
175 if (device != NULL) {
176 return getScanCodeStateLocked(device, scanCode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177 }
178 }
Jeff Brownc5ed5912010-07-14 18:48:53 -0700179 return AKEY_STATE_UNKNOWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180}
181
Jeff Brown46b9ac02010-04-22 18:58:52 -0700182int32_t EventHub::getScanCodeStateLocked(device_t* device, int32_t scanCode) const {
Jeff Brownfd035822010-06-30 16:10:35 -0700183 uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
Jeff Brown46b9ac02010-04-22 18:58:52 -0700184 memset(key_bitmask, 0, sizeof(key_bitmask));
185 if (ioctl(mFDs[id_to_index(device->id)].fd,
186 EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
Jeff Brownc5ed5912010-07-14 18:48:53 -0700187 return test_bit(scanCode, key_bitmask) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700188 }
Jeff Brownc5ed5912010-07-14 18:48:53 -0700189 return AKEY_STATE_UNKNOWN;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700190}
191
Jeff Brown6d0fec22010-07-23 21:28:06 -0700192int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const {
193 AutoMutex _l(mLock);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700194
Jeff Brown6d0fec22010-07-23 21:28:06 -0700195 device_t* device = getDevice(deviceId);
196 if (device != NULL) {
197 return getKeyCodeStateLocked(device, keyCode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 }
Jeff Brownc5ed5912010-07-14 18:48:53 -0700199 return AKEY_STATE_UNKNOWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200}
201
Jeff Brown46b9ac02010-04-22 18:58:52 -0700202int32_t EventHub::getKeyCodeStateLocked(device_t* device, int32_t keyCode) const {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203 Vector<int32_t> scanCodes;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700204 device->layoutMap->findScancodes(keyCode, &scanCodes);
205
Jeff Brownfd035822010-06-30 16:10:35 -0700206 uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 memset(key_bitmask, 0, sizeof(key_bitmask));
208 if (ioctl(mFDs[id_to_index(device->id)].fd,
209 EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
210 #if 0
211 for (size_t i=0; i<=KEY_MAX; i++) {
212 LOGI("(Scan code %d: down=%d)", i, test_bit(i, key_bitmask));
213 }
214 #endif
215 const size_t N = scanCodes.size();
216 for (size_t i=0; i<N && i<=KEY_MAX; i++) {
217 int32_t sc = scanCodes.itemAt(i);
218 //LOGI("Code %d: down=%d", sc, test_bit(sc, key_bitmask));
219 if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, key_bitmask)) {
Jeff Brownc5ed5912010-07-14 18:48:53 -0700220 return AKEY_STATE_DOWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221 }
222 }
Jeff Brownc5ed5912010-07-14 18:48:53 -0700223 return AKEY_STATE_UP;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224 }
Jeff Brownc5ed5912010-07-14 18:48:53 -0700225 return AKEY_STATE_UNKNOWN;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700226}
227
Jeff Brown6d0fec22010-07-23 21:28:06 -0700228int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700229#ifdef EV_SW
230 if (sw >= 0 && sw <= SW_MAX) {
231 AutoMutex _l(mLock);
232
Jeff Brown46b9ac02010-04-22 18:58:52 -0700233 device_t* device = getDevice(deviceId);
Jeff Brown6d0fec22010-07-23 21:28:06 -0700234 if (device != NULL) {
235 return getSwitchStateLocked(device, sw);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700236 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700237 }
238#endif
Jeff Brownc5ed5912010-07-14 18:48:53 -0700239 return AKEY_STATE_UNKNOWN;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700240}
241
242int32_t EventHub::getSwitchStateLocked(device_t* device, int32_t sw) const {
Jeff Brownfd035822010-06-30 16:10:35 -0700243 uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)];
Jeff Brown46b9ac02010-04-22 18:58:52 -0700244 memset(sw_bitmask, 0, sizeof(sw_bitmask));
245 if (ioctl(mFDs[id_to_index(device->id)].fd,
246 EVIOCGSW(sizeof(sw_bitmask)), sw_bitmask) >= 0) {
Jeff Brownc5ed5912010-07-14 18:48:53 -0700247 return test_bit(sw, sw_bitmask) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700248 }
Jeff Brownc5ed5912010-07-14 18:48:53 -0700249 return AKEY_STATE_UNKNOWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250}
251
Jeff Brown6d0fec22010-07-23 21:28:06 -0700252bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes,
253 const int32_t* keyCodes, uint8_t* outFlags) const {
254 AutoMutex _l(mLock);
255
256 device_t* device = getDevice(deviceId);
257 if (device != NULL) {
258 return markSupportedKeyCodesLocked(device, numCodes, keyCodes, outFlags);
259 }
260 return false;
261}
262
263bool EventHub::markSupportedKeyCodesLocked(device_t* device, size_t numCodes,
264 const int32_t* keyCodes, uint8_t* outFlags) const {
265 if (device->layoutMap == NULL || device->keyBitmask == NULL) {
266 return false;
267 }
268
269 Vector<int32_t> scanCodes;
270 for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) {
271 scanCodes.clear();
272
273 status_t err = device->layoutMap->findScancodes(keyCodes[codeIndex], &scanCodes);
274 if (! err) {
275 // check the possible scan codes identified by the layout map against the
276 // map of codes actually emitted by the driver
277 for (size_t sc = 0; sc < scanCodes.size(); sc++) {
278 if (test_bit(scanCodes[sc], device->keyBitmask)) {
279 outFlags[codeIndex] = 1;
280 break;
281 }
282 }
283 }
284 }
285 return true;
286}
287
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700288status_t EventHub::scancodeToKeycode(int32_t deviceId, int scancode,
289 int32_t* outKeycode, uint32_t* outFlags) const
290{
291 AutoMutex _l(mLock);
292 device_t* device = getDevice(deviceId);
293
294 if (device != NULL && device->layoutMap != NULL) {
295 status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
296 if (err == NO_ERROR) {
297 return NO_ERROR;
298 }
299 }
300
301 if (mHaveFirstKeyboard) {
302 device = getDevice(mFirstKeyboardId);
303
304 if (device != NULL && device->layoutMap != NULL) {
305 status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
306 if (err == NO_ERROR) {
307 return NO_ERROR;
308 }
309 }
310 }
311
312 *outKeycode = 0;
313 *outFlags = 0;
314 return NAME_NOT_FOUND;
315}
316
Mike Lockwood1d9dfc52009-07-16 11:11:18 -0400317void EventHub::addExcludedDevice(const char* deviceName)
318{
319 String8 name(deviceName);
320 mExcludedDevices.push_back(name);
321}
322
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800323EventHub::device_t* EventHub::getDevice(int32_t deviceId) const
324{
325 if (deviceId == 0) deviceId = mFirstKeyboardId;
326 int32_t id = deviceId & ID_MASK;
327 if (id >= mNumDevicesById || id < 0) return NULL;
328 device_t* dev = mDevicesById[id].device;
Dianne Hackborn4e829f02009-03-25 16:21:55 -0700329 if (dev == NULL) return NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 if (dev->id == deviceId) {
331 return dev;
332 }
333 return NULL;
334}
335
Jeff Brown6d0fec22010-07-23 21:28:06 -0700336bool EventHub::getEvent(RawEvent* outEvent)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337{
Jeff Brown6d0fec22010-07-23 21:28:06 -0700338 outEvent->deviceId = 0;
339 outEvent->type = 0;
340 outEvent->scanCode = 0;
341 outEvent->keyCode = 0;
342 outEvent->flags = 0;
343 outEvent->value = 0;
344 outEvent->when = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345
346 status_t err;
347
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 int i;
349 int res;
350 int pollres;
351 struct input_event iev;
352
353 // Note that we only allow one caller to getEvent(), so don't need
354 // to do locking here... only when adding/removing devices.
Mike Lockwood1d9dfc52009-07-16 11:11:18 -0400355
356 if (!mOpened) {
357 mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
358 mOpened = true;
359 }
360
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 while(1) {
362
363 // First, report any devices that had last been added/removed.
364 if (mClosingDevices != NULL) {
365 device_t* device = mClosingDevices;
366 LOGV("Reporting device closed: id=0x%x, name=%s\n",
367 device->id, device->path.string());
368 mClosingDevices = device->next;
Jeff Brown6d0fec22010-07-23 21:28:06 -0700369 if (device->id == mFirstKeyboardId) {
370 outEvent->deviceId = 0;
371 } else {
372 outEvent->deviceId = device->id;
373 }
374 outEvent->type = DEVICE_REMOVED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375 delete device;
376 return true;
377 }
Jeff Brown6d0fec22010-07-23 21:28:06 -0700378
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 if (mOpeningDevices != NULL) {
380 device_t* device = mOpeningDevices;
381 LOGV("Reporting device opened: id=0x%x, name=%s\n",
382 device->id, device->path.string());
383 mOpeningDevices = device->next;
Jeff Brown6d0fec22010-07-23 21:28:06 -0700384 if (device->id == mFirstKeyboardId) {
385 outEvent->deviceId = 0;
386 } else {
387 outEvent->deviceId = device->id;
388 }
389 outEvent->type = DEVICE_ADDED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 return true;
391 }
392
393 release_wake_lock(WAKE_LOCK_ID);
394
395 pollres = poll(mFDs, mFDCount, -1);
396
397 acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
398
399 if (pollres <= 0) {
400 if (errno != EINTR) {
401 LOGW("select failed (errno=%d)\n", errno);
402 usleep(100000);
403 }
404 continue;
405 }
406
407 //printf("poll %d, returned %d\n", mFDCount, pollres);
408
409 // mFDs[0] is used for inotify, so process regular events starting at mFDs[1]
410 for(i = 1; i < mFDCount; i++) {
411 if(mFDs[i].revents) {
412 LOGV("revents for %d = 0x%08x", i, mFDs[i].revents);
413 if(mFDs[i].revents & POLLIN) {
414 res = read(mFDs[i].fd, &iev, sizeof(iev));
415 if (res == sizeof(iev)) {
Jeff Brown6d0fec22010-07-23 21:28:06 -0700416 device_t* device = mDevices[i];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d",
Jeff Brown6d0fec22010-07-23 21:28:06 -0700418 device->path.string(),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419 (int) iev.time.tv_sec, (int) iev.time.tv_usec,
420 iev.type, iev.code, iev.value);
Jeff Brown6d0fec22010-07-23 21:28:06 -0700421 if (device->id == mFirstKeyboardId) {
422 outEvent->deviceId = 0;
423 } else {
424 outEvent->deviceId = device->id;
425 }
426 outEvent->type = iev.type;
427 outEvent->scanCode = iev.code;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 if (iev.type == EV_KEY) {
Jeff Brown6d0fec22010-07-23 21:28:06 -0700429 err = device->layoutMap->map(iev.code,
430 & outEvent->keyCode, & outEvent->flags);
431 LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
432 iev.code, outEvent->keyCode, outEvent->flags, err);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433 if (err != 0) {
Jeff Brown6d0fec22010-07-23 21:28:06 -0700434 outEvent->keyCode = AKEYCODE_UNKNOWN;
435 outEvent->flags = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 }
437 } else {
Jeff Brown6d0fec22010-07-23 21:28:06 -0700438 outEvent->keyCode = iev.code;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439 }
Jeff Brown6d0fec22010-07-23 21:28:06 -0700440 outEvent->value = iev.value;
441
442 // Use an event timestamp in the same timebase as
443 // java.lang.System.nanoTime() and android.os.SystemClock.uptimeMillis()
444 // as expected by the rest of the system.
445 outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800446 return true;
447 } else {
448 if (res<0) {
449 LOGW("could not get event (errno=%d)", errno);
450 } else {
451 LOGE("could not get event (wrong size: %d)", res);
452 }
453 continue;
454 }
455 }
456 }
457 }
458
459 // read_notify() will modify mFDs and mFDCount, so this must be done after
460 // processing all other events.
461 if(mFDs[0].revents & POLLIN) {
462 read_notify(mFDs[0].fd);
463 }
464 }
465}
466
467/*
468 * Open the platform-specific input device.
469 */
470bool EventHub::openPlatformInput(void)
471{
472 /*
473 * Open platform-specific input device(s).
474 */
475 int res;
476
477 mFDCount = 1;
478 mFDs = (pollfd *)calloc(1, sizeof(mFDs[0]));
479 mDevices = (device_t **)calloc(1, sizeof(mDevices[0]));
480 mFDs[0].events = POLLIN;
481 mDevices[0] = NULL;
482#ifdef HAVE_INOTIFY
483 mFDs[0].fd = inotify_init();
484 res = inotify_add_watch(mFDs[0].fd, device_path, IN_DELETE | IN_CREATE);
485 if(res < 0) {
486 LOGE("could not add watch for %s, %s\n", device_path, strerror(errno));
487 }
488#else
489 /*
490 * The code in EventHub::getEvent assumes that mFDs[0] is an inotify fd.
491 * We allocate space for it and set it to something invalid.
492 */
493 mFDs[0].fd = -1;
494#endif
495
496 res = scan_dir(device_path);
497 if(res < 0) {
498 LOGE("scan dir failed for %s\n", device_path);
499 //open_device("/dev/input/event0");
500 }
501
502 return true;
503}
504
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505// ----------------------------------------------------------------------------
506
Jeff Brownfd035822010-06-30 16:10:35 -0700507static bool containsNonZeroByte(const uint8_t* array, uint32_t startIndex, uint32_t endIndex) {
508 const uint8_t* end = array + endIndex;
509 array += startIndex;
510 while (array != end) {
511 if (*(array++) != 0) {
512 return true;
513 }
514 }
515 return false;
516}
517
518static const int32_t GAMEPAD_KEYCODES[] = {
519 AKEYCODE_BUTTON_A, AKEYCODE_BUTTON_B, AKEYCODE_BUTTON_C,
520 AKEYCODE_BUTTON_X, AKEYCODE_BUTTON_Y, AKEYCODE_BUTTON_Z,
521 AKEYCODE_BUTTON_L1, AKEYCODE_BUTTON_R1,
522 AKEYCODE_BUTTON_L2, AKEYCODE_BUTTON_R2,
523 AKEYCODE_BUTTON_THUMBL, AKEYCODE_BUTTON_THUMBR,
524 AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE
525};
526
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800527int EventHub::open_device(const char *deviceName)
528{
529 int version;
530 int fd;
531 struct pollfd *new_mFDs;
532 device_t **new_devices;
533 char **new_device_names;
534 char name[80];
535 char location[80];
536 char idstr[80];
537 struct input_id id;
538
539 LOGV("Opening device: %s", deviceName);
540
541 AutoMutex _l(mLock);
Nick Pellye6b1bbd2010-01-20 19:36:49 -0800542
Nick Pellyc8b60d12010-01-26 10:27:15 -0800543 fd = open(deviceName, O_RDWR);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544 if(fd < 0) {
545 LOGE("could not open %s, %s\n", deviceName, strerror(errno));
546 return -1;
547 }
548
549 if(ioctl(fd, EVIOCGVERSION, &version)) {
550 LOGE("could not get driver version for %s, %s\n", deviceName, strerror(errno));
551 return -1;
552 }
553 if(ioctl(fd, EVIOCGID, &id)) {
554 LOGE("could not get driver id for %s, %s\n", deviceName, strerror(errno));
555 return -1;
556 }
557 name[sizeof(name) - 1] = '\0';
558 location[sizeof(location) - 1] = '\0';
559 idstr[sizeof(idstr) - 1] = '\0';
560 if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
561 //fprintf(stderr, "could not get device name for %s, %s\n", deviceName, strerror(errno));
562 name[0] = '\0';
563 }
Mike Lockwood15431a92009-07-17 00:10:10 -0400564
565 // check to see if the device is on our excluded list
566 List<String8>::iterator iter = mExcludedDevices.begin();
567 List<String8>::iterator end = mExcludedDevices.end();
568 for ( ; iter != end; iter++) {
569 const char* test = *iter;
570 if (strcmp(name, test) == 0) {
571 LOGI("ignoring event id %s driver %s\n", deviceName, test);
572 close(fd);
573 fd = -1;
574 return -1;
575 }
576 }
577
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
579 //fprintf(stderr, "could not get location for %s, %s\n", deviceName, strerror(errno));
580 location[0] = '\0';
581 }
582 if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
583 //fprintf(stderr, "could not get idstring for %s, %s\n", deviceName, strerror(errno));
584 idstr[0] = '\0';
585 }
586
587 int devid = 0;
588 while (devid < mNumDevicesById) {
589 if (mDevicesById[devid].device == NULL) {
590 break;
591 }
592 devid++;
593 }
594 if (devid >= mNumDevicesById) {
595 device_ent* new_devids = (device_ent*)realloc(mDevicesById,
596 sizeof(mDevicesById[0]) * (devid + 1));
597 if (new_devids == NULL) {
598 LOGE("out of memory");
599 return -1;
600 }
601 mDevicesById = new_devids;
602 mNumDevicesById = devid+1;
603 mDevicesById[devid].device = NULL;
604 mDevicesById[devid].seq = 0;
605 }
606
607 mDevicesById[devid].seq = (mDevicesById[devid].seq+(1<<SEQ_SHIFT))&SEQ_MASK;
608 if (mDevicesById[devid].seq == 0) {
609 mDevicesById[devid].seq = 1<<SEQ_SHIFT;
610 }
611
612 new_mFDs = (pollfd*)realloc(mFDs, sizeof(mFDs[0]) * (mFDCount + 1));
613 new_devices = (device_t**)realloc(mDevices, sizeof(mDevices[0]) * (mFDCount + 1));
614 if (new_mFDs == NULL || new_devices == NULL) {
615 LOGE("out of memory");
616 return -1;
617 }
618 mFDs = new_mFDs;
619 mDevices = new_devices;
620
621#if 0
622 LOGI("add device %d: %s\n", mFDCount, deviceName);
623 LOGI(" bus: %04x\n"
624 " vendor %04x\n"
625 " product %04x\n"
626 " version %04x\n",
627 id.bustype, id.vendor, id.product, id.version);
628 LOGI(" name: \"%s\"\n", name);
629 LOGI(" location: \"%s\"\n"
630 " id: \"%s\"\n", location, idstr);
631 LOGI(" version: %d.%d.%d\n",
632 version >> 16, (version >> 8) & 0xff, version & 0xff);
633#endif
634
Iliyan Malchevfc2ebc42009-08-06 14:50:08 -0700635 device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName, name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 if (device == NULL) {
637 LOGE("out of memory");
638 return -1;
639 }
640
641 mFDs[mFDCount].fd = fd;
642 mFDs[mFDCount].events = POLLIN;
643
Jeff Brownfd035822010-06-30 16:10:35 -0700644 // Figure out the kinds of events the device reports.
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700645
Jeff Brownfd035822010-06-30 16:10:35 -0700646 uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647 memset(key_bitmask, 0, sizeof(key_bitmask));
Jeff Brownfd035822010-06-30 16:10:35 -0700648
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800649 LOGV("Getting keys...");
650 if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) {
651 //LOGI("MAP\n");
Jeff Brownfd035822010-06-30 16:10:35 -0700652 //for (int i = 0; i < sizeof(key_bitmask); i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 // LOGI("%d: 0x%02x\n", i, key_bitmask[i]);
654 //}
Jeff Brownfd035822010-06-30 16:10:35 -0700655
656 // See if this is a keyboard. Ignore everything in the button range except for
657 // gamepads which are also considered keyboards.
658 if (containsNonZeroByte(key_bitmask, 0, sizeof_bit_array(BTN_MISC))
659 || containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_GAMEPAD),
660 sizeof_bit_array(BTN_DIGI))
661 || containsNonZeroByte(key_bitmask, sizeof_bit_array(KEY_OK),
662 sizeof_bit_array(KEY_MAX + 1))) {
663 device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
664
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700665 device->keyBitmask = new uint8_t[sizeof(key_bitmask)];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800666 if (device->keyBitmask != NULL) {
667 memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
668 } else {
669 delete device;
670 LOGE("out of memory allocating key bitmask");
671 return -1;
672 }
673 }
674 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700675
Jeff Brownfd035822010-06-30 16:10:35 -0700676 // See if this is a trackball (or mouse).
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677 if (test_bit(BTN_MOUSE, key_bitmask)) {
Jeff Brownfd035822010-06-30 16:10:35 -0700678 uint8_t rel_bitmask[sizeof_bit_array(REL_MAX + 1)];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679 memset(rel_bitmask, 0, sizeof(rel_bitmask));
680 LOGV("Getting relative controllers...");
Jeff Brownfd035822010-06-30 16:10:35 -0700681 if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800682 if (test_bit(REL_X, rel_bitmask) && test_bit(REL_Y, rel_bitmask)) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700683 device->classes |= INPUT_DEVICE_CLASS_TRACKBALL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800684 }
685 }
686 }
Jeff Brownfd035822010-06-30 16:10:35 -0700687
688 // See if this is a touch pad.
689 uint8_t abs_bitmask[sizeof_bit_array(ABS_MAX + 1)];
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700690 memset(abs_bitmask, 0, sizeof(abs_bitmask));
691 LOGV("Getting absolute controllers...");
Jeff Brownfd035822010-06-30 16:10:35 -0700692 if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0) {
693 // Is this a new modern multi-touch driver?
694 if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask)
695 && test_bit(ABS_MT_POSITION_X, abs_bitmask)
696 && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) {
697 device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT;
698
699 // Is this an old style single-touch driver?
700 } else if (test_bit(BTN_TOUCH, key_bitmask)
701 && test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {
702 device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN;
703 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800704 }
705
706#ifdef EV_SW
707 // figure out the switches this device reports
Jeff Brownfd035822010-06-30 16:10:35 -0700708 uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800709 memset(sw_bitmask, 0, sizeof(sw_bitmask));
Jeff Brown6d0fec22010-07-23 21:28:06 -0700710 bool hasSwitches = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800711 if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask) >= 0) {
712 for (int i=0; i<EV_SW; i++) {
713 //LOGI("Device 0x%x sw %d: has=%d", device->id, i, test_bit(i, sw_bitmask));
714 if (test_bit(i, sw_bitmask)) {
Jeff Brown6d0fec22010-07-23 21:28:06 -0700715 hasSwitches = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800716 if (mSwitches[i] == 0) {
717 mSwitches[i] = device->id;
718 }
719 }
720 }
721 }
Jeff Brown6d0fec22010-07-23 21:28:06 -0700722 if (hasSwitches) {
723 device->classes |= INPUT_DEVICE_CLASS_SWITCH;
724 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800725#endif
726
Jeff Brown46b9ac02010-04-22 18:58:52 -0700727 if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) {
Iliyan Malchevfc2ebc42009-08-06 14:50:08 -0700728 char tmpfn[sizeof(name)];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800729 char keylayoutFilename[300];
730
731 // a more descriptive name
Iliyan Malchevfc2ebc42009-08-06 14:50:08 -0700732 device->name = name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800733
734 // replace all the spaces with underscores
Iliyan Malchevfc2ebc42009-08-06 14:50:08 -0700735 strcpy(tmpfn, name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736 for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))
737 *p = '_';
738
739 // find the .kl file we need for this device
740 const char* root = getenv("ANDROID_ROOT");
741 snprintf(keylayoutFilename, sizeof(keylayoutFilename),
742 "%s/usr/keylayout/%s.kl", root, tmpfn);
743 bool defaultKeymap = false;
744 if (access(keylayoutFilename, R_OK)) {
745 snprintf(keylayoutFilename, sizeof(keylayoutFilename),
746 "%s/usr/keylayout/%s", root, "qwerty.kl");
747 defaultKeymap = true;
748 }
Jeff Brownfd035822010-06-30 16:10:35 -0700749 status_t status = device->layoutMap->load(keylayoutFilename);
750 if (status) {
751 LOGE("Error %d loading key layout.", status);
752 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800753
754 // tell the world about the devname (the descriptive name)
Dianne Hackborna2e92262010-03-02 17:19:29 -0800755 if (!mHaveFirstKeyboard && !defaultKeymap && strstr(name, "-keypad")) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756 // the built-in keyboard has a well-known device ID of 0,
757 // this device better not go away.
758 mHaveFirstKeyboard = true;
759 mFirstKeyboardId = device->id;
Dianne Hackborna2e92262010-03-02 17:19:29 -0800760 property_set("hw.keyboards.0.devname", name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800762 // ensure mFirstKeyboardId is set to -something-.
763 if (mFirstKeyboardId == 0) {
764 mFirstKeyboardId = device->id;
765 }
766 }
767 char propName[100];
Dianne Hackborna2e92262010-03-02 17:19:29 -0800768 sprintf(propName, "hw.keyboards.%u.devname", device->id);
Iliyan Malchevfc2ebc42009-08-06 14:50:08 -0700769 property_set(propName, name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700771 // 'Q' key support = cheap test of whether this is an alpha-capable kbd
Jeff Brownfd035822010-06-30 16:10:35 -0700772 if (hasKeycode(device, AKEYCODE_Q)) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700773 device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700774 }
775
Jeff Brownfd035822010-06-30 16:10:35 -0700776 // See if this device has a DPAD.
777 if (hasKeycode(device, AKEYCODE_DPAD_UP) &&
778 hasKeycode(device, AKEYCODE_DPAD_DOWN) &&
779 hasKeycode(device, AKEYCODE_DPAD_LEFT) &&
780 hasKeycode(device, AKEYCODE_DPAD_RIGHT) &&
781 hasKeycode(device, AKEYCODE_DPAD_CENTER)) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700782 device->classes |= INPUT_DEVICE_CLASS_DPAD;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700783 }
784
Jeff Brownfd035822010-06-30 16:10:35 -0700785 // See if this device has a gamepad.
786 for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES); i++) {
787 if (hasKeycode(device, GAMEPAD_KEYCODES[i])) {
788 device->classes |= INPUT_DEVICE_CLASS_GAMEPAD;
789 break;
790 }
791 }
792
Dianne Hackborna2e92262010-03-02 17:19:29 -0800793 LOGI("New keyboard: device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n",
794 device->id, name, propName, keylayoutFilename);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 }
796
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700797 LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
798 deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes);
799
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800800 LOGV("Adding device %s %p at %d, id = %d, classes = 0x%x\n",
801 deviceName, device, mFDCount, devid, device->classes);
802
803 mDevicesById[devid].device = device;
804 device->next = mOpeningDevices;
805 mOpeningDevices = device;
806 mDevices[mFDCount] = device;
807
808 mFDCount++;
809 return 0;
810}
811
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700812bool EventHub::hasKeycode(device_t* device, int keycode) const
813{
814 if (device->keyBitmask == NULL || device->layoutMap == NULL) {
815 return false;
816 }
817
818 Vector<int32_t> scanCodes;
819 device->layoutMap->findScancodes(keycode, &scanCodes);
820 const size_t N = scanCodes.size();
821 for (size_t i=0; i<N && i<=KEY_MAX; i++) {
822 int32_t sc = scanCodes.itemAt(i);
823 if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, device->keyBitmask)) {
824 return true;
825 }
826 }
827
828 return false;
829}
830
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800831int EventHub::close_device(const char *deviceName)
832{
833 AutoMutex _l(mLock);
834
835 int i;
836 for(i = 1; i < mFDCount; i++) {
837 if(strcmp(mDevices[i]->path.string(), deviceName) == 0) {
838 //LOGD("remove device %d: %s\n", i, deviceName);
839 device_t* device = mDevices[i];
Dianne Hackborna8f60182009-09-01 19:01:50 -0700840
841 LOGI("Removed device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
842 device->path.string(), device->name.string(), device->id,
843 mNumDevicesById, mFDCount, mFDs[i].fd, device->classes);
844
845 // Clear this device's entry.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846 int index = (device->id&ID_MASK);
847 mDevicesById[index].device = NULL;
Dianne Hackborna8f60182009-09-01 19:01:50 -0700848
849 // Close the file descriptor and compact the fd array.
Mike Lockwood36dad722009-08-28 13:29:06 -0700850 close(mFDs[i].fd);
Dianne Hackborna8f60182009-09-01 19:01:50 -0700851 int count = mFDCount - i - 1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800852 memmove(mDevices + i, mDevices + i + 1, sizeof(mDevices[0]) * count);
853 memmove(mFDs + i, mFDs + i + 1, sizeof(mFDs[0]) * count);
Dianne Hackborna8f60182009-09-01 19:01:50 -0700854 mFDCount--;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855
856#ifdef EV_SW
857 for (int j=0; j<EV_SW; j++) {
858 if (mSwitches[j] == device->id) {
859 mSwitches[j] = 0;
860 }
861 }
862#endif
863
864 device->next = mClosingDevices;
865 mClosingDevices = device;
866
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800867 if (device->id == mFirstKeyboardId) {
868 LOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
869 device->path.string(), mFirstKeyboardId);
870 mFirstKeyboardId = 0;
Dianne Hackborna2e92262010-03-02 17:19:29 -0800871 property_set("hw.keyboards.0.devname", NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800872 }
873 // clear the property
874 char propName[100];
Dianne Hackborna2e92262010-03-02 17:19:29 -0800875 sprintf(propName, "hw.keyboards.%u.devname", device->id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800876 property_set(propName, NULL);
877 return 0;
878 }
879 }
Dianne Hackborna8f60182009-09-01 19:01:50 -0700880 LOGE("remove device: %s not found\n", deviceName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800881 return -1;
882}
883
884int EventHub::read_notify(int nfd)
885{
886#ifdef HAVE_INOTIFY
887 int res;
888 char devname[PATH_MAX];
889 char *filename;
890 char event_buf[512];
891 int event_size;
892 int event_pos = 0;
893 struct inotify_event *event;
894
Dianne Hackborna8f60182009-09-01 19:01:50 -0700895 LOGV("EventHub::read_notify nfd: %d\n", nfd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800896 res = read(nfd, event_buf, sizeof(event_buf));
897 if(res < (int)sizeof(*event)) {
898 if(errno == EINTR)
899 return 0;
900 LOGW("could not get event, %s\n", strerror(errno));
901 return 1;
902 }
903 //printf("got %d bytes of event information\n", res);
904
905 strcpy(devname, device_path);
906 filename = devname + strlen(devname);
907 *filename++ = '/';
908
909 while(res >= (int)sizeof(*event)) {
910 event = (struct inotify_event *)(event_buf + event_pos);
911 //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
912 if(event->len) {
913 strcpy(filename, event->name);
914 if(event->mask & IN_CREATE) {
915 open_device(devname);
916 }
917 else {
918 close_device(devname);
919 }
920 }
921 event_size = sizeof(*event) + event->len;
922 res -= event_size;
923 event_pos += event_size;
924 }
925#endif
926 return 0;
927}
928
929
930int EventHub::scan_dir(const char *dirname)
931{
932 char devname[PATH_MAX];
933 char *filename;
934 DIR *dir;
935 struct dirent *de;
936 dir = opendir(dirname);
937 if(dir == NULL)
938 return -1;
939 strcpy(devname, dirname);
940 filename = devname + strlen(devname);
941 *filename++ = '/';
942 while((de = readdir(dir))) {
943 if(de->d_name[0] == '.' &&
944 (de->d_name[1] == '\0' ||
945 (de->d_name[1] == '.' && de->d_name[2] == '\0')))
946 continue;
947 strcpy(filename, de->d_name);
948 open_device(devname);
949 }
950 closedir(dir);
951 return 0;
952}
953
954}; // namespace android