blob: ff4b11a937f842217444bb194a4096bccfd08280 [file] [log] [blame]
Jeff Brownb4ff35d2011-01-02 16:37:43 -08001/*
2 * Copyright (C) 2005 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080017//
18// Handle events, like key input and vsync.
19//
20// The goal is to provide an optimized solution for Linux, not an
21// implementation that works well across all platforms. We expect
22// events to arrive on file descriptors, so that we can use a select()
23// select() call to sleep.
24//
25// We can't select() on anything but network sockets in Windows, so we
26// provide an alternative implementation of waitEvent for that platform.
27//
28#define LOG_TAG "EventHub"
29
30//#define LOG_NDEBUG 0
31
Jeff Brownb4ff35d2011-01-02 16:37:43 -080032#include "EventHub.h"
33
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034#include <hardware_legacy/power.h>
35
36#include <cutils/properties.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037#include <utils/Log.h>
38#include <utils/Timers.h>
Mathias Agopian3b4062e2009-05-31 19:13:00 -070039#include <utils/threads.h>
Mathias Agopian3b4062e2009-05-31 19:13:00 -070040#include <utils/Errors.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041
42#include <stdlib.h>
43#include <stdio.h>
44#include <unistd.h>
45#include <fcntl.h>
46#include <memory.h>
47#include <errno.h>
48#include <assert.h>
49
Jeff Brown6b53e8d2010-11-10 16:03:06 -080050#include <ui/KeyLayoutMap.h>
Jeff Brown90655042010-12-02 13:50:46 -080051#include <ui/KeyCharacterMap.h>
52#include <ui/VirtualKeyMap.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053
54#include <string.h>
55#include <stdint.h>
56#include <dirent.h>
57#ifdef HAVE_INOTIFY
58# include <sys/inotify.h>
59#endif
60#ifdef HAVE_ANDROID_OS
61# include <sys/limits.h> /* not part of Linux */
62#endif
63#include <sys/poll.h>
64#include <sys/ioctl.h>
65
66/* this macro is used to tell if "bit" is set in "array"
67 * it selects a byte from the array, and does a boolean AND
68 * operation with a byte that only has the relevant bit set.
69 * eg. to check for the 12th bit, we do (array[1] & 1<<4)
70 */
71#define test_bit(bit, array) (array[bit/8] & (1<<(bit%8)))
72
Jeff Brownfd035822010-06-30 16:10:35 -070073/* this macro computes the number of bytes needed to represent a bit array of the specified size */
74#define sizeof_bit_array(bits) ((bits + 7) / 8)
75
Jeff Brown90655042010-12-02 13:50:46 -080076// Fd at index 0 is always reserved for inotify
77#define FIRST_ACTUAL_DEVICE_INDEX 1
78
Jeff Brownf2f48712010-10-01 17:46:21 -070079#define INDENT " "
80#define INDENT2 " "
81#define INDENT3 " "
82
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083namespace android {
84
85static const char *WAKE_LOCK_ID = "KeyEvents";
Jeff Brown90655042010-12-02 13:50:46 -080086static const char *DEVICE_PATH = "/dev/input";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087
88/* return the larger integer */
89static inline int max(int v1, int v2)
90{
91 return (v1 > v2) ? v1 : v2;
92}
93
Jeff Brownf2f48712010-10-01 17:46:21 -070094static inline const char* toString(bool value) {
95 return value ? "true" : "false";
96}
97
Jeff Brown90655042010-12-02 13:50:46 -080098// --- EventHub::Device ---
99
100EventHub::Device::Device(int fd, int32_t id, const String8& path,
101 const InputDeviceIdentifier& identifier) :
102 next(NULL),
103 fd(fd), id(id), path(path), identifier(identifier),
Jeff Browncc0c1592011-02-19 05:07:28 -0800104 classes(0), keyBitmask(NULL), relBitmask(NULL),
105 configuration(NULL), virtualKeyMap(NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106}
107
Jeff Brown90655042010-12-02 13:50:46 -0800108EventHub::Device::~Device() {
109 close();
110 delete[] keyBitmask;
Jeff Browncc0c1592011-02-19 05:07:28 -0800111 delete[] relBitmask;
Jeff Brown47e6b1b2010-11-29 17:37:49 -0800112 delete configuration;
Jeff Brown90655042010-12-02 13:50:46 -0800113 delete virtualKeyMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114}
115
Jeff Brown90655042010-12-02 13:50:46 -0800116void EventHub::Device::close() {
117 if (fd >= 0) {
118 ::close(fd);
119 fd = -1;
120 }
121}
122
123
124// --- EventHub ---
125
126EventHub::EventHub(void) :
127 mError(NO_INIT), mBuiltInKeyboardId(-1), mNextDeviceId(1),
128 mOpeningDevices(0), mClosingDevices(0),
129 mOpened(false), mNeedToSendFinishedDeviceScan(false),
Jeff Brownb7198742011-03-18 18:14:26 -0700130 mInputFdIndex(1) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131 acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
Jeff Brownb7198742011-03-18 18:14:26 -0700132
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 memset(mSwitches, 0, sizeof(mSwitches));
Jeff Brownb7198742011-03-18 18:14:26 -0700134 mNumCpus = sysconf(_SC_NPROCESSORS_ONLN);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135}
136
Jeff Brown90655042010-12-02 13:50:46 -0800137EventHub::~EventHub(void) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138 release_wake_lock(WAKE_LOCK_ID);
139 // we should free stuff here...
140}
141
Jeff Brown90655042010-12-02 13:50:46 -0800142status_t EventHub::errorCheck() const {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 return mError;
144}
145
Jeff Brown90655042010-12-02 13:50:46 -0800146String8 EventHub::getDeviceName(int32_t deviceId) const {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 AutoMutex _l(mLock);
Jeff Brown90655042010-12-02 13:50:46 -0800148 Device* device = getDeviceLocked(deviceId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149 if (device == NULL) return String8();
Jeff Brown90655042010-12-02 13:50:46 -0800150 return device->identifier.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151}
152
Jeff Brown90655042010-12-02 13:50:46 -0800153uint32_t EventHub::getDeviceClasses(int32_t deviceId) const {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154 AutoMutex _l(mLock);
Jeff Brown90655042010-12-02 13:50:46 -0800155 Device* device = getDeviceLocked(deviceId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156 if (device == NULL) return 0;
157 return device->classes;
158}
159
Jeff Brown47e6b1b2010-11-29 17:37:49 -0800160void EventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const {
Jeff Brown47e6b1b2010-11-29 17:37:49 -0800161 AutoMutex _l(mLock);
Jeff Brown90655042010-12-02 13:50:46 -0800162 Device* device = getDeviceLocked(deviceId);
Jeff Brown47e6b1b2010-11-29 17:37:49 -0800163 if (device && device->configuration) {
164 *outConfiguration = *device->configuration;
Jeff Brown1f245102010-11-18 20:53:46 -0800165 } else {
166 outConfiguration->clear();
Jeff Brown47e6b1b2010-11-29 17:37:49 -0800167 }
168}
169
Jeff Brown6d0fec22010-07-23 21:28:06 -0700170status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis,
171 RawAbsoluteAxisInfo* outAxisInfo) const {
Jeff Brown8d608662010-08-30 03:02:23 -0700172 outAxisInfo->clear();
Jeff Brown6d0fec22010-07-23 21:28:06 -0700173
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174 AutoMutex _l(mLock);
Jeff Brown90655042010-12-02 13:50:46 -0800175 Device* device = getDeviceLocked(deviceId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176 if (device == NULL) return -1;
177
178 struct input_absinfo info;
179
Jens Gulinc4554b92010-06-22 22:21:57 +0200180 if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
Jeff Brown6d0fec22010-07-23 21:28:06 -0700181 LOGW("Error reading absolute controller %d for device %s fd %d\n",
Jeff Brown90655042010-12-02 13:50:46 -0800182 axis, device->identifier.name.string(), device->fd);
Jeff Brown6d0fec22010-07-23 21:28:06 -0700183 return -errno;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184 }
Jeff Brown6d0fec22010-07-23 21:28:06 -0700185
186 if (info.minimum != info.maximum) {
187 outAxisInfo->valid = true;
188 outAxisInfo->minValue = info.minimum;
189 outAxisInfo->maxValue = info.maximum;
190 outAxisInfo->flat = info.flat;
191 outAxisInfo->fuzz = info.fuzz;
192 }
193 return OK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194}
195
Jeff Browncc0c1592011-02-19 05:07:28 -0800196bool EventHub::hasRelativeAxis(int32_t deviceId, int axis) const {
197 if (axis >= 0 && axis <= REL_MAX) {
198 AutoMutex _l(mLock);
199
200 Device* device = getDeviceLocked(deviceId);
201 if (device && device->relBitmask) {
202 return test_bit(axis, device->relBitmask);
203 }
204 }
205 return false;
206}
207
Jeff Brown6d0fec22010-07-23 21:28:06 -0700208int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700209 if (scanCode >= 0 && scanCode <= KEY_MAX) {
210 AutoMutex _l(mLock);
211
Jeff Brown90655042010-12-02 13:50:46 -0800212 Device* device = getDeviceLocked(deviceId);
Jeff Brown6d0fec22010-07-23 21:28:06 -0700213 if (device != NULL) {
214 return getScanCodeStateLocked(device, scanCode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 }
216 }
Jeff Brownc5ed5912010-07-14 18:48:53 -0700217 return AKEY_STATE_UNKNOWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218}
219
Jeff Brown90655042010-12-02 13:50:46 -0800220int32_t EventHub::getScanCodeStateLocked(Device* device, int32_t scanCode) const {
Jeff Brownfd035822010-06-30 16:10:35 -0700221 uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
Jeff Brown46b9ac02010-04-22 18:58:52 -0700222 memset(key_bitmask, 0, sizeof(key_bitmask));
Jens Gulinc4554b92010-06-22 22:21:57 +0200223 if (ioctl(device->fd,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700224 EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
Jeff Brownc5ed5912010-07-14 18:48:53 -0700225 return test_bit(scanCode, key_bitmask) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700226 }
Jeff Brownc5ed5912010-07-14 18:48:53 -0700227 return AKEY_STATE_UNKNOWN;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700228}
229
Jeff Brown6d0fec22010-07-23 21:28:06 -0700230int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const {
231 AutoMutex _l(mLock);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700232
Jeff Brown90655042010-12-02 13:50:46 -0800233 Device* device = getDeviceLocked(deviceId);
Jeff Brown6d0fec22010-07-23 21:28:06 -0700234 if (device != NULL) {
235 return getKeyCodeStateLocked(device, keyCode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236 }
Jeff Brownc5ed5912010-07-14 18:48:53 -0700237 return AKEY_STATE_UNKNOWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238}
239
Jeff Brown90655042010-12-02 13:50:46 -0800240int32_t EventHub::getKeyCodeStateLocked(Device* device, int32_t keyCode) const {
241 if (!device->keyMap.haveKeyLayout()) {
Jeff Brown6b53e8d2010-11-10 16:03:06 -0800242 return AKEY_STATE_UNKNOWN;
243 }
244
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245 Vector<int32_t> scanCodes;
Jeff Brown6f2fba42011-02-19 01:08:02 -0800246 device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode, &scanCodes);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700247
Jeff Brownfd035822010-06-30 16:10:35 -0700248 uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 memset(key_bitmask, 0, sizeof(key_bitmask));
Jens Gulinc4554b92010-06-22 22:21:57 +0200250 if (ioctl(device->fd, EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251 #if 0
252 for (size_t i=0; i<=KEY_MAX; i++) {
253 LOGI("(Scan code %d: down=%d)", i, test_bit(i, key_bitmask));
254 }
255 #endif
256 const size_t N = scanCodes.size();
257 for (size_t i=0; i<N && i<=KEY_MAX; i++) {
258 int32_t sc = scanCodes.itemAt(i);
259 //LOGI("Code %d: down=%d", sc, test_bit(sc, key_bitmask));
260 if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, key_bitmask)) {
Jeff Brownc5ed5912010-07-14 18:48:53 -0700261 return AKEY_STATE_DOWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800262 }
263 }
Jeff Brownc5ed5912010-07-14 18:48:53 -0700264 return AKEY_STATE_UP;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 }
Jeff Brownc5ed5912010-07-14 18:48:53 -0700266 return AKEY_STATE_UNKNOWN;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700267}
268
Jeff Brown6d0fec22010-07-23 21:28:06 -0700269int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700270 if (sw >= 0 && sw <= SW_MAX) {
271 AutoMutex _l(mLock);
272
Jeff Brown90655042010-12-02 13:50:46 -0800273 Device* device = getDeviceLocked(deviceId);
Jeff Brown6d0fec22010-07-23 21:28:06 -0700274 if (device != NULL) {
275 return getSwitchStateLocked(device, sw);
Jeff Brown46b9ac02010-04-22 18:58:52 -0700276 }
Jeff Brown46b9ac02010-04-22 18:58:52 -0700277 }
Jeff Brownc5ed5912010-07-14 18:48:53 -0700278 return AKEY_STATE_UNKNOWN;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700279}
280
Jeff Brown90655042010-12-02 13:50:46 -0800281int32_t EventHub::getSwitchStateLocked(Device* device, int32_t sw) const {
Jeff Brownfd035822010-06-30 16:10:35 -0700282 uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)];
Jeff Brown46b9ac02010-04-22 18:58:52 -0700283 memset(sw_bitmask, 0, sizeof(sw_bitmask));
Jens Gulinc4554b92010-06-22 22:21:57 +0200284 if (ioctl(device->fd,
Jeff Brown46b9ac02010-04-22 18:58:52 -0700285 EVIOCGSW(sizeof(sw_bitmask)), sw_bitmask) >= 0) {
Jeff Brownc5ed5912010-07-14 18:48:53 -0700286 return test_bit(sw, sw_bitmask) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
Jeff Brown46b9ac02010-04-22 18:58:52 -0700287 }
Jeff Brownc5ed5912010-07-14 18:48:53 -0700288 return AKEY_STATE_UNKNOWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289}
290
Jeff Brown6d0fec22010-07-23 21:28:06 -0700291bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes,
292 const int32_t* keyCodes, uint8_t* outFlags) const {
293 AutoMutex _l(mLock);
294
Jeff Brown90655042010-12-02 13:50:46 -0800295 Device* device = getDeviceLocked(deviceId);
Jeff Brown6d0fec22010-07-23 21:28:06 -0700296 if (device != NULL) {
297 return markSupportedKeyCodesLocked(device, numCodes, keyCodes, outFlags);
298 }
299 return false;
300}
301
Jeff Brown90655042010-12-02 13:50:46 -0800302bool EventHub::markSupportedKeyCodesLocked(Device* device, size_t numCodes,
Jeff Brown6d0fec22010-07-23 21:28:06 -0700303 const int32_t* keyCodes, uint8_t* outFlags) const {
Jeff Brown90655042010-12-02 13:50:46 -0800304 if (!device->keyMap.haveKeyLayout() || !device->keyBitmask) {
Jeff Brown6d0fec22010-07-23 21:28:06 -0700305 return false;
306 }
307
308 Vector<int32_t> scanCodes;
309 for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) {
310 scanCodes.clear();
311
Jeff Brown6f2fba42011-02-19 01:08:02 -0800312 status_t err = device->keyMap.keyLayoutMap->findScanCodesForKey(
313 keyCodes[codeIndex], &scanCodes);
Jeff Brown6d0fec22010-07-23 21:28:06 -0700314 if (! err) {
315 // check the possible scan codes identified by the layout map against the
316 // map of codes actually emitted by the driver
317 for (size_t sc = 0; sc < scanCodes.size(); sc++) {
318 if (test_bit(scanCodes[sc], device->keyBitmask)) {
319 outFlags[codeIndex] = 1;
320 break;
321 }
322 }
323 }
324 }
325 return true;
326}
327
Jeff Brown6f2fba42011-02-19 01:08:02 -0800328status_t EventHub::mapKey(int32_t deviceId, int scancode,
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700329 int32_t* outKeycode, uint32_t* outFlags) const
330{
331 AutoMutex _l(mLock);
Jeff Brown90655042010-12-02 13:50:46 -0800332 Device* device = getDeviceLocked(deviceId);
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700333
Jeff Brown90655042010-12-02 13:50:46 -0800334 if (device && device->keyMap.haveKeyLayout()) {
Jeff Brown6f2fba42011-02-19 01:08:02 -0800335 status_t err = device->keyMap.keyLayoutMap->mapKey(scancode, outKeycode, outFlags);
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700336 if (err == NO_ERROR) {
337 return NO_ERROR;
338 }
339 }
340
Jeff Brown90655042010-12-02 13:50:46 -0800341 if (mBuiltInKeyboardId != -1) {
342 device = getDeviceLocked(mBuiltInKeyboardId);
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700343
Jeff Brown90655042010-12-02 13:50:46 -0800344 if (device && device->keyMap.haveKeyLayout()) {
Jeff Brown6f2fba42011-02-19 01:08:02 -0800345 status_t err = device->keyMap.keyLayoutMap->mapKey(scancode, outKeycode, outFlags);
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700346 if (err == NO_ERROR) {
347 return NO_ERROR;
348 }
349 }
350 }
351
352 *outKeycode = 0;
353 *outFlags = 0;
354 return NAME_NOT_FOUND;
355}
356
Jeff Brown85297452011-03-04 13:07:49 -0800357status_t EventHub::mapAxis(int32_t deviceId, int scancode, AxisInfo* outAxisInfo) const
Jeff Brown6f2fba42011-02-19 01:08:02 -0800358{
359 AutoMutex _l(mLock);
360 Device* device = getDeviceLocked(deviceId);
361
362 if (device && device->keyMap.haveKeyLayout()) {
Jeff Brown85297452011-03-04 13:07:49 -0800363 status_t err = device->keyMap.keyLayoutMap->mapAxis(scancode, outAxisInfo);
Jeff Brown6f2fba42011-02-19 01:08:02 -0800364 if (err == NO_ERROR) {
365 return NO_ERROR;
366 }
367 }
368
369 if (mBuiltInKeyboardId != -1) {
370 device = getDeviceLocked(mBuiltInKeyboardId);
371
372 if (device && device->keyMap.haveKeyLayout()) {
Jeff Brown85297452011-03-04 13:07:49 -0800373 status_t err = device->keyMap.keyLayoutMap->mapAxis(scancode, outAxisInfo);
Jeff Brown6f2fba42011-02-19 01:08:02 -0800374 if (err == NO_ERROR) {
375 return NO_ERROR;
376 }
377 }
378 }
379
Jeff Brown6f2fba42011-02-19 01:08:02 -0800380 return NAME_NOT_FOUND;
381}
382
Mike Lockwood1d9dfc52009-07-16 11:11:18 -0400383void EventHub::addExcludedDevice(const char* deviceName)
384{
Jeff Brownf2f48712010-10-01 17:46:21 -0700385 AutoMutex _l(mLock);
386
Mike Lockwood1d9dfc52009-07-16 11:11:18 -0400387 String8 name(deviceName);
388 mExcludedDevices.push_back(name);
389}
390
Jeff Brown497a92c2010-09-12 17:55:08 -0700391bool EventHub::hasLed(int32_t deviceId, int32_t led) const {
392 AutoMutex _l(mLock);
Jeff Brown90655042010-12-02 13:50:46 -0800393 Device* device = getDeviceLocked(deviceId);
Jeff Brown497a92c2010-09-12 17:55:08 -0700394 if (device) {
395 uint8_t bitmask[sizeof_bit_array(LED_MAX + 1)];
396 memset(bitmask, 0, sizeof(bitmask));
397 if (ioctl(device->fd, EVIOCGBIT(EV_LED, sizeof(bitmask)), bitmask) >= 0) {
398 if (test_bit(led, bitmask)) {
399 return true;
400 }
401 }
402 }
403 return false;
404}
405
406void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) {
407 AutoMutex _l(mLock);
Jeff Brown90655042010-12-02 13:50:46 -0800408 Device* device = getDeviceLocked(deviceId);
Jeff Brown497a92c2010-09-12 17:55:08 -0700409 if (device) {
410 struct input_event ev;
411 ev.time.tv_sec = 0;
412 ev.time.tv_usec = 0;
413 ev.type = EV_LED;
414 ev.code = led;
415 ev.value = on ? 1 : 0;
416
417 ssize_t nWrite;
418 do {
419 nWrite = write(device->fd, &ev, sizeof(struct input_event));
420 } while (nWrite == -1 && errno == EINTR);
421 }
422}
423
Jeff Brown90655042010-12-02 13:50:46 -0800424void EventHub::getVirtualKeyDefinitions(int32_t deviceId,
425 Vector<VirtualKeyDefinition>& outVirtualKeys) const {
426 outVirtualKeys.clear();
427
428 AutoMutex _l(mLock);
429 Device* device = getDeviceLocked(deviceId);
430 if (device && device->virtualKeyMap) {
431 outVirtualKeys.appendVector(device->virtualKeyMap->getVirtualKeys());
432 }
433}
434
435EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const {
436 if (deviceId == 0) {
437 deviceId = mBuiltInKeyboardId;
438 }
439
440 size_t numDevices = mDevices.size();
441 for (size_t i = FIRST_ACTUAL_DEVICE_INDEX; i < numDevices; i++) {
442 Device* device = mDevices[i];
443 if (device->id == deviceId) {
444 return device;
445 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800446 }
447 return NULL;
448}
449
Jeff Brownb7198742011-03-18 18:14:26 -0700450size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
451 // Note that we only allow one caller to getEvents(), so don't need
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 // to do locking here... only when adding/removing devices.
Jeff Brownb6110c22011-04-01 16:15:13 -0700453 LOG_ASSERT(bufferSize >= 1);
Mike Lockwood1d9dfc52009-07-16 11:11:18 -0400454
455 if (!mOpened) {
456 mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
457 mOpened = true;
Jeff Brown7342bb92010-10-01 18:55:43 -0700458 mNeedToSendFinishedDeviceScan = true;
Mike Lockwood1d9dfc52009-07-16 11:11:18 -0400459 }
460
Jeff Brownb7198742011-03-18 18:14:26 -0700461 struct input_event readBuffer[bufferSize];
462
463 RawEvent* event = buffer;
464 size_t capacity = bufferSize;
Jeff Browncc2e7172010-08-17 16:48:25 -0700465 for (;;) {
Jeff Brownb7198742011-03-18 18:14:26 -0700466 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
467
Jeff Browncc2e7172010-08-17 16:48:25 -0700468 // Report any devices that had last been added/removed.
Jeff Brownb7198742011-03-18 18:14:26 -0700469 while (mClosingDevices) {
Jeff Brown90655042010-12-02 13:50:46 -0800470 Device* device = mClosingDevices;
471 LOGV("Reporting device closed: id=%d, name=%s\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 device->id, device->path.string());
473 mClosingDevices = device->next;
Jeff Brownb7198742011-03-18 18:14:26 -0700474 event->when = now;
475 event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
476 event->type = DEVICE_REMOVED;
477 event += 1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800478 delete device;
Jeff Brown7342bb92010-10-01 18:55:43 -0700479 mNeedToSendFinishedDeviceScan = true;
Jeff Brownb7198742011-03-18 18:14:26 -0700480 if (--capacity == 0) {
481 break;
482 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800483 }
Jeff Brown6d0fec22010-07-23 21:28:06 -0700484
Jeff Brownb7198742011-03-18 18:14:26 -0700485 while (mOpeningDevices != NULL) {
Jeff Brown90655042010-12-02 13:50:46 -0800486 Device* device = mOpeningDevices;
487 LOGV("Reporting device opened: id=%d, name=%s\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800488 device->id, device->path.string());
489 mOpeningDevices = device->next;
Jeff Brownb7198742011-03-18 18:14:26 -0700490 event->when = now;
491 event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
492 event->type = DEVICE_ADDED;
493 event += 1;
Jeff Brown7342bb92010-10-01 18:55:43 -0700494 mNeedToSendFinishedDeviceScan = true;
Jeff Brownb7198742011-03-18 18:14:26 -0700495 if (--capacity == 0) {
496 break;
497 }
Jeff Brown7342bb92010-10-01 18:55:43 -0700498 }
499
500 if (mNeedToSendFinishedDeviceScan) {
501 mNeedToSendFinishedDeviceScan = false;
Jeff Brownb7198742011-03-18 18:14:26 -0700502 event->when = now;
503 event->type = FINISHED_DEVICE_SCAN;
504 event += 1;
505 if (--capacity == 0) {
506 break;
507 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 }
509
Jeff Browncc2e7172010-08-17 16:48:25 -0700510 // Grab the next input event.
Jeff Brownb7198742011-03-18 18:14:26 -0700511 // mInputFdIndex is initially 1 because index 0 is used for inotify.
Jeff Brown33bbfd22011-02-24 20:55:35 -0800512 bool deviceWasRemoved = false;
Jeff Brownb7198742011-03-18 18:14:26 -0700513 while (mInputFdIndex < mFds.size()) {
Jeff Brown90655042010-12-02 13:50:46 -0800514 const struct pollfd& pfd = mFds[mInputFdIndex];
Jeff Browncc2e7172010-08-17 16:48:25 -0700515 if (pfd.revents & POLLIN) {
Jeff Brownb7198742011-03-18 18:14:26 -0700516 int32_t readSize = read(pfd.fd, readBuffer, sizeof(struct input_event) * capacity);
Jeff Browncc2e7172010-08-17 16:48:25 -0700517 if (readSize < 0) {
Jeff Brown33bbfd22011-02-24 20:55:35 -0800518 if (errno == ENODEV) {
519 deviceWasRemoved = true;
520 break;
521 }
Jeff Browncc2e7172010-08-17 16:48:25 -0700522 if (errno != EAGAIN && errno != EINTR) {
523 LOGW("could not get event (errno=%d)", errno);
524 }
525 } else if ((readSize % sizeof(struct input_event)) != 0) {
526 LOGE("could not get event (wrong size: %d)", readSize);
Jeff Brownb7198742011-03-18 18:14:26 -0700527 } else if (readSize == 0) { // eof
528 deviceWasRemoved = true;
529 break;
Jeff Browncc2e7172010-08-17 16:48:25 -0700530 } else {
Jeff Brownb7198742011-03-18 18:14:26 -0700531 const Device* device = mDevices[mInputFdIndex];
532 int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
533
534 size_t count = size_t(readSize) / sizeof(struct input_event);
535 for (size_t i = 0; i < count; i++) {
536 const struct input_event& iev = readBuffer[i];
537 LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, value=%d",
538 device->path.string(),
539 (int) iev.time.tv_sec, (int) iev.time.tv_usec,
540 iev.type, iev.code, iev.value);
541
Jeff Brown4e91a182011-04-07 11:38:09 -0700542#ifdef HAVE_POSIX_CLOCKS
543 // Use the time specified in the event instead of the current time
544 // so that downstream code can get more accurate estimates of
545 // event dispatch latency from the time the event is enqueued onto
546 // the evdev client buffer.
547 //
548 // The event's timestamp fortuitously uses the same monotonic clock
549 // time base as the rest of Android. The kernel event device driver
550 // (drivers/input/evdev.c) obtains timestamps using ktime_get_ts().
551 // The systemTime(SYSTEM_TIME_MONOTONIC) function we use everywhere
552 // calls clock_gettime(CLOCK_MONOTONIC) which is implemented as a
553 // system call that also queries ktime_get_ts().
554 event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL
555 + nsecs_t(iev.time.tv_usec) * 1000LL;
556 LOGV("event time %lld, now %lld", event->when, now);
557#else
Jeff Brownb7198742011-03-18 18:14:26 -0700558 event->when = now;
Jeff Brown4e91a182011-04-07 11:38:09 -0700559#endif
Jeff Brownb7198742011-03-18 18:14:26 -0700560 event->deviceId = deviceId;
561 event->type = iev.type;
562 event->scanCode = iev.code;
563 event->value = iev.value;
564 event->keyCode = AKEYCODE_UNKNOWN;
565 event->flags = 0;
566 if (iev.type == EV_KEY && device->keyMap.haveKeyLayout()) {
567 status_t err = device->keyMap.keyLayoutMap->mapKey(iev.code,
568 &event->keyCode, &event->flags);
569 LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
570 iev.code, event->keyCode, event->flags, err);
571 }
572 event += 1;
573 }
574 capacity -= count;
575 if (capacity == 0) {
576 break;
577 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 }
579 }
Jeff Brownb7198742011-03-18 18:14:26 -0700580 mInputFdIndex += 1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 }
Jeff Browncc2e7172010-08-17 16:48:25 -0700582
Jeff Brown33bbfd22011-02-24 20:55:35 -0800583 // Handle the case where a device has been removed but INotify has not yet noticed.
584 if (deviceWasRemoved) {
585 AutoMutex _l(mLock);
586 closeDeviceAtIndexLocked(mInputFdIndex);
587 continue; // report added or removed devices immediately
588 }
589
Jeff Browna9b84222010-10-14 02:23:43 -0700590#if HAVE_INOTIFY
Jeff Brown7342bb92010-10-01 18:55:43 -0700591 // readNotify() will modify mFDs and mFDCount, so this must be done after
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800592 // processing all other events.
Jeff Brown90655042010-12-02 13:50:46 -0800593 if(mFds[0].revents & POLLIN) {
594 readNotify(mFds[0].fd);
595 mFds.editItemAt(0).revents = 0;
Jeff Brownb7198742011-03-18 18:14:26 -0700596 mInputFdIndex = mFds.size();
Jeff Browna9b84222010-10-14 02:23:43 -0700597 continue; // report added or removed devices immediately
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 }
Jeff Browna9b84222010-10-14 02:23:43 -0700599#endif
600
Jeff Brownb7198742011-03-18 18:14:26 -0700601 // Return now if we have collected any events, otherwise poll.
602 if (event != buffer) {
603 break;
604 }
605
Jeff Browncc2e7172010-08-17 16:48:25 -0700606 // Poll for events. Mind the wake lock dance!
607 // We hold a wake lock at all times except during poll(). This works due to some
608 // subtle choreography. When a device driver has pending (unread) events, it acquires
609 // a kernel wake lock. However, once the last pending event has been read, the device
610 // driver will release the kernel wake lock. To prevent the system from going to sleep
611 // when this happens, the EventHub holds onto its own user wake lock while the client
612 // is processing events. Thus the system can only sleep if there are no events
613 // pending or currently being processed.
Jeff Brownaa3855d2011-03-17 01:34:19 -0700614 //
615 // The timeout is advisory only. If the device is asleep, it will not wake just to
616 // service the timeout.
Jeff Browncc2e7172010-08-17 16:48:25 -0700617 release_wake_lock(WAKE_LOCK_ID);
618
Jeff Brownaa3855d2011-03-17 01:34:19 -0700619 int pollResult = poll(mFds.editArray(), mFds.size(), timeoutMillis);
Jeff Browncc2e7172010-08-17 16:48:25 -0700620
621 acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
622
Jeff Brownaa3855d2011-03-17 01:34:19 -0700623 if (pollResult == 0) {
Jeff Brownb7198742011-03-18 18:14:26 -0700624 break; // timed out
Jeff Brownaa3855d2011-03-17 01:34:19 -0700625 }
626 if (pollResult < 0) {
Jeff Brownb7198742011-03-18 18:14:26 -0700627 // Sleep after errors to avoid locking up the system.
628 // Hopefully the error is transient.
Jeff Browncc2e7172010-08-17 16:48:25 -0700629 if (errno != EINTR) {
Jeff Browna9b84222010-10-14 02:23:43 -0700630 LOGW("poll failed (errno=%d)\n", errno);
Jeff Browncc2e7172010-08-17 16:48:25 -0700631 usleep(100000);
632 }
Jeff Brownb7198742011-03-18 18:14:26 -0700633 } else {
634 // On an SMP system, it is possible for the framework to read input events
635 // faster than the kernel input device driver can produce a complete packet.
636 // Because poll() wakes up as soon as the first input event becomes available,
637 // the framework will often end up reading one event at a time until the
638 // packet is complete. Instead of one call to read() returning 71 events,
639 // it could take 71 calls to read() each returning 1 event.
640 //
641 // Sleep for a short period of time after waking up from the poll() to give
642 // the kernel time to finish writing the entire packet of input events.
643 if (mNumCpus > 1) {
644 usleep(250);
645 }
Jeff Browncc2e7172010-08-17 16:48:25 -0700646 }
Jeff Brown33bbfd22011-02-24 20:55:35 -0800647
648 // Prepare to process all of the FDs we just polled.
Jeff Brownb7198742011-03-18 18:14:26 -0700649 mInputFdIndex = 1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 }
Jeff Brownb7198742011-03-18 18:14:26 -0700651
652 // All done, return the number of events we read.
653 return event - buffer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654}
655
656/*
657 * Open the platform-specific input device.
658 */
Jeff Brown90655042010-12-02 13:50:46 -0800659bool EventHub::openPlatformInput(void) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660 /*
661 * Open platform-specific input device(s).
662 */
Jeff Brown90655042010-12-02 13:50:46 -0800663 int res, fd;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665#ifdef HAVE_INOTIFY
Jeff Brown90655042010-12-02 13:50:46 -0800666 fd = inotify_init();
667 res = inotify_add_watch(fd, DEVICE_PATH, IN_DELETE | IN_CREATE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 if(res < 0) {
Jeff Brown90655042010-12-02 13:50:46 -0800669 LOGE("could not add watch for %s, %s\n", DEVICE_PATH, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800670 }
671#else
672 /*
673 * The code in EventHub::getEvent assumes that mFDs[0] is an inotify fd.
674 * We allocate space for it and set it to something invalid.
675 */
Jeff Brown90655042010-12-02 13:50:46 -0800676 fd = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677#endif
678
Jeff Brown90655042010-12-02 13:50:46 -0800679 // Reserve fd index 0 for inotify.
680 struct pollfd pollfd;
681 pollfd.fd = fd;
682 pollfd.events = POLLIN;
683 pollfd.revents = 0;
684 mFds.push(pollfd);
685 mDevices.push(NULL);
686
687 res = scanDir(DEVICE_PATH);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 if(res < 0) {
Jeff Brown90655042010-12-02 13:50:46 -0800689 LOGE("scan dir failed for %s\n", DEVICE_PATH);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800690 }
691
692 return true;
693}
694
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695// ----------------------------------------------------------------------------
696
Jeff Brownfd035822010-06-30 16:10:35 -0700697static bool containsNonZeroByte(const uint8_t* array, uint32_t startIndex, uint32_t endIndex) {
698 const uint8_t* end = array + endIndex;
699 array += startIndex;
700 while (array != end) {
701 if (*(array++) != 0) {
702 return true;
703 }
704 }
705 return false;
706}
707
708static const int32_t GAMEPAD_KEYCODES[] = {
709 AKEYCODE_BUTTON_A, AKEYCODE_BUTTON_B, AKEYCODE_BUTTON_C,
710 AKEYCODE_BUTTON_X, AKEYCODE_BUTTON_Y, AKEYCODE_BUTTON_Z,
711 AKEYCODE_BUTTON_L1, AKEYCODE_BUTTON_R1,
712 AKEYCODE_BUTTON_L2, AKEYCODE_BUTTON_R2,
713 AKEYCODE_BUTTON_THUMBL, AKEYCODE_BUTTON_THUMBR,
Jeff Browncb1404e2011-01-15 18:14:15 -0800714 AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE,
715 AKEYCODE_BUTTON_1, AKEYCODE_BUTTON_2, AKEYCODE_BUTTON_3, AKEYCODE_BUTTON_4,
716 AKEYCODE_BUTTON_5, AKEYCODE_BUTTON_6, AKEYCODE_BUTTON_7, AKEYCODE_BUTTON_8,
717 AKEYCODE_BUTTON_9, AKEYCODE_BUTTON_10, AKEYCODE_BUTTON_11, AKEYCODE_BUTTON_12,
718 AKEYCODE_BUTTON_13, AKEYCODE_BUTTON_14, AKEYCODE_BUTTON_15, AKEYCODE_BUTTON_16,
Jeff Brownfd035822010-06-30 16:10:35 -0700719};
720
Jeff Brown90655042010-12-02 13:50:46 -0800721int EventHub::openDevice(const char *devicePath) {
722 char buffer[80];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723
Jeff Brown90655042010-12-02 13:50:46 -0800724 LOGV("Opening device: %s", devicePath);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800725
726 AutoMutex _l(mLock);
Nick Pellye6b1bbd2010-01-20 19:36:49 -0800727
Jeff Brown90655042010-12-02 13:50:46 -0800728 int fd = open(devicePath, O_RDWR);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800729 if(fd < 0) {
Jeff Brown90655042010-12-02 13:50:46 -0800730 LOGE("could not open %s, %s\n", devicePath, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800731 return -1;
732 }
733
Jeff Brown90655042010-12-02 13:50:46 -0800734 InputDeviceIdentifier identifier;
735
736 // Get device name.
737 if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {
738 //fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno));
739 } else {
740 buffer[sizeof(buffer) - 1] = '\0';
741 identifier.name.setTo(buffer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800742 }
Mike Lockwood15431a92009-07-17 00:10:10 -0400743
Jeff Brown90655042010-12-02 13:50:46 -0800744 // Check to see if the device is on our excluded list
Mike Lockwood15431a92009-07-17 00:10:10 -0400745 List<String8>::iterator iter = mExcludedDevices.begin();
746 List<String8>::iterator end = mExcludedDevices.end();
747 for ( ; iter != end; iter++) {
748 const char* test = *iter;
Jeff Brown90655042010-12-02 13:50:46 -0800749 if (identifier.name == test) {
750 LOGI("ignoring event id %s driver %s\n", devicePath, test);
Mike Lockwood15431a92009-07-17 00:10:10 -0400751 close(fd);
Mike Lockwood15431a92009-07-17 00:10:10 -0400752 return -1;
753 }
754 }
755
Jeff Brown90655042010-12-02 13:50:46 -0800756 // Get device driver version.
757 int driverVersion;
758 if(ioctl(fd, EVIOCGVERSION, &driverVersion)) {
759 LOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno));
760 close(fd);
761 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800762 }
763
Jeff Brown90655042010-12-02 13:50:46 -0800764 // Get device identifier.
765 struct input_id inputId;
766 if(ioctl(fd, EVIOCGID, &inputId)) {
767 LOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno));
768 close(fd);
769 return -1;
770 }
771 identifier.bus = inputId.bustype;
772 identifier.product = inputId.product;
773 identifier.vendor = inputId.vendor;
774 identifier.version = inputId.version;
775
776 // Get device physical location.
777 if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) {
778 //fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno));
779 } else {
780 buffer[sizeof(buffer) - 1] = '\0';
781 identifier.location.setTo(buffer);
782 }
783
784 // Get device unique id.
785 if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) {
786 //fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno));
787 } else {
788 buffer[sizeof(buffer) - 1] = '\0';
789 identifier.uniqueId.setTo(buffer);
790 }
791
792 // Make file descriptor non-blocking for use with poll().
Jeff Browncc2e7172010-08-17 16:48:25 -0700793 if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
794 LOGE("Error %d making device file descriptor non-blocking.", errno);
795 close(fd);
796 return -1;
797 }
798
Jeff Brown90655042010-12-02 13:50:46 -0800799 // Allocate device. (The device object takes ownership of the fd at this point.)
800 int32_t deviceId = mNextDeviceId++;
801 Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802
803#if 0
Jeff Brown90655042010-12-02 13:50:46 -0800804 LOGI("add device %d: %s\n", deviceId, devicePath);
805 LOGI(" bus: %04x\n"
806 " vendor %04x\n"
807 " product %04x\n"
808 " version %04x\n",
809 identifier.bus, identifier.vendor, identifier.product, identifier.version);
810 LOGI(" name: \"%s\"\n", identifier.name.string());
811 LOGI(" location: \"%s\"\n", identifier.location.string());
812 LOGI(" unique id: \"%s\"\n", identifier.uniqueId.string());
813 LOGI(" driver: v%d.%d.%d\n",
814 driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815#endif
816
Jeff Brown47e6b1b2010-11-29 17:37:49 -0800817 // Load the configuration file for the device.
818 loadConfiguration(device);
819
Jeff Brownfd035822010-06-30 16:10:35 -0700820 // Figure out the kinds of events the device reports.
Jeff Brownfd035822010-06-30 16:10:35 -0700821 uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822 memset(key_bitmask, 0, sizeof(key_bitmask));
Jeff Brown6f2fba42011-02-19 01:08:02 -0800823 ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask);
Jeff Brownfd035822010-06-30 16:10:35 -0700824
Jeff Brown6f2fba42011-02-19 01:08:02 -0800825 uint8_t abs_bitmask[sizeof_bit_array(ABS_MAX + 1)];
826 memset(abs_bitmask, 0, sizeof(abs_bitmask));
827 ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask);
Jeff Brownfd035822010-06-30 16:10:35 -0700828
Jeff Brown6f2fba42011-02-19 01:08:02 -0800829 uint8_t rel_bitmask[sizeof_bit_array(REL_MAX + 1)];
830 memset(rel_bitmask, 0, sizeof(rel_bitmask));
831 ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask);
Jeff Brownfd035822010-06-30 16:10:35 -0700832
Jeff Brown6f2fba42011-02-19 01:08:02 -0800833 uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)];
834 memset(sw_bitmask, 0, sizeof(sw_bitmask));
835 ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask);
836
Jeff Browncc0c1592011-02-19 05:07:28 -0800837 device->keyBitmask = new uint8_t[sizeof(key_bitmask)];
838 if (device->keyBitmask != NULL) {
839 memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
840 } else {
841 delete device;
842 LOGE("out of memory allocating key bitmask");
843 return -1;
844 }
845
846 device->relBitmask = new uint8_t[sizeof(rel_bitmask)];
847 if (device->relBitmask != NULL) {
848 memcpy(device->relBitmask, rel_bitmask, sizeof(rel_bitmask));
849 } else {
850 delete device;
851 LOGE("out of memory allocating rel bitmask");
852 return -1;
853 }
854
Jeff Brown6f2fba42011-02-19 01:08:02 -0800855 // See if this is a keyboard. Ignore everything in the button range except for
856 // joystick and gamepad buttons which are handled like keyboards for the most part.
857 bool haveKeyboardKeys = containsNonZeroByte(key_bitmask, 0, sizeof_bit_array(BTN_MISC))
858 || containsNonZeroByte(key_bitmask, sizeof_bit_array(KEY_OK),
859 sizeof_bit_array(KEY_MAX + 1));
Jeff Brown9e8e40c2011-03-03 03:39:29 -0800860 bool haveGamepadButtons = containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_MISC),
861 sizeof_bit_array(BTN_MOUSE))
862 || containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_JOYSTICK),
863 sizeof_bit_array(BTN_DIGI));
Jeff Brown6f2fba42011-02-19 01:08:02 -0800864 if (haveKeyboardKeys || haveGamepadButtons) {
865 device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800866 }
Jeff Brown6f2fba42011-02-19 01:08:02 -0800867
Jeff Brown83c09682010-12-23 17:50:18 -0800868 // See if this is a cursor device such as a trackball or mouse.
Jeff Brown6f2fba42011-02-19 01:08:02 -0800869 if (test_bit(BTN_MOUSE, key_bitmask)
870 && test_bit(REL_X, rel_bitmask)
871 && test_bit(REL_Y, rel_bitmask)) {
872 device->classes |= INPUT_DEVICE_CLASS_CURSOR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 }
Jeff Brownfd035822010-06-30 16:10:35 -0700874
875 // See if this is a touch pad.
Jeff Brown6f2fba42011-02-19 01:08:02 -0800876 // Is this a new modern multi-touch driver?
877 if (test_bit(ABS_MT_POSITION_X, abs_bitmask)
878 && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) {
879 // Some joysticks such as the PS3 controller report axes that conflict
880 // with the ABS_MT range. Try to confirm that the device really is
881 // a touch screen.
882 if (test_bit(BTN_TOUCH, key_bitmask) || !haveGamepadButtons) {
Jeff Brown58a2da82011-01-25 16:02:22 -0800883 device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT;
Jeff Brownfd035822010-06-30 16:10:35 -0700884 }
Jeff Brown6f2fba42011-02-19 01:08:02 -0800885 // Is this an old style single-touch driver?
886 } else if (test_bit(BTN_TOUCH, key_bitmask)
887 && test_bit(ABS_X, abs_bitmask)
888 && test_bit(ABS_Y, abs_bitmask)) {
889 device->classes |= INPUT_DEVICE_CLASS_TOUCH;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800890 }
891
Jeff Brown9e8e40c2011-03-03 03:39:29 -0800892 // See if this device is a joystick.
893 // Ignore touchscreens because they use the same absolute axes for other purposes.
894 // Assumes that joysticks always have gamepad buttons in order to distinguish them
895 // from other devices such as accelerometers that also have absolute axes.
896 if (haveGamepadButtons
897 && !(device->classes & INPUT_DEVICE_CLASS_TOUCH)
898 && containsNonZeroByte(abs_bitmask, 0, sizeof_bit_array(ABS_MAX + 1))) {
899 device->classes |= INPUT_DEVICE_CLASS_JOYSTICK;
900 }
901
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800902 // figure out the switches this device reports
Jeff Brown6f2fba42011-02-19 01:08:02 -0800903 bool haveSwitches = false;
904 for (int i=0; i<EV_SW; i++) {
905 //LOGI("Device %d sw %d: has=%d", device->id, i, test_bit(i, sw_bitmask));
906 if (test_bit(i, sw_bitmask)) {
907 haveSwitches = true;
908 if (mSwitches[i] == 0) {
909 mSwitches[i] = device->id;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800910 }
911 }
912 }
Jeff Brown6f2fba42011-02-19 01:08:02 -0800913 if (haveSwitches) {
Jeff Brown6d0fec22010-07-23 21:28:06 -0700914 device->classes |= INPUT_DEVICE_CLASS_SWITCH;
915 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800916
Jeff Brown58a2da82011-01-25 16:02:22 -0800917 if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) {
Jeff Brown90655042010-12-02 13:50:46 -0800918 // Load the virtual keys for the touch screen, if any.
919 // We do this now so that we can make sure to load the keymap if necessary.
920 status_t status = loadVirtualKeyMap(device);
921 if (!status) {
922 device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800923 }
Jeff Brown90655042010-12-02 13:50:46 -0800924 }
925
Jeff Brown9e8e40c2011-03-03 03:39:29 -0800926 // Load the key map.
927 // We need to do this for joysticks too because the key layout may specify axes.
928 status_t keyMapStatus = NAME_NOT_FOUND;
929 if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) {
Jeff Brown90655042010-12-02 13:50:46 -0800930 // Load the keymap for the device.
Jeff Brown9e8e40c2011-03-03 03:39:29 -0800931 keyMapStatus = loadKeyMap(device);
932 }
Jeff Brown90655042010-12-02 13:50:46 -0800933
Jeff Brown9e8e40c2011-03-03 03:39:29 -0800934 // Configure the keyboard, gamepad or virtual keyboard.
935 if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) {
Jeff Brown90655042010-12-02 13:50:46 -0800936 // Set system properties for the keyboard.
Jeff Brown497a92c2010-09-12 17:55:08 -0700937 setKeyboardProperties(device, false);
938
Jeff Brown90655042010-12-02 13:50:46 -0800939 // Register the keyboard as a built-in keyboard if it is eligible.
Jeff Brown9e8e40c2011-03-03 03:39:29 -0800940 if (!keyMapStatus
Jeff Brown90655042010-12-02 13:50:46 -0800941 && mBuiltInKeyboardId == -1
942 && isEligibleBuiltInKeyboard(device->identifier,
943 device->configuration, &device->keyMap)) {
944 mBuiltInKeyboardId = device->id;
945 setKeyboardProperties(device, true);
Jeff Brown497a92c2010-09-12 17:55:08 -0700946 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800947
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700948 // 'Q' key support = cheap test of whether this is an alpha-capable kbd
Jeff Brownf2f48712010-10-01 17:46:21 -0700949 if (hasKeycodeLocked(device, AKEYCODE_Q)) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700950 device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700951 }
Jeff Brown497a92c2010-09-12 17:55:08 -0700952
Jeff Brownfd035822010-06-30 16:10:35 -0700953 // See if this device has a DPAD.
Jeff Brownf2f48712010-10-01 17:46:21 -0700954 if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) &&
955 hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) &&
956 hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) &&
957 hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) &&
958 hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) {
Jeff Brown46b9ac02010-04-22 18:58:52 -0700959 device->classes |= INPUT_DEVICE_CLASS_DPAD;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700960 }
Jeff Brown497a92c2010-09-12 17:55:08 -0700961
Jeff Brownfd035822010-06-30 16:10:35 -0700962 // See if this device has a gamepad.
Kenny Root1d79a9d2010-10-21 15:46:03 -0700963 for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) {
Jeff Brownf2f48712010-10-01 17:46:21 -0700964 if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) {
Jeff Brownfd035822010-06-30 16:10:35 -0700965 device->classes |= INPUT_DEVICE_CLASS_GAMEPAD;
966 break;
967 }
968 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800969 }
970
Sean McNeilaeb00c42010-06-23 16:00:37 +0700971 // If the device isn't recognized as something we handle, don't monitor it.
972 if (device->classes == 0) {
Jeff Brown90655042010-12-02 13:50:46 -0800973 LOGV("Dropping device: id=%d, path='%s', name='%s'",
974 deviceId, devicePath, device->identifier.name.string());
Sean McNeilaeb00c42010-06-23 16:00:37 +0700975 delete device;
976 return -1;
977 }
978
Jeff Brown56194eb2011-03-02 19:23:13 -0800979 // Determine whether the device is external or internal.
980 if (isExternalDevice(device)) {
981 device->classes |= INPUT_DEVICE_CLASS_EXTERNAL;
982 }
983
Jeff Brown90655042010-12-02 13:50:46 -0800984 LOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
985 "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s",
986 deviceId, fd, devicePath, device->identifier.name.string(),
987 device->classes,
988 device->configurationFile.string(),
989 device->keyMap.keyLayoutFile.string(),
990 device->keyMap.keyCharacterMapFile.string(),
991 toString(mBuiltInKeyboardId == deviceId));
Jeff Brown47e6b1b2010-11-29 17:37:49 -0800992
Jeff Brown90655042010-12-02 13:50:46 -0800993 struct pollfd pollfd;
994 pollfd.fd = fd;
995 pollfd.events = POLLIN;
996 pollfd.revents = 0;
997 mFds.push(pollfd);
998 mDevices.push(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800999
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001000 device->next = mOpeningDevices;
1001 mOpeningDevices = device;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001002 return 0;
1003}
1004
Jeff Brown90655042010-12-02 13:50:46 -08001005void EventHub::loadConfiguration(Device* device) {
1006 device->configurationFile = getInputDeviceConfigurationFilePathByDeviceIdentifier(
1007 device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION);
Jeff Brown47e6b1b2010-11-29 17:37:49 -08001008 if (device->configurationFile.isEmpty()) {
Jeff Brown90655042010-12-02 13:50:46 -08001009 LOGD("No input device configuration file found for device '%s'.",
1010 device->identifier.name.string());
Jeff Brown47e6b1b2010-11-29 17:37:49 -08001011 } else {
1012 status_t status = PropertyMap::load(device->configurationFile,
1013 &device->configuration);
1014 if (status) {
Jeff Brown90655042010-12-02 13:50:46 -08001015 LOGE("Error loading input device configuration file for device '%s'. "
1016 "Using default configuration.",
1017 device->identifier.name.string());
Jeff Brown47e6b1b2010-11-29 17:37:49 -08001018 }
1019 }
1020}
1021
Jeff Brown90655042010-12-02 13:50:46 -08001022status_t EventHub::loadVirtualKeyMap(Device* device) {
1023 // The virtual key map is supplied by the kernel as a system board property file.
1024 String8 path;
1025 path.append("/sys/board_properties/virtualkeys.");
1026 path.append(device->identifier.name);
1027 if (access(path.string(), R_OK)) {
1028 return NAME_NOT_FOUND;
1029 }
1030 return VirtualKeyMap::load(path, &device->virtualKeyMap);
Jeff Brown497a92c2010-09-12 17:55:08 -07001031}
1032
Jeff Brown90655042010-12-02 13:50:46 -08001033status_t EventHub::loadKeyMap(Device* device) {
1034 return device->keyMap.load(device->identifier, device->configuration);
Jeff Brown497a92c2010-09-12 17:55:08 -07001035}
1036
Jeff Brown90655042010-12-02 13:50:46 -08001037void EventHub::setKeyboardProperties(Device* device, bool builtInKeyboard) {
1038 int32_t id = builtInKeyboard ? 0 : device->id;
1039 android::setKeyboardProperties(id, device->identifier,
1040 device->keyMap.keyLayoutFile, device->keyMap.keyCharacterMapFile);
1041}
1042
1043void EventHub::clearKeyboardProperties(Device* device, bool builtInKeyboard) {
1044 int32_t id = builtInKeyboard ? 0 : device->id;
Jeff Brown6b53e8d2010-11-10 16:03:06 -08001045 android::clearKeyboardProperties(id);
Jeff Brown497a92c2010-09-12 17:55:08 -07001046}
1047
Jeff Brown56194eb2011-03-02 19:23:13 -08001048bool EventHub::isExternalDevice(Device* device) {
1049 if (device->configuration) {
1050 bool value;
1051 if (device->configuration->tryGetProperty(String8("device.internal"), value)
1052 && value) {
1053 return false;
1054 }
1055 }
1056 return device->identifier.bus == BUS_USB || device->identifier.bus == BUS_BLUETOOTH;
1057}
1058
Jeff Brown90655042010-12-02 13:50:46 -08001059bool EventHub::hasKeycodeLocked(Device* device, int keycode) const {
1060 if (!device->keyMap.haveKeyLayout() || !device->keyBitmask) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -07001061 return false;
1062 }
1063
1064 Vector<int32_t> scanCodes;
Jeff Brown6f2fba42011-02-19 01:08:02 -08001065 device->keyMap.keyLayoutMap->findScanCodesForKey(keycode, &scanCodes);
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -07001066 const size_t N = scanCodes.size();
1067 for (size_t i=0; i<N && i<=KEY_MAX; i++) {
1068 int32_t sc = scanCodes.itemAt(i);
1069 if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, device->keyBitmask)) {
1070 return true;
1071 }
1072 }
1073
1074 return false;
1075}
1076
Jeff Brown90655042010-12-02 13:50:46 -08001077int EventHub::closeDevice(const char *devicePath) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001078 AutoMutex _l(mLock);
Jeff Brown7342bb92010-10-01 18:55:43 -07001079
Jeff Brown90655042010-12-02 13:50:46 -08001080 for (size_t i = FIRST_ACTUAL_DEVICE_INDEX; i < mDevices.size(); i++) {
1081 Device* device = mDevices[i];
1082 if (device->path == devicePath) {
Jeff Brown33bbfd22011-02-24 20:55:35 -08001083 return closeDeviceAtIndexLocked(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001084 }
1085 }
Jeff Brown33bbfd22011-02-24 20:55:35 -08001086 LOGV("Remove device: %s not found, device may already have been removed.", devicePath);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087 return -1;
1088}
1089
Jeff Brown33bbfd22011-02-24 20:55:35 -08001090int EventHub::closeDeviceAtIndexLocked(int index) {
1091 Device* device = mDevices[index];
1092 LOGI("Removed device: path=%s name=%s id=%d fd=%d classes=0x%x\n",
1093 device->path.string(), device->identifier.name.string(), device->id,
1094 device->fd, device->classes);
1095
1096 for (int j=0; j<EV_SW; j++) {
1097 if (mSwitches[j] == device->id) {
1098 mSwitches[j] = 0;
1099 }
1100 }
1101
1102 if (device->id == mBuiltInKeyboardId) {
1103 LOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
1104 device->path.string(), mBuiltInKeyboardId);
1105 mBuiltInKeyboardId = -1;
1106 clearKeyboardProperties(device, true);
1107 }
1108 clearKeyboardProperties(device, false);
1109
1110 mFds.removeAt(index);
1111 mDevices.removeAt(index);
1112 device->close();
1113
Jeff Brown8e9d4432011-03-12 19:46:59 -08001114 // Unlink for opening devices list if it is present.
1115 Device* pred = NULL;
1116 bool found = false;
1117 for (Device* entry = mOpeningDevices; entry != NULL; ) {
1118 if (entry == device) {
1119 found = true;
1120 break;
1121 }
1122 pred = entry;
1123 entry = entry->next;
1124 }
1125 if (found) {
1126 // Unlink the device from the opening devices list then delete it.
1127 // We don't need to tell the client that the device was closed because
1128 // it does not even know it was opened in the first place.
1129 LOGI("Device %s was immediately closed after opening.", device->path.string());
1130 if (pred) {
1131 pred->next = device->next;
1132 } else {
1133 mOpeningDevices = device->next;
1134 }
1135 delete device;
1136 } else {
1137 // Link into closing devices list.
1138 // The device will be deleted later after we have informed the client.
1139 device->next = mClosingDevices;
1140 mClosingDevices = device;
1141 }
Jeff Brown33bbfd22011-02-24 20:55:35 -08001142 return 0;
1143}
1144
Jeff Brown7342bb92010-10-01 18:55:43 -07001145int EventHub::readNotify(int nfd) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001146#ifdef HAVE_INOTIFY
1147 int res;
1148 char devname[PATH_MAX];
1149 char *filename;
1150 char event_buf[512];
1151 int event_size;
1152 int event_pos = 0;
1153 struct inotify_event *event;
1154
Jeff Brown7342bb92010-10-01 18:55:43 -07001155 LOGV("EventHub::readNotify nfd: %d\n", nfd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001156 res = read(nfd, event_buf, sizeof(event_buf));
1157 if(res < (int)sizeof(*event)) {
1158 if(errno == EINTR)
1159 return 0;
1160 LOGW("could not get event, %s\n", strerror(errno));
1161 return 1;
1162 }
1163 //printf("got %d bytes of event information\n", res);
1164
Jeff Brown90655042010-12-02 13:50:46 -08001165 strcpy(devname, DEVICE_PATH);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001166 filename = devname + strlen(devname);
1167 *filename++ = '/';
1168
1169 while(res >= (int)sizeof(*event)) {
1170 event = (struct inotify_event *)(event_buf + event_pos);
1171 //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
1172 if(event->len) {
1173 strcpy(filename, event->name);
1174 if(event->mask & IN_CREATE) {
Jeff Brown7342bb92010-10-01 18:55:43 -07001175 openDevice(devname);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 }
1177 else {
Jeff Brown7342bb92010-10-01 18:55:43 -07001178 closeDevice(devname);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001179 }
1180 }
1181 event_size = sizeof(*event) + event->len;
1182 res -= event_size;
1183 event_pos += event_size;
1184 }
1185#endif
1186 return 0;
1187}
1188
Jeff Brown7342bb92010-10-01 18:55:43 -07001189int EventHub::scanDir(const char *dirname)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001190{
1191 char devname[PATH_MAX];
1192 char *filename;
1193 DIR *dir;
1194 struct dirent *de;
1195 dir = opendir(dirname);
1196 if(dir == NULL)
1197 return -1;
1198 strcpy(devname, dirname);
1199 filename = devname + strlen(devname);
1200 *filename++ = '/';
1201 while((de = readdir(dir))) {
1202 if(de->d_name[0] == '.' &&
1203 (de->d_name[1] == '\0' ||
1204 (de->d_name[1] == '.' && de->d_name[2] == '\0')))
1205 continue;
1206 strcpy(filename, de->d_name);
Jeff Brown7342bb92010-10-01 18:55:43 -07001207 openDevice(devname);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001208 }
1209 closedir(dir);
1210 return 0;
1211}
1212
Jeff Brownf2f48712010-10-01 17:46:21 -07001213void EventHub::dump(String8& dump) {
1214 dump.append("Event Hub State:\n");
1215
1216 { // acquire lock
1217 AutoMutex _l(mLock);
1218
Jeff Brown90655042010-12-02 13:50:46 -08001219 dump.appendFormat(INDENT "BuiltInKeyboardId: %d\n", mBuiltInKeyboardId);
Jeff Brownf2f48712010-10-01 17:46:21 -07001220
1221 dump.append(INDENT "Devices:\n");
1222
Jeff Brown90655042010-12-02 13:50:46 -08001223 for (size_t i = FIRST_ACTUAL_DEVICE_INDEX; i < mDevices.size(); i++) {
1224 const Device* device = mDevices[i];
Jeff Brownf2f48712010-10-01 17:46:21 -07001225 if (device) {
Jeff Brown90655042010-12-02 13:50:46 -08001226 if (mBuiltInKeyboardId == device->id) {
1227 dump.appendFormat(INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n",
1228 device->id, device->identifier.name.string());
Jeff Brownf2f48712010-10-01 17:46:21 -07001229 } else {
Jeff Brown90655042010-12-02 13:50:46 -08001230 dump.appendFormat(INDENT2 "%d: %s\n", device->id,
1231 device->identifier.name.string());
Jeff Brownf2f48712010-10-01 17:46:21 -07001232 }
1233 dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes);
1234 dump.appendFormat(INDENT3 "Path: %s\n", device->path.string());
Jeff Brown90655042010-12-02 13:50:46 -08001235 dump.appendFormat(INDENT3 "Location: %s\n", device->identifier.location.string());
1236 dump.appendFormat(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string());
1237 dump.appendFormat(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, "
1238 "product=0x%04x, version=0x%04x\n",
1239 device->identifier.bus, device->identifier.vendor,
1240 device->identifier.product, device->identifier.version);
Jeff Brown6b53e8d2010-11-10 16:03:06 -08001241 dump.appendFormat(INDENT3 "KeyLayoutFile: %s\n",
Jeff Brown90655042010-12-02 13:50:46 -08001242 device->keyMap.keyLayoutFile.string());
Jeff Brown6b53e8d2010-11-10 16:03:06 -08001243 dump.appendFormat(INDENT3 "KeyCharacterMapFile: %s\n",
Jeff Brown90655042010-12-02 13:50:46 -08001244 device->keyMap.keyCharacterMapFile.string());
Jeff Brown47e6b1b2010-11-29 17:37:49 -08001245 dump.appendFormat(INDENT3 "ConfigurationFile: %s\n",
1246 device->configurationFile.string());
Jeff Brownf2f48712010-10-01 17:46:21 -07001247 }
1248 }
1249 } // release lock
1250}
1251
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001252}; // namespace android