blob: b312cda8acf7bac35cd120c60794719acb27155a [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>
19#include <hardware_legacy/power.h>
20
21#include <cutils/properties.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080022#include <utils/Log.h>
23#include <utils/Timers.h>
Mathias Agopiane0c32202009-05-31 19:13:00 -070024#include <utils/threads.h>
Mathias Agopiane0c32202009-05-31 19:13:00 -070025#include <utils/Errors.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080026
27#include <stdlib.h>
28#include <stdio.h>
29#include <unistd.h>
30#include <fcntl.h>
31#include <memory.h>
32#include <errno.h>
33#include <assert.h>
34
Jeff Browna3477c82010-11-10 16:03:06 -080035#include <ui/KeyLayoutMap.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080036
37#include <string.h>
38#include <stdint.h>
39#include <dirent.h>
40#ifdef HAVE_INOTIFY
41# include <sys/inotify.h>
42#endif
43#ifdef HAVE_ANDROID_OS
44# include <sys/limits.h> /* not part of Linux */
45#endif
46#include <sys/poll.h>
47#include <sys/ioctl.h>
48
49/* this macro is used to tell if "bit" is set in "array"
50 * it selects a byte from the array, and does a boolean AND
51 * operation with a byte that only has the relevant bit set.
52 * eg. to check for the 12th bit, we do (array[1] & 1<<4)
53 */
54#define test_bit(bit, array) (array[bit/8] & (1<<(bit%8)))
55
Jeff Brown8575a872010-06-30 16:10:35 -070056/* this macro computes the number of bytes needed to represent a bit array of the specified size */
57#define sizeof_bit_array(bits) ((bits + 7) / 8)
58
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080059#define ID_MASK 0x0000ffff
60#define SEQ_MASK 0x7fff0000
61#define SEQ_SHIFT 16
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080062
Dianne Hackbornc5917362009-08-04 05:49:43 -070063#ifndef ABS_MT_TOUCH_MAJOR
64#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
65#endif
66
67#ifndef ABS_MT_POSITION_X
68#define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */
69#endif
70
71#ifndef ABS_MT_POSITION_Y
72#define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */
73#endif
74
Jeff Brown2806e382010-10-01 17:46:21 -070075#define INDENT " "
76#define INDENT2 " "
77#define INDENT3 " "
78
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080079namespace android {
80
81static const char *WAKE_LOCK_ID = "KeyEvents";
82static const char *device_path = "/dev/input";
83
84/* return the larger integer */
85static inline int max(int v1, int v2)
86{
87 return (v1 > v2) ? v1 : v2;
88}
89
Jeff Brown2806e382010-10-01 17:46:21 -070090static inline const char* toString(bool value) {
91 return value ? "true" : "false";
92}
93
Iliyan Malchev34193b32009-08-06 14:50:08 -070094EventHub::device_t::device_t(int32_t _id, const char* _path, const char* name)
95 : id(_id), path(_path), name(name), classes(0)
Jeff Brown66888372010-11-29 17:37:49 -080096 , keyBitmask(NULL), layoutMap(NULL), configuration(NULL), fd(-1), next(NULL) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080097}
98
99EventHub::device_t::~device_t() {
100 delete [] keyBitmask;
101 delete layoutMap;
Jeff Brown66888372010-11-29 17:37:49 -0800102 delete configuration;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800103}
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 Brown66888372010-11-29 17:37:49 -0800148void EventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const {
Jeff Brown66888372010-11-29 17:37:49 -0800149 AutoMutex _l(mLock);
150 device_t* device = getDeviceLocked(deviceId);
151 if (device && device->configuration) {
152 *outConfiguration = *device->configuration;
Jeff Brown53c16642010-11-18 20:53:46 -0800153 } else {
154 outConfiguration->clear();
Jeff Brown66888372010-11-29 17:37:49 -0800155 }
156}
157
Jeff Browne57e8952010-07-23 21:28:06 -0700158status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis,
159 RawAbsoluteAxisInfo* outAxisInfo) const {
Jeff Brown38a7fab2010-08-30 03:02:23 -0700160 outAxisInfo->clear();
Jeff Browne57e8952010-07-23 21:28:06 -0700161
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800162 AutoMutex _l(mLock);
Jeff Brown2806e382010-10-01 17:46:21 -0700163 device_t* device = getDeviceLocked(deviceId);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800164 if (device == NULL) return -1;
165
166 struct input_absinfo info;
167
Jens Gulin7dcaa582010-06-22 22:21:57 +0200168 if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
Jeff Browne57e8952010-07-23 21:28:06 -0700169 LOGW("Error reading absolute controller %d for device %s fd %d\n",
Jens Gulin7dcaa582010-06-22 22:21:57 +0200170 axis, device->name.string(), device->fd);
Jeff Browne57e8952010-07-23 21:28:06 -0700171 return -errno;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800172 }
Jeff Browne57e8952010-07-23 21:28:06 -0700173
174 if (info.minimum != info.maximum) {
175 outAxisInfo->valid = true;
176 outAxisInfo->minValue = info.minimum;
177 outAxisInfo->maxValue = info.maximum;
178 outAxisInfo->flat = info.flat;
179 outAxisInfo->fuzz = info.fuzz;
180 }
181 return OK;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800182}
183
Jeff Browne57e8952010-07-23 21:28:06 -0700184int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const {
Jeff Browne839a582010-04-22 18:58:52 -0700185 if (scanCode >= 0 && scanCode <= KEY_MAX) {
186 AutoMutex _l(mLock);
187
Jeff Brown2806e382010-10-01 17:46:21 -0700188 device_t* device = getDeviceLocked(deviceId);
Jeff Browne57e8952010-07-23 21:28:06 -0700189 if (device != NULL) {
190 return getScanCodeStateLocked(device, scanCode);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800191 }
192 }
Jeff Brown5c1ed842010-07-14 18:48:53 -0700193 return AKEY_STATE_UNKNOWN;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800194}
195
Jeff Browne839a582010-04-22 18:58:52 -0700196int32_t EventHub::getScanCodeStateLocked(device_t* device, int32_t scanCode) const {
Jeff Brown8575a872010-06-30 16:10:35 -0700197 uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
Jeff Browne839a582010-04-22 18:58:52 -0700198 memset(key_bitmask, 0, sizeof(key_bitmask));
Jens Gulin7dcaa582010-06-22 22:21:57 +0200199 if (ioctl(device->fd,
Jeff Browne839a582010-04-22 18:58:52 -0700200 EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
Jeff Brown5c1ed842010-07-14 18:48:53 -0700201 return test_bit(scanCode, key_bitmask) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
Jeff Browne839a582010-04-22 18:58:52 -0700202 }
Jeff Brown5c1ed842010-07-14 18:48:53 -0700203 return AKEY_STATE_UNKNOWN;
Jeff Browne839a582010-04-22 18:58:52 -0700204}
205
Jeff Browne57e8952010-07-23 21:28:06 -0700206int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const {
207 AutoMutex _l(mLock);
Jeff Browne839a582010-04-22 18:58:52 -0700208
Jeff Brown2806e382010-10-01 17:46:21 -0700209 device_t* device = getDeviceLocked(deviceId);
Jeff Browne57e8952010-07-23 21:28:06 -0700210 if (device != NULL) {
211 return getKeyCodeStateLocked(device, keyCode);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800212 }
Jeff Brown5c1ed842010-07-14 18:48:53 -0700213 return AKEY_STATE_UNKNOWN;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800214}
215
Jeff Browne839a582010-04-22 18:58:52 -0700216int32_t EventHub::getKeyCodeStateLocked(device_t* device, int32_t keyCode) const {
Jeff Browna3477c82010-11-10 16:03:06 -0800217 if (!device->layoutMap) {
218 return AKEY_STATE_UNKNOWN;
219 }
220
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800221 Vector<int32_t> scanCodes;
Jeff Browna3477c82010-11-10 16:03:06 -0800222 device->layoutMap->findScanCodes(keyCode, &scanCodes);
Jeff Browne839a582010-04-22 18:58:52 -0700223
Jeff Brown8575a872010-06-30 16:10:35 -0700224 uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800225 memset(key_bitmask, 0, sizeof(key_bitmask));
Jens Gulin7dcaa582010-06-22 22:21:57 +0200226 if (ioctl(device->fd, EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800227 #if 0
228 for (size_t i=0; i<=KEY_MAX; i++) {
229 LOGI("(Scan code %d: down=%d)", i, test_bit(i, key_bitmask));
230 }
231 #endif
232 const size_t N = scanCodes.size();
233 for (size_t i=0; i<N && i<=KEY_MAX; i++) {
234 int32_t sc = scanCodes.itemAt(i);
235 //LOGI("Code %d: down=%d", sc, test_bit(sc, key_bitmask));
236 if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, key_bitmask)) {
Jeff Brown5c1ed842010-07-14 18:48:53 -0700237 return AKEY_STATE_DOWN;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800238 }
239 }
Jeff Brown5c1ed842010-07-14 18:48:53 -0700240 return AKEY_STATE_UP;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800241 }
Jeff Brown5c1ed842010-07-14 18:48:53 -0700242 return AKEY_STATE_UNKNOWN;
Jeff Browne839a582010-04-22 18:58:52 -0700243}
244
Jeff Browne57e8952010-07-23 21:28:06 -0700245int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const {
Jeff Browne839a582010-04-22 18:58:52 -0700246#ifdef EV_SW
247 if (sw >= 0 && sw <= SW_MAX) {
248 AutoMutex _l(mLock);
249
Jeff Brown2806e382010-10-01 17:46:21 -0700250 device_t* device = getDeviceLocked(deviceId);
Jeff Browne57e8952010-07-23 21:28:06 -0700251 if (device != NULL) {
252 return getSwitchStateLocked(device, sw);
Jeff Browne839a582010-04-22 18:58:52 -0700253 }
Jeff Browne839a582010-04-22 18:58:52 -0700254 }
255#endif
Jeff Brown5c1ed842010-07-14 18:48:53 -0700256 return AKEY_STATE_UNKNOWN;
Jeff Browne839a582010-04-22 18:58:52 -0700257}
258
259int32_t EventHub::getSwitchStateLocked(device_t* device, int32_t sw) const {
Jeff Brown8575a872010-06-30 16:10:35 -0700260 uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)];
Jeff Browne839a582010-04-22 18:58:52 -0700261 memset(sw_bitmask, 0, sizeof(sw_bitmask));
Jens Gulin7dcaa582010-06-22 22:21:57 +0200262 if (ioctl(device->fd,
Jeff Browne839a582010-04-22 18:58:52 -0700263 EVIOCGSW(sizeof(sw_bitmask)), sw_bitmask) >= 0) {
Jeff Brown5c1ed842010-07-14 18:48:53 -0700264 return test_bit(sw, sw_bitmask) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
Jeff Browne839a582010-04-22 18:58:52 -0700265 }
Jeff Brown5c1ed842010-07-14 18:48:53 -0700266 return AKEY_STATE_UNKNOWN;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800267}
268
Jeff Browne57e8952010-07-23 21:28:06 -0700269bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes,
270 const int32_t* keyCodes, uint8_t* outFlags) const {
271 AutoMutex _l(mLock);
272
Jeff Brown2806e382010-10-01 17:46:21 -0700273 device_t* device = getDeviceLocked(deviceId);
Jeff Browne57e8952010-07-23 21:28:06 -0700274 if (device != NULL) {
275 return markSupportedKeyCodesLocked(device, numCodes, keyCodes, outFlags);
276 }
277 return false;
278}
279
280bool EventHub::markSupportedKeyCodesLocked(device_t* device, size_t numCodes,
281 const int32_t* keyCodes, uint8_t* outFlags) const {
282 if (device->layoutMap == NULL || device->keyBitmask == NULL) {
283 return false;
284 }
285
286 Vector<int32_t> scanCodes;
287 for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) {
288 scanCodes.clear();
289
Jeff Browna3477c82010-11-10 16:03:06 -0800290 status_t err = device->layoutMap->findScanCodes(keyCodes[codeIndex], &scanCodes);
Jeff Browne57e8952010-07-23 21:28:06 -0700291 if (! err) {
292 // check the possible scan codes identified by the layout map against the
293 // map of codes actually emitted by the driver
294 for (size_t sc = 0; sc < scanCodes.size(); sc++) {
295 if (test_bit(scanCodes[sc], device->keyBitmask)) {
296 outFlags[codeIndex] = 1;
297 break;
298 }
299 }
300 }
301 }
302 return true;
303}
304
Dianne Hackbornc968c3a2009-07-14 12:06:54 -0700305status_t EventHub::scancodeToKeycode(int32_t deviceId, int scancode,
306 int32_t* outKeycode, uint32_t* outFlags) const
307{
308 AutoMutex _l(mLock);
Jeff Brown2806e382010-10-01 17:46:21 -0700309 device_t* device = getDeviceLocked(deviceId);
Dianne Hackbornc968c3a2009-07-14 12:06:54 -0700310
311 if (device != NULL && device->layoutMap != NULL) {
312 status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
313 if (err == NO_ERROR) {
314 return NO_ERROR;
315 }
316 }
317
318 if (mHaveFirstKeyboard) {
Jeff Brown2806e382010-10-01 17:46:21 -0700319 device = getDeviceLocked(mFirstKeyboardId);
Dianne Hackbornc968c3a2009-07-14 12:06:54 -0700320
321 if (device != NULL && device->layoutMap != NULL) {
322 status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
323 if (err == NO_ERROR) {
324 return NO_ERROR;
325 }
326 }
327 }
328
329 *outKeycode = 0;
330 *outFlags = 0;
331 return NAME_NOT_FOUND;
332}
333
Mike Lockwoodb4411062009-07-16 11:11:18 -0400334void EventHub::addExcludedDevice(const char* deviceName)
335{
Jeff Brown2806e382010-10-01 17:46:21 -0700336 AutoMutex _l(mLock);
337
Mike Lockwoodb4411062009-07-16 11:11:18 -0400338 String8 name(deviceName);
339 mExcludedDevices.push_back(name);
340}
341
Jeff Brown6a817e22010-09-12 17:55:08 -0700342bool EventHub::hasLed(int32_t deviceId, int32_t led) const {
343 AutoMutex _l(mLock);
344 device_t* device = getDeviceLocked(deviceId);
345 if (device) {
346 uint8_t bitmask[sizeof_bit_array(LED_MAX + 1)];
347 memset(bitmask, 0, sizeof(bitmask));
348 if (ioctl(device->fd, EVIOCGBIT(EV_LED, sizeof(bitmask)), bitmask) >= 0) {
349 if (test_bit(led, bitmask)) {
350 return true;
351 }
352 }
353 }
354 return false;
355}
356
357void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) {
358 AutoMutex _l(mLock);
359 device_t* device = getDeviceLocked(deviceId);
360 if (device) {
361 struct input_event ev;
362 ev.time.tv_sec = 0;
363 ev.time.tv_usec = 0;
364 ev.type = EV_LED;
365 ev.code = led;
366 ev.value = on ? 1 : 0;
367
368 ssize_t nWrite;
369 do {
370 nWrite = write(device->fd, &ev, sizeof(struct input_event));
371 } while (nWrite == -1 && errno == EINTR);
372 }
373}
374
Jeff Brown2806e382010-10-01 17:46:21 -0700375EventHub::device_t* EventHub::getDeviceLocked(int32_t deviceId) const
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800376{
377 if (deviceId == 0) deviceId = mFirstKeyboardId;
378 int32_t id = deviceId & ID_MASK;
379 if (id >= mNumDevicesById || id < 0) return NULL;
380 device_t* dev = mDevicesById[id].device;
Dianne Hackbornc3aa00b2009-03-25 16:21:55 -0700381 if (dev == NULL) return NULL;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800382 if (dev->id == deviceId) {
383 return dev;
384 }
385 return NULL;
386}
387
Jeff Browne57e8952010-07-23 21:28:06 -0700388bool EventHub::getEvent(RawEvent* outEvent)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800389{
Jeff Browne57e8952010-07-23 21:28:06 -0700390 outEvent->deviceId = 0;
391 outEvent->type = 0;
392 outEvent->scanCode = 0;
393 outEvent->keyCode = 0;
394 outEvent->flags = 0;
395 outEvent->value = 0;
396 outEvent->when = 0;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800397
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800398 // Note that we only allow one caller to getEvent(), so don't need
399 // to do locking here... only when adding/removing devices.
Mike Lockwoodb4411062009-07-16 11:11:18 -0400400
401 if (!mOpened) {
402 mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
403 mOpened = true;
Jeff Brown1ad00e92010-10-01 18:55:43 -0700404 mNeedToSendFinishedDeviceScan = true;
Mike Lockwoodb4411062009-07-16 11:11:18 -0400405 }
406
Jeff Brown82763072010-08-17 16:48:25 -0700407 for (;;) {
408 // Report any devices that had last been added/removed.
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800409 if (mClosingDevices != NULL) {
410 device_t* device = mClosingDevices;
411 LOGV("Reporting device closed: id=0x%x, name=%s\n",
412 device->id, device->path.string());
413 mClosingDevices = device->next;
Jeff Browne57e8952010-07-23 21:28:06 -0700414 if (device->id == mFirstKeyboardId) {
415 outEvent->deviceId = 0;
416 } else {
417 outEvent->deviceId = device->id;
418 }
419 outEvent->type = DEVICE_REMOVED;
Jeff Brown3c3cc622010-10-20 15:33:38 -0700420 outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800421 delete device;
Jeff Brown1ad00e92010-10-01 18:55:43 -0700422 mNeedToSendFinishedDeviceScan = true;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800423 return true;
424 }
Jeff Browne57e8952010-07-23 21:28:06 -0700425
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800426 if (mOpeningDevices != NULL) {
427 device_t* device = mOpeningDevices;
428 LOGV("Reporting device opened: id=0x%x, name=%s\n",
429 device->id, device->path.string());
430 mOpeningDevices = device->next;
Jeff Browne57e8952010-07-23 21:28:06 -0700431 if (device->id == mFirstKeyboardId) {
432 outEvent->deviceId = 0;
433 } else {
434 outEvent->deviceId = device->id;
435 }
436 outEvent->type = DEVICE_ADDED;
Jeff Brown3c3cc622010-10-20 15:33:38 -0700437 outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
Jeff Brown1ad00e92010-10-01 18:55:43 -0700438 mNeedToSendFinishedDeviceScan = true;
439 return true;
440 }
441
442 if (mNeedToSendFinishedDeviceScan) {
443 mNeedToSendFinishedDeviceScan = false;
444 outEvent->type = FINISHED_DEVICE_SCAN;
Jeff Brown3c3cc622010-10-20 15:33:38 -0700445 outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800446 return true;
447 }
448
Jeff Brown82763072010-08-17 16:48:25 -0700449 // Grab the next input event.
450 for (;;) {
451 // Consume buffered input events, if any.
452 if (mInputBufferIndex < mInputBufferCount) {
453 const struct input_event& iev = mInputBufferData[mInputBufferIndex++];
454 const device_t* device = mDevices[mInputDeviceIndex];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800455
Jeff Brown82763072010-08-17 16:48:25 -0700456 LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d", device->path.string(),
457 (int) iev.time.tv_sec, (int) iev.time.tv_usec, iev.type, iev.code, iev.value);
458 if (device->id == mFirstKeyboardId) {
459 outEvent->deviceId = 0;
460 } else {
461 outEvent->deviceId = device->id;
462 }
463 outEvent->type = iev.type;
464 outEvent->scanCode = iev.code;
Jeff Browna3477c82010-11-10 16:03:06 -0800465 outEvent->flags = 0;
Jeff Brown82763072010-08-17 16:48:25 -0700466 if (iev.type == EV_KEY) {
Jeff Browna3477c82010-11-10 16:03:06 -0800467 outEvent->keyCode = AKEYCODE_UNKNOWN;
468 if (device->layoutMap) {
469 status_t err = device->layoutMap->map(iev.code,
470 &outEvent->keyCode, &outEvent->flags);
471 LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
472 iev.code, outEvent->keyCode, outEvent->flags, err);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800473 }
Jeff Brown82763072010-08-17 16:48:25 -0700474 } else {
475 outEvent->keyCode = iev.code;
476 }
477 outEvent->value = iev.value;
478
479 // Use an event timestamp in the same timebase as
480 // java.lang.System.nanoTime() and android.os.SystemClock.uptimeMillis()
481 // as expected by the rest of the system.
482 outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
483 return true;
484 }
485
486 // Finish reading all events from devices identified in previous poll().
487 // This code assumes that mInputDeviceIndex is initially 0 and that the
488 // revents member of pollfd is initialized to 0 when the device is first added.
489 // Since mFDs[0] is used for inotify, we process regular events starting at index 1.
490 mInputDeviceIndex += 1;
491 if (mInputDeviceIndex >= mFDCount) {
Jeff Brown82763072010-08-17 16:48:25 -0700492 break;
493 }
494
Jeff Brown7e40f362010-10-14 02:23:43 -0700495 const struct pollfd& pfd = mFDs[mInputDeviceIndex];
Jeff Brown82763072010-08-17 16:48:25 -0700496 if (pfd.revents & POLLIN) {
497 int32_t readSize = read(pfd.fd, mInputBufferData,
498 sizeof(struct input_event) * INPUT_BUFFER_SIZE);
499 if (readSize < 0) {
500 if (errno != EAGAIN && errno != EINTR) {
501 LOGW("could not get event (errno=%d)", errno);
502 }
503 } else if ((readSize % sizeof(struct input_event)) != 0) {
504 LOGE("could not get event (wrong size: %d)", readSize);
505 } else {
506 mInputBufferCount = readSize / sizeof(struct input_event);
507 mInputBufferIndex = 0;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800508 }
509 }
510 }
Jeff Brown82763072010-08-17 16:48:25 -0700511
Jeff Brown7e40f362010-10-14 02:23:43 -0700512#if HAVE_INOTIFY
Jeff Brown1ad00e92010-10-01 18:55:43 -0700513 // readNotify() will modify mFDs and mFDCount, so this must be done after
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800514 // processing all other events.
515 if(mFDs[0].revents & POLLIN) {
Jeff Brown1ad00e92010-10-01 18:55:43 -0700516 readNotify(mFDs[0].fd);
Jeff Brown7e40f362010-10-14 02:23:43 -0700517 mFDs[0].revents = 0;
518 continue; // report added or removed devices immediately
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800519 }
Jeff Brown7e40f362010-10-14 02:23:43 -0700520#endif
521
522 mInputDeviceIndex = 0;
Jeff Brown82763072010-08-17 16:48:25 -0700523
524 // Poll for events. Mind the wake lock dance!
525 // We hold a wake lock at all times except during poll(). This works due to some
526 // subtle choreography. When a device driver has pending (unread) events, it acquires
527 // a kernel wake lock. However, once the last pending event has been read, the device
528 // driver will release the kernel wake lock. To prevent the system from going to sleep
529 // when this happens, the EventHub holds onto its own user wake lock while the client
530 // is processing events. Thus the system can only sleep if there are no events
531 // pending or currently being processed.
532 release_wake_lock(WAKE_LOCK_ID);
533
534 int pollResult = poll(mFDs, mFDCount, -1);
535
536 acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
537
538 if (pollResult <= 0) {
539 if (errno != EINTR) {
Jeff Brown7e40f362010-10-14 02:23:43 -0700540 LOGW("poll failed (errno=%d)\n", errno);
Jeff Brown82763072010-08-17 16:48:25 -0700541 usleep(100000);
542 }
543 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800544 }
545}
546
547/*
548 * Open the platform-specific input device.
549 */
550bool EventHub::openPlatformInput(void)
551{
552 /*
553 * Open platform-specific input device(s).
554 */
555 int res;
556
557 mFDCount = 1;
558 mFDs = (pollfd *)calloc(1, sizeof(mFDs[0]));
559 mDevices = (device_t **)calloc(1, sizeof(mDevices[0]));
560 mFDs[0].events = POLLIN;
Jeff Brown82763072010-08-17 16:48:25 -0700561 mFDs[0].revents = 0;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800562 mDevices[0] = NULL;
563#ifdef HAVE_INOTIFY
564 mFDs[0].fd = inotify_init();
565 res = inotify_add_watch(mFDs[0].fd, device_path, IN_DELETE | IN_CREATE);
566 if(res < 0) {
567 LOGE("could not add watch for %s, %s\n", device_path, strerror(errno));
568 }
569#else
570 /*
571 * The code in EventHub::getEvent assumes that mFDs[0] is an inotify fd.
572 * We allocate space for it and set it to something invalid.
573 */
574 mFDs[0].fd = -1;
575#endif
576
Jeff Brown1ad00e92010-10-01 18:55:43 -0700577 res = scanDir(device_path);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800578 if(res < 0) {
579 LOGE("scan dir failed for %s\n", device_path);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800580 }
581
582 return true;
583}
584
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800585// ----------------------------------------------------------------------------
586
Jeff Brown8575a872010-06-30 16:10:35 -0700587static bool containsNonZeroByte(const uint8_t* array, uint32_t startIndex, uint32_t endIndex) {
588 const uint8_t* end = array + endIndex;
589 array += startIndex;
590 while (array != end) {
591 if (*(array++) != 0) {
592 return true;
593 }
594 }
595 return false;
596}
597
598static const int32_t GAMEPAD_KEYCODES[] = {
599 AKEYCODE_BUTTON_A, AKEYCODE_BUTTON_B, AKEYCODE_BUTTON_C,
600 AKEYCODE_BUTTON_X, AKEYCODE_BUTTON_Y, AKEYCODE_BUTTON_Z,
601 AKEYCODE_BUTTON_L1, AKEYCODE_BUTTON_R1,
602 AKEYCODE_BUTTON_L2, AKEYCODE_BUTTON_R2,
603 AKEYCODE_BUTTON_THUMBL, AKEYCODE_BUTTON_THUMBR,
604 AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE
605};
606
Jeff Brown1ad00e92010-10-01 18:55:43 -0700607int EventHub::openDevice(const char *deviceName) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800608 int version;
609 int fd;
610 struct pollfd *new_mFDs;
611 device_t **new_devices;
612 char **new_device_names;
613 char name[80];
614 char location[80];
615 char idstr[80];
616 struct input_id id;
617
618 LOGV("Opening device: %s", deviceName);
619
620 AutoMutex _l(mLock);
Nick Pellyc81bb202010-01-20 19:36:49 -0800621
Nick Pelly1b5cf322010-01-26 10:27:15 -0800622 fd = open(deviceName, O_RDWR);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800623 if(fd < 0) {
624 LOGE("could not open %s, %s\n", deviceName, strerror(errno));
625 return -1;
626 }
627
628 if(ioctl(fd, EVIOCGVERSION, &version)) {
629 LOGE("could not get driver version for %s, %s\n", deviceName, strerror(errno));
630 return -1;
631 }
632 if(ioctl(fd, EVIOCGID, &id)) {
633 LOGE("could not get driver id for %s, %s\n", deviceName, strerror(errno));
634 return -1;
635 }
636 name[sizeof(name) - 1] = '\0';
637 location[sizeof(location) - 1] = '\0';
638 idstr[sizeof(idstr) - 1] = '\0';
639 if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
640 //fprintf(stderr, "could not get device name for %s, %s\n", deviceName, strerror(errno));
641 name[0] = '\0';
642 }
Mike Lockwood24a7e042009-07-17 00:10:10 -0400643
644 // check to see if the device is on our excluded list
645 List<String8>::iterator iter = mExcludedDevices.begin();
646 List<String8>::iterator end = mExcludedDevices.end();
647 for ( ; iter != end; iter++) {
648 const char* test = *iter;
649 if (strcmp(name, test) == 0) {
650 LOGI("ignoring event id %s driver %s\n", deviceName, test);
651 close(fd);
Mike Lockwood24a7e042009-07-17 00:10:10 -0400652 return -1;
653 }
654 }
655
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800656 if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
657 //fprintf(stderr, "could not get location for %s, %s\n", deviceName, strerror(errno));
658 location[0] = '\0';
659 }
660 if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
661 //fprintf(stderr, "could not get idstring for %s, %s\n", deviceName, strerror(errno));
662 idstr[0] = '\0';
663 }
664
Jeff Brown82763072010-08-17 16:48:25 -0700665 if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
666 LOGE("Error %d making device file descriptor non-blocking.", errno);
667 close(fd);
668 return -1;
669 }
670
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800671 int devid = 0;
672 while (devid < mNumDevicesById) {
673 if (mDevicesById[devid].device == NULL) {
674 break;
675 }
676 devid++;
677 }
678 if (devid >= mNumDevicesById) {
679 device_ent* new_devids = (device_ent*)realloc(mDevicesById,
680 sizeof(mDevicesById[0]) * (devid + 1));
681 if (new_devids == NULL) {
682 LOGE("out of memory");
683 return -1;
684 }
685 mDevicesById = new_devids;
686 mNumDevicesById = devid+1;
687 mDevicesById[devid].device = NULL;
688 mDevicesById[devid].seq = 0;
689 }
690
691 mDevicesById[devid].seq = (mDevicesById[devid].seq+(1<<SEQ_SHIFT))&SEQ_MASK;
692 if (mDevicesById[devid].seq == 0) {
693 mDevicesById[devid].seq = 1<<SEQ_SHIFT;
694 }
695
696 new_mFDs = (pollfd*)realloc(mFDs, sizeof(mFDs[0]) * (mFDCount + 1));
697 new_devices = (device_t**)realloc(mDevices, sizeof(mDevices[0]) * (mFDCount + 1));
698 if (new_mFDs == NULL || new_devices == NULL) {
699 LOGE("out of memory");
700 return -1;
701 }
702 mFDs = new_mFDs;
703 mDevices = new_devices;
704
705#if 0
706 LOGI("add device %d: %s\n", mFDCount, deviceName);
707 LOGI(" bus: %04x\n"
708 " vendor %04x\n"
709 " product %04x\n"
710 " version %04x\n",
711 id.bustype, id.vendor, id.product, id.version);
712 LOGI(" name: \"%s\"\n", name);
713 LOGI(" location: \"%s\"\n"
714 " id: \"%s\"\n", location, idstr);
715 LOGI(" version: %d.%d.%d\n",
716 version >> 16, (version >> 8) & 0xff, version & 0xff);
717#endif
718
Iliyan Malchev34193b32009-08-06 14:50:08 -0700719 device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName, name);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800720 if (device == NULL) {
721 LOGE("out of memory");
722 return -1;
723 }
724
Jens Gulin7dcaa582010-06-22 22:21:57 +0200725 device->fd = fd;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800726 mFDs[mFDCount].fd = fd;
727 mFDs[mFDCount].events = POLLIN;
Jeff Brown82763072010-08-17 16:48:25 -0700728 mFDs[mFDCount].revents = 0;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800729
Jeff Brown66888372010-11-29 17:37:49 -0800730 // Load the configuration file for the device.
731 loadConfiguration(device);
732
Jeff Brown8575a872010-06-30 16:10:35 -0700733 // Figure out the kinds of events the device reports.
Dianne Hackbornc5917362009-08-04 05:49:43 -0700734
Jeff Brown8575a872010-06-30 16:10:35 -0700735 uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800736 memset(key_bitmask, 0, sizeof(key_bitmask));
Jeff Brown8575a872010-06-30 16:10:35 -0700737
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800738 LOGV("Getting keys...");
739 if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) {
740 //LOGI("MAP\n");
Jeff Brown8575a872010-06-30 16:10:35 -0700741 //for (int i = 0; i < sizeof(key_bitmask); i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800742 // LOGI("%d: 0x%02x\n", i, key_bitmask[i]);
743 //}
Jeff Brown8575a872010-06-30 16:10:35 -0700744
745 // See if this is a keyboard. Ignore everything in the button range except for
746 // gamepads which are also considered keyboards.
747 if (containsNonZeroByte(key_bitmask, 0, sizeof_bit_array(BTN_MISC))
748 || containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_GAMEPAD),
749 sizeof_bit_array(BTN_DIGI))
750 || containsNonZeroByte(key_bitmask, sizeof_bit_array(KEY_OK),
751 sizeof_bit_array(KEY_MAX + 1))) {
752 device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
753
Dianne Hackbornc5917362009-08-04 05:49:43 -0700754 device->keyBitmask = new uint8_t[sizeof(key_bitmask)];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800755 if (device->keyBitmask != NULL) {
756 memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
757 } else {
758 delete device;
759 LOGE("out of memory allocating key bitmask");
760 return -1;
761 }
762 }
763 }
Dianne Hackbornc5917362009-08-04 05:49:43 -0700764
Jeff Brown8575a872010-06-30 16:10:35 -0700765 // See if this is a trackball (or mouse).
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800766 if (test_bit(BTN_MOUSE, key_bitmask)) {
Jeff Brown8575a872010-06-30 16:10:35 -0700767 uint8_t rel_bitmask[sizeof_bit_array(REL_MAX + 1)];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800768 memset(rel_bitmask, 0, sizeof(rel_bitmask));
769 LOGV("Getting relative controllers...");
Jeff Brown8575a872010-06-30 16:10:35 -0700770 if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800771 if (test_bit(REL_X, rel_bitmask) && test_bit(REL_Y, rel_bitmask)) {
Jeff Browne839a582010-04-22 18:58:52 -0700772 device->classes |= INPUT_DEVICE_CLASS_TRACKBALL;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800773 }
774 }
775 }
Jeff Brown8575a872010-06-30 16:10:35 -0700776
777 // See if this is a touch pad.
778 uint8_t abs_bitmask[sizeof_bit_array(ABS_MAX + 1)];
Dianne Hackbornc5917362009-08-04 05:49:43 -0700779 memset(abs_bitmask, 0, sizeof(abs_bitmask));
780 LOGV("Getting absolute controllers...");
Jeff Brown8575a872010-06-30 16:10:35 -0700781 if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0) {
782 // Is this a new modern multi-touch driver?
Jeff Brown38a7fab2010-08-30 03:02:23 -0700783 if (test_bit(ABS_MT_POSITION_X, abs_bitmask)
Jeff Brown8575a872010-06-30 16:10:35 -0700784 && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) {
785 device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT;
786
787 // Is this an old style single-touch driver?
788 } else if (test_bit(BTN_TOUCH, key_bitmask)
789 && test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {
790 device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN;
791 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800792 }
793
794#ifdef EV_SW
795 // figure out the switches this device reports
Jeff Brown8575a872010-06-30 16:10:35 -0700796 uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800797 memset(sw_bitmask, 0, sizeof(sw_bitmask));
Jeff Browne57e8952010-07-23 21:28:06 -0700798 bool hasSwitches = false;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800799 if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask) >= 0) {
800 for (int i=0; i<EV_SW; i++) {
801 //LOGI("Device 0x%x sw %d: has=%d", device->id, i, test_bit(i, sw_bitmask));
802 if (test_bit(i, sw_bitmask)) {
Jeff Browne57e8952010-07-23 21:28:06 -0700803 hasSwitches = true;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800804 if (mSwitches[i] == 0) {
805 mSwitches[i] = device->id;
806 }
807 }
808 }
809 }
Jeff Browne57e8952010-07-23 21:28:06 -0700810 if (hasSwitches) {
811 device->classes |= INPUT_DEVICE_CLASS_SWITCH;
812 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800813#endif
814
Jeff Browne839a582010-04-22 18:58:52 -0700815 if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800816 // a more descriptive name
Iliyan Malchev34193b32009-08-06 14:50:08 -0700817 device->name = name;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800818
Jeff Brown6a817e22010-09-12 17:55:08 -0700819 // Configure the keymap for the device.
820 configureKeyMap(device);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800821
Jeff Brown6a817e22010-09-12 17:55:08 -0700822 // Tell the world about the devname (the descriptive name)
Jeff Browna3477c82010-11-10 16:03:06 -0800823 if (!mHaveFirstKeyboard && !device->keyMapInfo.isDefaultKeyMap && strstr(name, "-keypad")) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800824 // the built-in keyboard has a well-known device ID of 0,
825 // this device better not go away.
826 mHaveFirstKeyboard = true;
827 mFirstKeyboardId = device->id;
Jeff Brown6a817e22010-09-12 17:55:08 -0700828 setKeyboardProperties(device, true);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800829 } else {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800830 // ensure mFirstKeyboardId is set to -something-.
Jeff Brown6a817e22010-09-12 17:55:08 -0700831 if (mFirstKeyboardId == -1) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800832 mFirstKeyboardId = device->id;
Jeff Brown6a817e22010-09-12 17:55:08 -0700833 setKeyboardProperties(device, true);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800834 }
835 }
Jeff Brown6a817e22010-09-12 17:55:08 -0700836 setKeyboardProperties(device, false);
837
838 // Load the keylayout.
Jeff Browna3477c82010-11-10 16:03:06 -0800839 if (!device->keyMapInfo.keyLayoutFile.isEmpty()) {
840 status_t status = KeyLayoutMap::load(device->keyMapInfo.keyLayoutFile,
841 &device->layoutMap);
Jeff Brown6a817e22010-09-12 17:55:08 -0700842 if (status) {
843 LOGE("Error %d loading key layout file '%s'.", status,
Jeff Browna3477c82010-11-10 16:03:06 -0800844 device->keyMapInfo.keyLayoutFile.string());
Jeff Brown6a817e22010-09-12 17:55:08 -0700845 }
846 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800847
Dianne Hackbornc5917362009-08-04 05:49:43 -0700848 // 'Q' key support = cheap test of whether this is an alpha-capable kbd
Jeff Brown2806e382010-10-01 17:46:21 -0700849 if (hasKeycodeLocked(device, AKEYCODE_Q)) {
Jeff Browne839a582010-04-22 18:58:52 -0700850 device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY;
Dianne Hackbornc5917362009-08-04 05:49:43 -0700851 }
Jeff Brown6a817e22010-09-12 17:55:08 -0700852
Jeff Brown8575a872010-06-30 16:10:35 -0700853 // See if this device has a DPAD.
Jeff Brown2806e382010-10-01 17:46:21 -0700854 if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) &&
855 hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) &&
856 hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) &&
857 hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) &&
858 hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) {
Jeff Browne839a582010-04-22 18:58:52 -0700859 device->classes |= INPUT_DEVICE_CLASS_DPAD;
Dianne Hackbornc5917362009-08-04 05:49:43 -0700860 }
Jeff Brown6a817e22010-09-12 17:55:08 -0700861
Jeff Brown8575a872010-06-30 16:10:35 -0700862 // See if this device has a gamepad.
Kenny Rootbc9c82f2010-10-21 15:46:03 -0700863 for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) {
Jeff Brown2806e382010-10-01 17:46:21 -0700864 if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) {
Jeff Brown8575a872010-06-30 16:10:35 -0700865 device->classes |= INPUT_DEVICE_CLASS_GAMEPAD;
866 break;
867 }
868 }
869
Jeff Brown6a817e22010-09-12 17:55:08 -0700870 LOGI("New keyboard: device->id=0x%x devname='%s' keylayout='%s' keycharactermap='%s'\n",
871 device->id, name,
Jeff Browna3477c82010-11-10 16:03:06 -0800872 device->keyMapInfo.keyLayoutFile.string(),
873 device->keyMapInfo.keyCharacterMapFile.string());
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800874 }
875
Sean McNeil2e7a5302010-06-23 16:00:37 +0700876 // If the device isn't recognized as something we handle, don't monitor it.
877 if (device->classes == 0) {
878 LOGV("Dropping device %s %p, id = %d\n", deviceName, device, devid);
879 close(fd);
880 delete device;
881 return -1;
882 }
883
Jeff Brown66888372010-11-29 17:37:49 -0800884 LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x "
885 "configuration='%s'\n",
886 deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes,
887 device->configurationFile.string());
888
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800889 LOGV("Adding device %s %p at %d, id = %d, classes = 0x%x\n",
890 deviceName, device, mFDCount, devid, device->classes);
891
892 mDevicesById[devid].device = device;
893 device->next = mOpeningDevices;
894 mOpeningDevices = device;
895 mDevices[mFDCount] = device;
896
897 mFDCount++;
898 return 0;
899}
900
Jeff Brown66888372010-11-29 17:37:49 -0800901void EventHub::loadConfiguration(device_t* device) {
902 device->configurationFile = getInputDeviceConfigurationFilePath(device->name,
903 INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION);
904 if (device->configurationFile.isEmpty()) {
905 LOGI("No input device configuration file found for device '%s'.",
906 device->name.string());
907 } else {
908 status_t status = PropertyMap::load(device->configurationFile,
909 &device->configuration);
910 if (status) {
911 LOGE("Error loading input device configuration file for device '%s'.",
912 device->name.string());
913 }
914 }
915}
916
Jeff Brown6a817e22010-09-12 17:55:08 -0700917void EventHub::configureKeyMap(device_t* device) {
Jeff Brown66888372010-11-29 17:37:49 -0800918 android::resolveKeyMap(device->name, device->configuration, device->keyMapInfo);
Jeff Brown6a817e22010-09-12 17:55:08 -0700919}
920
921void EventHub::setKeyboardProperties(device_t* device, bool firstKeyboard) {
922 int32_t id = firstKeyboard ? 0 : device->id;
Jeff Browna3477c82010-11-10 16:03:06 -0800923 android::setKeyboardProperties(id, device->name, device->keyMapInfo);
Jeff Brown6a817e22010-09-12 17:55:08 -0700924}
925
926void EventHub::clearKeyboardProperties(device_t* device, bool firstKeyboard) {
927 int32_t id = firstKeyboard ? 0 : device->id;
Jeff Browna3477c82010-11-10 16:03:06 -0800928 android::clearKeyboardProperties(id);
Jeff Brown6a817e22010-09-12 17:55:08 -0700929}
930
Jeff Brown2806e382010-10-01 17:46:21 -0700931bool EventHub::hasKeycodeLocked(device_t* device, int keycode) const
Dianne Hackbornc5917362009-08-04 05:49:43 -0700932{
933 if (device->keyBitmask == NULL || device->layoutMap == NULL) {
934 return false;
935 }
936
937 Vector<int32_t> scanCodes;
Jeff Browna3477c82010-11-10 16:03:06 -0800938 device->layoutMap->findScanCodes(keycode, &scanCodes);
Dianne Hackbornc5917362009-08-04 05:49:43 -0700939 const size_t N = scanCodes.size();
940 for (size_t i=0; i<N && i<=KEY_MAX; i++) {
941 int32_t sc = scanCodes.itemAt(i);
942 if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, device->keyBitmask)) {
943 return true;
944 }
945 }
946
947 return false;
948}
949
Jeff Brown1ad00e92010-10-01 18:55:43 -0700950int EventHub::closeDevice(const char *deviceName) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800951 AutoMutex _l(mLock);
Jeff Brown1ad00e92010-10-01 18:55:43 -0700952
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800953 int i;
954 for(i = 1; i < mFDCount; i++) {
955 if(strcmp(mDevices[i]->path.string(), deviceName) == 0) {
956 //LOGD("remove device %d: %s\n", i, deviceName);
957 device_t* device = mDevices[i];
Dianne Hackborn39bf9182009-09-01 19:01:50 -0700958
959 LOGI("Removed device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
960 device->path.string(), device->name.string(), device->id,
961 mNumDevicesById, mFDCount, mFDs[i].fd, device->classes);
962
963 // Clear this device's entry.
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800964 int index = (device->id&ID_MASK);
965 mDevicesById[index].device = NULL;
Dianne Hackborn39bf9182009-09-01 19:01:50 -0700966
967 // Close the file descriptor and compact the fd array.
Mike Lockwood07549f92009-08-28 13:29:06 -0700968 close(mFDs[i].fd);
Dianne Hackborn39bf9182009-09-01 19:01:50 -0700969 int count = mFDCount - i - 1;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800970 memmove(mDevices + i, mDevices + i + 1, sizeof(mDevices[0]) * count);
971 memmove(mFDs + i, mFDs + i + 1, sizeof(mFDs[0]) * count);
Dianne Hackborn39bf9182009-09-01 19:01:50 -0700972 mFDCount--;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800973
974#ifdef EV_SW
975 for (int j=0; j<EV_SW; j++) {
976 if (mSwitches[j] == device->id) {
977 mSwitches[j] = 0;
978 }
979 }
980#endif
981
982 device->next = mClosingDevices;
983 mClosingDevices = device;
984
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800985 if (device->id == mFirstKeyboardId) {
986 LOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
987 device->path.string(), mFirstKeyboardId);
Jeff Brown6a817e22010-09-12 17:55:08 -0700988 mFirstKeyboardId = -1;
989 clearKeyboardProperties(device, true);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800990 }
Jeff Brown6a817e22010-09-12 17:55:08 -0700991 clearKeyboardProperties(device, false);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800992 return 0;
993 }
994 }
Dianne Hackborn39bf9182009-09-01 19:01:50 -0700995 LOGE("remove device: %s not found\n", deviceName);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800996 return -1;
997}
998
Jeff Brown1ad00e92010-10-01 18:55:43 -0700999int EventHub::readNotify(int nfd) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001000#ifdef HAVE_INOTIFY
1001 int res;
1002 char devname[PATH_MAX];
1003 char *filename;
1004 char event_buf[512];
1005 int event_size;
1006 int event_pos = 0;
1007 struct inotify_event *event;
1008
Jeff Brown1ad00e92010-10-01 18:55:43 -07001009 LOGV("EventHub::readNotify nfd: %d\n", nfd);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001010 res = read(nfd, event_buf, sizeof(event_buf));
1011 if(res < (int)sizeof(*event)) {
1012 if(errno == EINTR)
1013 return 0;
1014 LOGW("could not get event, %s\n", strerror(errno));
1015 return 1;
1016 }
1017 //printf("got %d bytes of event information\n", res);
1018
1019 strcpy(devname, device_path);
1020 filename = devname + strlen(devname);
1021 *filename++ = '/';
1022
1023 while(res >= (int)sizeof(*event)) {
1024 event = (struct inotify_event *)(event_buf + event_pos);
1025 //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
1026 if(event->len) {
1027 strcpy(filename, event->name);
1028 if(event->mask & IN_CREATE) {
Jeff Brown1ad00e92010-10-01 18:55:43 -07001029 openDevice(devname);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001030 }
1031 else {
Jeff Brown1ad00e92010-10-01 18:55:43 -07001032 closeDevice(devname);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001033 }
1034 }
1035 event_size = sizeof(*event) + event->len;
1036 res -= event_size;
1037 event_pos += event_size;
1038 }
1039#endif
1040 return 0;
1041}
1042
1043
Jeff Brown1ad00e92010-10-01 18:55:43 -07001044int EventHub::scanDir(const char *dirname)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001045{
1046 char devname[PATH_MAX];
1047 char *filename;
1048 DIR *dir;
1049 struct dirent *de;
1050 dir = opendir(dirname);
1051 if(dir == NULL)
1052 return -1;
1053 strcpy(devname, dirname);
1054 filename = devname + strlen(devname);
1055 *filename++ = '/';
1056 while((de = readdir(dir))) {
1057 if(de->d_name[0] == '.' &&
1058 (de->d_name[1] == '\0' ||
1059 (de->d_name[1] == '.' && de->d_name[2] == '\0')))
1060 continue;
1061 strcpy(filename, de->d_name);
Jeff Brown1ad00e92010-10-01 18:55:43 -07001062 openDevice(devname);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001063 }
1064 closedir(dir);
1065 return 0;
1066}
1067
Jeff Brown2806e382010-10-01 17:46:21 -07001068void EventHub::dump(String8& dump) {
1069 dump.append("Event Hub State:\n");
1070
1071 { // acquire lock
1072 AutoMutex _l(mLock);
1073
1074 dump.appendFormat(INDENT "HaveFirstKeyboard: %s\n", toString(mHaveFirstKeyboard));
1075 dump.appendFormat(INDENT "FirstKeyboardId: 0x%x\n", mFirstKeyboardId);
1076
1077 dump.append(INDENT "Devices:\n");
1078
1079 for (int i = 0; i < mNumDevicesById; i++) {
1080 const device_t* device = mDevicesById[i].device;
1081 if (device) {
1082 if (mFirstKeyboardId == device->id) {
1083 dump.appendFormat(INDENT2 "0x%x: %s (aka device 0 - first keyboard)\n",
1084 device->id, device->name.string());
1085 } else {
1086 dump.appendFormat(INDENT2 "0x%x: %s\n", device->id, device->name.string());
1087 }
1088 dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes);
1089 dump.appendFormat(INDENT3 "Path: %s\n", device->path.string());
Jeff Browna3477c82010-11-10 16:03:06 -08001090 dump.appendFormat(INDENT3 "IsDefaultKeyMap: %s\n",
1091 toString(device->keyMapInfo.isDefaultKeyMap));
Jeff Browna3477c82010-11-10 16:03:06 -08001092 dump.appendFormat(INDENT3 "KeyLayoutFile: %s\n",
1093 device->keyMapInfo.keyLayoutFile.string());
1094 dump.appendFormat(INDENT3 "KeyCharacterMapFile: %s\n",
1095 device->keyMapInfo.keyCharacterMapFile.string());
Jeff Brown66888372010-11-29 17:37:49 -08001096 dump.appendFormat(INDENT3 "ConfigurationFile: %s\n",
1097 device->configurationFile.string());
Jeff Brown2806e382010-10-01 17:46:21 -07001098 }
1099 }
1100 } // release lock
1101}
1102
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001103}; // namespace android