blob: 7625adb1410807b5369efdcb80ec6e0f0e93eba3 [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 Brownfd0358292010-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 Brownf2f487182010-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 Brownf2f487182010-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 Browndbf8d272011-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 Browndbf8d272011-03-18 18:14:26 -0700132
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 memset(mSwitches, 0, sizeof(mSwitches));
Jeff Browndbf8d272011-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 Brown46b9ac0a2010-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 Brownfd0358292010-06-30 16:10:35 -0700221 uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
Jeff Brown46b9ac0a2010-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 Brown46b9ac0a2010-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 Brown46b9ac0a2010-04-22 18:58:52 -0700226 }
Jeff Brownc5ed5912010-07-14 18:48:53 -0700227 return AKEY_STATE_UNKNOWN;
Jeff Brown46b9ac0a2010-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 Brown46b9ac0a2010-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 Brown46b9ac0a2010-04-22 18:58:52 -0700247
Jeff Brownfd0358292010-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 Brown46b9ac0a2010-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 Brown46b9ac0a2010-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 Brown46b9ac0a2010-04-22 18:58:52 -0700276 }
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700277 }
Jeff Brownc5ed5912010-07-14 18:48:53 -0700278 return AKEY_STATE_UNKNOWN;
Jeff Brown46b9ac0a2010-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 Brownfd0358292010-06-30 16:10:35 -0700282 uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)];
Jeff Brown46b9ac0a2010-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 Brown46b9ac0a2010-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 Brown46b9ac0a2010-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 Brownf2f487182010-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 Browndbf8d272011-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 Browndbf8d272011-03-18 18:14:26 -0700453 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 Browndbf8d272011-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 Browndbf8d272011-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 Browndbf8d272011-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 Browndbf8d272011-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 Browndbf8d272011-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 Browndbf8d272011-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 Browndbf8d272011-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 Browndbf8d272011-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 Browndbf8d272011-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 Browndbf8d272011-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 Browndbf8d272011-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 Browndbf8d272011-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 Browndbf8d272011-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 Browndbf8d272011-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
542 event->when = now;
543 event->deviceId = deviceId;
544 event->type = iev.type;
545 event->scanCode = iev.code;
546 event->value = iev.value;
547 event->keyCode = AKEYCODE_UNKNOWN;
548 event->flags = 0;
549 if (iev.type == EV_KEY && device->keyMap.haveKeyLayout()) {
550 status_t err = device->keyMap.keyLayoutMap->mapKey(iev.code,
551 &event->keyCode, &event->flags);
552 LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
553 iev.code, event->keyCode, event->flags, err);
554 }
555 event += 1;
556 }
557 capacity -= count;
558 if (capacity == 0) {
559 break;
560 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561 }
562 }
Jeff Browndbf8d272011-03-18 18:14:26 -0700563 mInputFdIndex += 1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800564 }
Jeff Browncc2e7172010-08-17 16:48:25 -0700565
Jeff Brown33bbfd22011-02-24 20:55:35 -0800566 // Handle the case where a device has been removed but INotify has not yet noticed.
567 if (deviceWasRemoved) {
568 AutoMutex _l(mLock);
569 closeDeviceAtIndexLocked(mInputFdIndex);
570 continue; // report added or removed devices immediately
571 }
572
Jeff Browna9b84222010-10-14 02:23:43 -0700573#if HAVE_INOTIFY
Jeff Brown7342bb92010-10-01 18:55:43 -0700574 // readNotify() will modify mFDs and mFDCount, so this must be done after
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575 // processing all other events.
Jeff Brown90655042010-12-02 13:50:46 -0800576 if(mFds[0].revents & POLLIN) {
577 readNotify(mFds[0].fd);
578 mFds.editItemAt(0).revents = 0;
Jeff Browndbf8d272011-03-18 18:14:26 -0700579 mInputFdIndex = mFds.size();
Jeff Browna9b84222010-10-14 02:23:43 -0700580 continue; // report added or removed devices immediately
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 }
Jeff Browna9b84222010-10-14 02:23:43 -0700582#endif
583
Jeff Browndbf8d272011-03-18 18:14:26 -0700584 // Return now if we have collected any events, otherwise poll.
585 if (event != buffer) {
586 break;
587 }
588
Jeff Browncc2e7172010-08-17 16:48:25 -0700589 // Poll for events. Mind the wake lock dance!
590 // We hold a wake lock at all times except during poll(). This works due to some
591 // subtle choreography. When a device driver has pending (unread) events, it acquires
592 // a kernel wake lock. However, once the last pending event has been read, the device
593 // driver will release the kernel wake lock. To prevent the system from going to sleep
594 // when this happens, the EventHub holds onto its own user wake lock while the client
595 // is processing events. Thus the system can only sleep if there are no events
596 // pending or currently being processed.
Jeff Brown68d60752011-03-17 01:34:19 -0700597 //
598 // The timeout is advisory only. If the device is asleep, it will not wake just to
599 // service the timeout.
Jeff Browncc2e7172010-08-17 16:48:25 -0700600 release_wake_lock(WAKE_LOCK_ID);
601
Jeff Brown68d60752011-03-17 01:34:19 -0700602 int pollResult = poll(mFds.editArray(), mFds.size(), timeoutMillis);
Jeff Browncc2e7172010-08-17 16:48:25 -0700603
604 acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
605
Jeff Brown68d60752011-03-17 01:34:19 -0700606 if (pollResult == 0) {
Jeff Browndbf8d272011-03-18 18:14:26 -0700607 break; // timed out
Jeff Brown68d60752011-03-17 01:34:19 -0700608 }
609 if (pollResult < 0) {
Jeff Browndbf8d272011-03-18 18:14:26 -0700610 // Sleep after errors to avoid locking up the system.
611 // Hopefully the error is transient.
Jeff Browncc2e7172010-08-17 16:48:25 -0700612 if (errno != EINTR) {
Jeff Browna9b84222010-10-14 02:23:43 -0700613 LOGW("poll failed (errno=%d)\n", errno);
Jeff Browncc2e7172010-08-17 16:48:25 -0700614 usleep(100000);
615 }
Jeff Browndbf8d272011-03-18 18:14:26 -0700616 } else {
617 // On an SMP system, it is possible for the framework to read input events
618 // faster than the kernel input device driver can produce a complete packet.
619 // Because poll() wakes up as soon as the first input event becomes available,
620 // the framework will often end up reading one event at a time until the
621 // packet is complete. Instead of one call to read() returning 71 events,
622 // it could take 71 calls to read() each returning 1 event.
623 //
624 // Sleep for a short period of time after waking up from the poll() to give
625 // the kernel time to finish writing the entire packet of input events.
626 if (mNumCpus > 1) {
627 usleep(250);
628 }
Jeff Browncc2e7172010-08-17 16:48:25 -0700629 }
Jeff Brown33bbfd22011-02-24 20:55:35 -0800630
631 // Prepare to process all of the FDs we just polled.
Jeff Browndbf8d272011-03-18 18:14:26 -0700632 mInputFdIndex = 1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 }
Jeff Browndbf8d272011-03-18 18:14:26 -0700634
635 // All done, return the number of events we read.
636 return event - buffer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637}
638
639/*
640 * Open the platform-specific input device.
641 */
Jeff Brown90655042010-12-02 13:50:46 -0800642bool EventHub::openPlatformInput(void) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800643 /*
644 * Open platform-specific input device(s).
645 */
Jeff Brown90655042010-12-02 13:50:46 -0800646 int res, fd;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648#ifdef HAVE_INOTIFY
Jeff Brown90655042010-12-02 13:50:46 -0800649 fd = inotify_init();
650 res = inotify_add_watch(fd, DEVICE_PATH, IN_DELETE | IN_CREATE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800651 if(res < 0) {
Jeff Brown90655042010-12-02 13:50:46 -0800652 LOGE("could not add watch for %s, %s\n", DEVICE_PATH, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 }
654#else
655 /*
656 * The code in EventHub::getEvent assumes that mFDs[0] is an inotify fd.
657 * We allocate space for it and set it to something invalid.
658 */
Jeff Brown90655042010-12-02 13:50:46 -0800659 fd = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660#endif
661
Jeff Brown90655042010-12-02 13:50:46 -0800662 // Reserve fd index 0 for inotify.
663 struct pollfd pollfd;
664 pollfd.fd = fd;
665 pollfd.events = POLLIN;
666 pollfd.revents = 0;
667 mFds.push(pollfd);
668 mDevices.push(NULL);
669
670 res = scanDir(DEVICE_PATH);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 if(res < 0) {
Jeff Brown90655042010-12-02 13:50:46 -0800672 LOGE("scan dir failed for %s\n", DEVICE_PATH);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800673 }
674
675 return true;
676}
677
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678// ----------------------------------------------------------------------------
679
Jeff Brownfd0358292010-06-30 16:10:35 -0700680static bool containsNonZeroByte(const uint8_t* array, uint32_t startIndex, uint32_t endIndex) {
681 const uint8_t* end = array + endIndex;
682 array += startIndex;
683 while (array != end) {
684 if (*(array++) != 0) {
685 return true;
686 }
687 }
688 return false;
689}
690
691static const int32_t GAMEPAD_KEYCODES[] = {
692 AKEYCODE_BUTTON_A, AKEYCODE_BUTTON_B, AKEYCODE_BUTTON_C,
693 AKEYCODE_BUTTON_X, AKEYCODE_BUTTON_Y, AKEYCODE_BUTTON_Z,
694 AKEYCODE_BUTTON_L1, AKEYCODE_BUTTON_R1,
695 AKEYCODE_BUTTON_L2, AKEYCODE_BUTTON_R2,
696 AKEYCODE_BUTTON_THUMBL, AKEYCODE_BUTTON_THUMBR,
Jeff Browncb1404e2011-01-15 18:14:15 -0800697 AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE,
698 AKEYCODE_BUTTON_1, AKEYCODE_BUTTON_2, AKEYCODE_BUTTON_3, AKEYCODE_BUTTON_4,
699 AKEYCODE_BUTTON_5, AKEYCODE_BUTTON_6, AKEYCODE_BUTTON_7, AKEYCODE_BUTTON_8,
700 AKEYCODE_BUTTON_9, AKEYCODE_BUTTON_10, AKEYCODE_BUTTON_11, AKEYCODE_BUTTON_12,
701 AKEYCODE_BUTTON_13, AKEYCODE_BUTTON_14, AKEYCODE_BUTTON_15, AKEYCODE_BUTTON_16,
Jeff Brownfd0358292010-06-30 16:10:35 -0700702};
703
Jeff Brown90655042010-12-02 13:50:46 -0800704int EventHub::openDevice(const char *devicePath) {
705 char buffer[80];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800706
Jeff Brown90655042010-12-02 13:50:46 -0800707 LOGV("Opening device: %s", devicePath);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800708
709 AutoMutex _l(mLock);
Nick Pellye6b1bbd2010-01-20 19:36:49 -0800710
Jeff Brown90655042010-12-02 13:50:46 -0800711 int fd = open(devicePath, O_RDWR);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800712 if(fd < 0) {
Jeff Brown90655042010-12-02 13:50:46 -0800713 LOGE("could not open %s, %s\n", devicePath, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800714 return -1;
715 }
716
Jeff Brown90655042010-12-02 13:50:46 -0800717 InputDeviceIdentifier identifier;
718
719 // Get device name.
720 if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {
721 //fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno));
722 } else {
723 buffer[sizeof(buffer) - 1] = '\0';
724 identifier.name.setTo(buffer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800725 }
Mike Lockwood15431a92009-07-17 00:10:10 -0400726
Jeff Brown90655042010-12-02 13:50:46 -0800727 // Check to see if the device is on our excluded list
Mike Lockwood15431a92009-07-17 00:10:10 -0400728 List<String8>::iterator iter = mExcludedDevices.begin();
729 List<String8>::iterator end = mExcludedDevices.end();
730 for ( ; iter != end; iter++) {
731 const char* test = *iter;
Jeff Brown90655042010-12-02 13:50:46 -0800732 if (identifier.name == test) {
733 LOGI("ignoring event id %s driver %s\n", devicePath, test);
Mike Lockwood15431a92009-07-17 00:10:10 -0400734 close(fd);
Mike Lockwood15431a92009-07-17 00:10:10 -0400735 return -1;
736 }
737 }
738
Jeff Brown90655042010-12-02 13:50:46 -0800739 // Get device driver version.
740 int driverVersion;
741 if(ioctl(fd, EVIOCGVERSION, &driverVersion)) {
742 LOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno));
743 close(fd);
744 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745 }
746
Jeff Brown90655042010-12-02 13:50:46 -0800747 // Get device identifier.
748 struct input_id inputId;
749 if(ioctl(fd, EVIOCGID, &inputId)) {
750 LOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno));
751 close(fd);
752 return -1;
753 }
754 identifier.bus = inputId.bustype;
755 identifier.product = inputId.product;
756 identifier.vendor = inputId.vendor;
757 identifier.version = inputId.version;
758
759 // Get device physical location.
760 if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) {
761 //fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno));
762 } else {
763 buffer[sizeof(buffer) - 1] = '\0';
764 identifier.location.setTo(buffer);
765 }
766
767 // Get device unique id.
768 if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) {
769 //fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno));
770 } else {
771 buffer[sizeof(buffer) - 1] = '\0';
772 identifier.uniqueId.setTo(buffer);
773 }
774
775 // Make file descriptor non-blocking for use with poll().
Jeff Browncc2e7172010-08-17 16:48:25 -0700776 if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
777 LOGE("Error %d making device file descriptor non-blocking.", errno);
778 close(fd);
779 return -1;
780 }
781
Jeff Brown90655042010-12-02 13:50:46 -0800782 // Allocate device. (The device object takes ownership of the fd at this point.)
783 int32_t deviceId = mNextDeviceId++;
784 Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785
786#if 0
Jeff Brown90655042010-12-02 13:50:46 -0800787 LOGI("add device %d: %s\n", deviceId, devicePath);
788 LOGI(" bus: %04x\n"
789 " vendor %04x\n"
790 " product %04x\n"
791 " version %04x\n",
792 identifier.bus, identifier.vendor, identifier.product, identifier.version);
793 LOGI(" name: \"%s\"\n", identifier.name.string());
794 LOGI(" location: \"%s\"\n", identifier.location.string());
795 LOGI(" unique id: \"%s\"\n", identifier.uniqueId.string());
796 LOGI(" driver: v%d.%d.%d\n",
797 driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800798#endif
799
Jeff Brown47e6b1b2010-11-29 17:37:49 -0800800 // Load the configuration file for the device.
801 loadConfiguration(device);
802
Jeff Brownfd0358292010-06-30 16:10:35 -0700803 // Figure out the kinds of events the device reports.
Jeff Brownfd0358292010-06-30 16:10:35 -0700804 uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 memset(key_bitmask, 0, sizeof(key_bitmask));
Jeff Brown6f2fba42011-02-19 01:08:02 -0800806 ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask);
Jeff Brownfd0358292010-06-30 16:10:35 -0700807
Jeff Brown6f2fba42011-02-19 01:08:02 -0800808 uint8_t abs_bitmask[sizeof_bit_array(ABS_MAX + 1)];
809 memset(abs_bitmask, 0, sizeof(abs_bitmask));
810 ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask);
Jeff Brownfd0358292010-06-30 16:10:35 -0700811
Jeff Brown6f2fba42011-02-19 01:08:02 -0800812 uint8_t rel_bitmask[sizeof_bit_array(REL_MAX + 1)];
813 memset(rel_bitmask, 0, sizeof(rel_bitmask));
814 ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask);
Jeff Brownfd0358292010-06-30 16:10:35 -0700815
Jeff Brown6f2fba42011-02-19 01:08:02 -0800816 uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)];
817 memset(sw_bitmask, 0, sizeof(sw_bitmask));
818 ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask);
819
Jeff Browncc0c1592011-02-19 05:07:28 -0800820 device->keyBitmask = new uint8_t[sizeof(key_bitmask)];
821 if (device->keyBitmask != NULL) {
822 memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
823 } else {
824 delete device;
825 LOGE("out of memory allocating key bitmask");
826 return -1;
827 }
828
829 device->relBitmask = new uint8_t[sizeof(rel_bitmask)];
830 if (device->relBitmask != NULL) {
831 memcpy(device->relBitmask, rel_bitmask, sizeof(rel_bitmask));
832 } else {
833 delete device;
834 LOGE("out of memory allocating rel bitmask");
835 return -1;
836 }
837
Jeff Brown6f2fba42011-02-19 01:08:02 -0800838 // See if this is a keyboard. Ignore everything in the button range except for
839 // joystick and gamepad buttons which are handled like keyboards for the most part.
840 bool haveKeyboardKeys = containsNonZeroByte(key_bitmask, 0, sizeof_bit_array(BTN_MISC))
841 || containsNonZeroByte(key_bitmask, sizeof_bit_array(KEY_OK),
842 sizeof_bit_array(KEY_MAX + 1));
Jeff Brown9e8e40c2011-03-03 03:39:29 -0800843 bool haveGamepadButtons = containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_MISC),
844 sizeof_bit_array(BTN_MOUSE))
845 || containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_JOYSTICK),
846 sizeof_bit_array(BTN_DIGI));
Jeff Brown6f2fba42011-02-19 01:08:02 -0800847 if (haveKeyboardKeys || haveGamepadButtons) {
848 device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800849 }
Jeff Brown6f2fba42011-02-19 01:08:02 -0800850
Jeff Brown83c09682010-12-23 17:50:18 -0800851 // See if this is a cursor device such as a trackball or mouse.
Jeff Brown6f2fba42011-02-19 01:08:02 -0800852 if (test_bit(BTN_MOUSE, key_bitmask)
853 && test_bit(REL_X, rel_bitmask)
854 && test_bit(REL_Y, rel_bitmask)) {
855 device->classes |= INPUT_DEVICE_CLASS_CURSOR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800856 }
Jeff Brownfd0358292010-06-30 16:10:35 -0700857
858 // See if this is a touch pad.
Jeff Brown6f2fba42011-02-19 01:08:02 -0800859 // Is this a new modern multi-touch driver?
860 if (test_bit(ABS_MT_POSITION_X, abs_bitmask)
861 && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) {
862 // Some joysticks such as the PS3 controller report axes that conflict
863 // with the ABS_MT range. Try to confirm that the device really is
864 // a touch screen.
865 if (test_bit(BTN_TOUCH, key_bitmask) || !haveGamepadButtons) {
Jeff Brown58a2da82011-01-25 16:02:22 -0800866 device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT;
Jeff Brownfd0358292010-06-30 16:10:35 -0700867 }
Jeff Brown6f2fba42011-02-19 01:08:02 -0800868 // Is this an old style single-touch driver?
869 } else if (test_bit(BTN_TOUCH, key_bitmask)
870 && test_bit(ABS_X, abs_bitmask)
871 && test_bit(ABS_Y, abs_bitmask)) {
872 device->classes |= INPUT_DEVICE_CLASS_TOUCH;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 }
874
Jeff Brown9e8e40c2011-03-03 03:39:29 -0800875 // See if this device is a joystick.
876 // Ignore touchscreens because they use the same absolute axes for other purposes.
877 // Assumes that joysticks always have gamepad buttons in order to distinguish them
878 // from other devices such as accelerometers that also have absolute axes.
879 if (haveGamepadButtons
880 && !(device->classes & INPUT_DEVICE_CLASS_TOUCH)
881 && containsNonZeroByte(abs_bitmask, 0, sizeof_bit_array(ABS_MAX + 1))) {
882 device->classes |= INPUT_DEVICE_CLASS_JOYSTICK;
883 }
884
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800885 // figure out the switches this device reports
Jeff Brown6f2fba42011-02-19 01:08:02 -0800886 bool haveSwitches = false;
887 for (int i=0; i<EV_SW; i++) {
888 //LOGI("Device %d sw %d: has=%d", device->id, i, test_bit(i, sw_bitmask));
889 if (test_bit(i, sw_bitmask)) {
890 haveSwitches = true;
891 if (mSwitches[i] == 0) {
892 mSwitches[i] = device->id;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800893 }
894 }
895 }
Jeff Brown6f2fba42011-02-19 01:08:02 -0800896 if (haveSwitches) {
Jeff Brown6d0fec22010-07-23 21:28:06 -0700897 device->classes |= INPUT_DEVICE_CLASS_SWITCH;
898 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800899
Jeff Brown58a2da82011-01-25 16:02:22 -0800900 if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) {
Jeff Brown90655042010-12-02 13:50:46 -0800901 // Load the virtual keys for the touch screen, if any.
902 // We do this now so that we can make sure to load the keymap if necessary.
903 status_t status = loadVirtualKeyMap(device);
904 if (!status) {
905 device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800906 }
Jeff Brown90655042010-12-02 13:50:46 -0800907 }
908
Jeff Brown9e8e40c2011-03-03 03:39:29 -0800909 // Load the key map.
910 // We need to do this for joysticks too because the key layout may specify axes.
911 status_t keyMapStatus = NAME_NOT_FOUND;
912 if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) {
Jeff Brown90655042010-12-02 13:50:46 -0800913 // Load the keymap for the device.
Jeff Brown9e8e40c2011-03-03 03:39:29 -0800914 keyMapStatus = loadKeyMap(device);
915 }
Jeff Brown90655042010-12-02 13:50:46 -0800916
Jeff Brown9e8e40c2011-03-03 03:39:29 -0800917 // Configure the keyboard, gamepad or virtual keyboard.
918 if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) {
Jeff Brown90655042010-12-02 13:50:46 -0800919 // Set system properties for the keyboard.
Jeff Brown497a92c2010-09-12 17:55:08 -0700920 setKeyboardProperties(device, false);
921
Jeff Brown90655042010-12-02 13:50:46 -0800922 // Register the keyboard as a built-in keyboard if it is eligible.
Jeff Brown9e8e40c2011-03-03 03:39:29 -0800923 if (!keyMapStatus
Jeff Brown90655042010-12-02 13:50:46 -0800924 && mBuiltInKeyboardId == -1
925 && isEligibleBuiltInKeyboard(device->identifier,
926 device->configuration, &device->keyMap)) {
927 mBuiltInKeyboardId = device->id;
928 setKeyboardProperties(device, true);
Jeff Brown497a92c2010-09-12 17:55:08 -0700929 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800930
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700931 // 'Q' key support = cheap test of whether this is an alpha-capable kbd
Jeff Brownf2f487182010-10-01 17:46:21 -0700932 if (hasKeycodeLocked(device, AKEYCODE_Q)) {
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700933 device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700934 }
Jeff Brown497a92c2010-09-12 17:55:08 -0700935
Jeff Brownfd0358292010-06-30 16:10:35 -0700936 // See if this device has a DPAD.
Jeff Brownf2f487182010-10-01 17:46:21 -0700937 if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) &&
938 hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) &&
939 hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) &&
940 hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) &&
941 hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) {
Jeff Brown46b9ac0a2010-04-22 18:58:52 -0700942 device->classes |= INPUT_DEVICE_CLASS_DPAD;
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700943 }
Jeff Brown497a92c2010-09-12 17:55:08 -0700944
Jeff Brownfd0358292010-06-30 16:10:35 -0700945 // See if this device has a gamepad.
Kenny Root1d79a9d2010-10-21 15:46:03 -0700946 for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) {
Jeff Brownf2f487182010-10-01 17:46:21 -0700947 if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) {
Jeff Brownfd0358292010-06-30 16:10:35 -0700948 device->classes |= INPUT_DEVICE_CLASS_GAMEPAD;
949 break;
950 }
951 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952 }
953
Sean McNeilaeb00c42010-06-23 16:00:37 +0700954 // If the device isn't recognized as something we handle, don't monitor it.
955 if (device->classes == 0) {
Jeff Brown90655042010-12-02 13:50:46 -0800956 LOGV("Dropping device: id=%d, path='%s', name='%s'",
957 deviceId, devicePath, device->identifier.name.string());
Sean McNeilaeb00c42010-06-23 16:00:37 +0700958 delete device;
959 return -1;
960 }
961
Jeff Brown56194eb2011-03-02 19:23:13 -0800962 // Determine whether the device is external or internal.
963 if (isExternalDevice(device)) {
964 device->classes |= INPUT_DEVICE_CLASS_EXTERNAL;
965 }
966
Jeff Brown90655042010-12-02 13:50:46 -0800967 LOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
968 "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s",
969 deviceId, fd, devicePath, device->identifier.name.string(),
970 device->classes,
971 device->configurationFile.string(),
972 device->keyMap.keyLayoutFile.string(),
973 device->keyMap.keyCharacterMapFile.string(),
974 toString(mBuiltInKeyboardId == deviceId));
Jeff Brown47e6b1b2010-11-29 17:37:49 -0800975
Jeff Brown90655042010-12-02 13:50:46 -0800976 struct pollfd pollfd;
977 pollfd.fd = fd;
978 pollfd.events = POLLIN;
979 pollfd.revents = 0;
980 mFds.push(pollfd);
981 mDevices.push(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 device->next = mOpeningDevices;
984 mOpeningDevices = device;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800985 return 0;
986}
987
Jeff Brown90655042010-12-02 13:50:46 -0800988void EventHub::loadConfiguration(Device* device) {
989 device->configurationFile = getInputDeviceConfigurationFilePathByDeviceIdentifier(
990 device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION);
Jeff Brown47e6b1b2010-11-29 17:37:49 -0800991 if (device->configurationFile.isEmpty()) {
Jeff Brown90655042010-12-02 13:50:46 -0800992 LOGD("No input device configuration file found for device '%s'.",
993 device->identifier.name.string());
Jeff Brown47e6b1b2010-11-29 17:37:49 -0800994 } else {
995 status_t status = PropertyMap::load(device->configurationFile,
996 &device->configuration);
997 if (status) {
Jeff Brown90655042010-12-02 13:50:46 -0800998 LOGE("Error loading input device configuration file for device '%s'. "
999 "Using default configuration.",
1000 device->identifier.name.string());
Jeff Brown47e6b1b2010-11-29 17:37:49 -08001001 }
1002 }
1003}
1004
Jeff Brown90655042010-12-02 13:50:46 -08001005status_t EventHub::loadVirtualKeyMap(Device* device) {
1006 // The virtual key map is supplied by the kernel as a system board property file.
1007 String8 path;
1008 path.append("/sys/board_properties/virtualkeys.");
1009 path.append(device->identifier.name);
1010 if (access(path.string(), R_OK)) {
1011 return NAME_NOT_FOUND;
1012 }
1013 return VirtualKeyMap::load(path, &device->virtualKeyMap);
Jeff Brown497a92c2010-09-12 17:55:08 -07001014}
1015
Jeff Brown90655042010-12-02 13:50:46 -08001016status_t EventHub::loadKeyMap(Device* device) {
1017 return device->keyMap.load(device->identifier, device->configuration);
Jeff Brown497a92c2010-09-12 17:55:08 -07001018}
1019
Jeff Brown90655042010-12-02 13:50:46 -08001020void EventHub::setKeyboardProperties(Device* device, bool builtInKeyboard) {
1021 int32_t id = builtInKeyboard ? 0 : device->id;
1022 android::setKeyboardProperties(id, device->identifier,
1023 device->keyMap.keyLayoutFile, device->keyMap.keyCharacterMapFile);
1024}
1025
1026void EventHub::clearKeyboardProperties(Device* device, bool builtInKeyboard) {
1027 int32_t id = builtInKeyboard ? 0 : device->id;
Jeff Brown6b53e8d2010-11-10 16:03:06 -08001028 android::clearKeyboardProperties(id);
Jeff Brown497a92c2010-09-12 17:55:08 -07001029}
1030
Jeff Brown56194eb2011-03-02 19:23:13 -08001031bool EventHub::isExternalDevice(Device* device) {
1032 if (device->configuration) {
1033 bool value;
1034 if (device->configuration->tryGetProperty(String8("device.internal"), value)
1035 && value) {
1036 return false;
1037 }
1038 }
1039 return device->identifier.bus == BUS_USB || device->identifier.bus == BUS_BLUETOOTH;
1040}
1041
Jeff Brown90655042010-12-02 13:50:46 -08001042bool EventHub::hasKeycodeLocked(Device* device, int keycode) const {
1043 if (!device->keyMap.haveKeyLayout() || !device->keyBitmask) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -07001044 return false;
1045 }
1046
1047 Vector<int32_t> scanCodes;
Jeff Brown6f2fba42011-02-19 01:08:02 -08001048 device->keyMap.keyLayoutMap->findScanCodesForKey(keycode, &scanCodes);
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -07001049 const size_t N = scanCodes.size();
1050 for (size_t i=0; i<N && i<=KEY_MAX; i++) {
1051 int32_t sc = scanCodes.itemAt(i);
1052 if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, device->keyBitmask)) {
1053 return true;
1054 }
1055 }
1056
1057 return false;
1058}
1059
Jeff Brown90655042010-12-02 13:50:46 -08001060int EventHub::closeDevice(const char *devicePath) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061 AutoMutex _l(mLock);
Jeff Brown7342bb92010-10-01 18:55:43 -07001062
Jeff Brown90655042010-12-02 13:50:46 -08001063 for (size_t i = FIRST_ACTUAL_DEVICE_INDEX; i < mDevices.size(); i++) {
1064 Device* device = mDevices[i];
1065 if (device->path == devicePath) {
Jeff Brown33bbfd22011-02-24 20:55:35 -08001066 return closeDeviceAtIndexLocked(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 }
1068 }
Jeff Brown33bbfd22011-02-24 20:55:35 -08001069 LOGV("Remove device: %s not found, device may already have been removed.", devicePath);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001070 return -1;
1071}
1072
Jeff Brown33bbfd22011-02-24 20:55:35 -08001073int EventHub::closeDeviceAtIndexLocked(int index) {
1074 Device* device = mDevices[index];
1075 LOGI("Removed device: path=%s name=%s id=%d fd=%d classes=0x%x\n",
1076 device->path.string(), device->identifier.name.string(), device->id,
1077 device->fd, device->classes);
1078
1079 for (int j=0; j<EV_SW; j++) {
1080 if (mSwitches[j] == device->id) {
1081 mSwitches[j] = 0;
1082 }
1083 }
1084
1085 if (device->id == mBuiltInKeyboardId) {
1086 LOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
1087 device->path.string(), mBuiltInKeyboardId);
1088 mBuiltInKeyboardId = -1;
1089 clearKeyboardProperties(device, true);
1090 }
1091 clearKeyboardProperties(device, false);
1092
1093 mFds.removeAt(index);
1094 mDevices.removeAt(index);
1095 device->close();
1096
Jeff Brown8e9d4432011-03-12 19:46:59 -08001097 // Unlink for opening devices list if it is present.
1098 Device* pred = NULL;
1099 bool found = false;
1100 for (Device* entry = mOpeningDevices; entry != NULL; ) {
1101 if (entry == device) {
1102 found = true;
1103 break;
1104 }
1105 pred = entry;
1106 entry = entry->next;
1107 }
1108 if (found) {
1109 // Unlink the device from the opening devices list then delete it.
1110 // We don't need to tell the client that the device was closed because
1111 // it does not even know it was opened in the first place.
1112 LOGI("Device %s was immediately closed after opening.", device->path.string());
1113 if (pred) {
1114 pred->next = device->next;
1115 } else {
1116 mOpeningDevices = device->next;
1117 }
1118 delete device;
1119 } else {
1120 // Link into closing devices list.
1121 // The device will be deleted later after we have informed the client.
1122 device->next = mClosingDevices;
1123 mClosingDevices = device;
1124 }
Jeff Brown33bbfd22011-02-24 20:55:35 -08001125 return 0;
1126}
1127
Jeff Brown7342bb92010-10-01 18:55:43 -07001128int EventHub::readNotify(int nfd) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001129#ifdef HAVE_INOTIFY
1130 int res;
1131 char devname[PATH_MAX];
1132 char *filename;
1133 char event_buf[512];
1134 int event_size;
1135 int event_pos = 0;
1136 struct inotify_event *event;
1137
Jeff Brown7342bb92010-10-01 18:55:43 -07001138 LOGV("EventHub::readNotify nfd: %d\n", nfd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001139 res = read(nfd, event_buf, sizeof(event_buf));
1140 if(res < (int)sizeof(*event)) {
1141 if(errno == EINTR)
1142 return 0;
1143 LOGW("could not get event, %s\n", strerror(errno));
1144 return 1;
1145 }
1146 //printf("got %d bytes of event information\n", res);
1147
Jeff Brown90655042010-12-02 13:50:46 -08001148 strcpy(devname, DEVICE_PATH);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001149 filename = devname + strlen(devname);
1150 *filename++ = '/';
1151
1152 while(res >= (int)sizeof(*event)) {
1153 event = (struct inotify_event *)(event_buf + event_pos);
1154 //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
1155 if(event->len) {
1156 strcpy(filename, event->name);
1157 if(event->mask & IN_CREATE) {
Jeff Brown7342bb92010-10-01 18:55:43 -07001158 openDevice(devname);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001159 }
1160 else {
Jeff Brown7342bb92010-10-01 18:55:43 -07001161 closeDevice(devname);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001162 }
1163 }
1164 event_size = sizeof(*event) + event->len;
1165 res -= event_size;
1166 event_pos += event_size;
1167 }
1168#endif
1169 return 0;
1170}
1171
Jeff Brown7342bb92010-10-01 18:55:43 -07001172int EventHub::scanDir(const char *dirname)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001173{
1174 char devname[PATH_MAX];
1175 char *filename;
1176 DIR *dir;
1177 struct dirent *de;
1178 dir = opendir(dirname);
1179 if(dir == NULL)
1180 return -1;
1181 strcpy(devname, dirname);
1182 filename = devname + strlen(devname);
1183 *filename++ = '/';
1184 while((de = readdir(dir))) {
1185 if(de->d_name[0] == '.' &&
1186 (de->d_name[1] == '\0' ||
1187 (de->d_name[1] == '.' && de->d_name[2] == '\0')))
1188 continue;
1189 strcpy(filename, de->d_name);
Jeff Brown7342bb92010-10-01 18:55:43 -07001190 openDevice(devname);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001191 }
1192 closedir(dir);
1193 return 0;
1194}
1195
Jeff Brownf2f487182010-10-01 17:46:21 -07001196void EventHub::dump(String8& dump) {
1197 dump.append("Event Hub State:\n");
1198
1199 { // acquire lock
1200 AutoMutex _l(mLock);
1201
Jeff Brown90655042010-12-02 13:50:46 -08001202 dump.appendFormat(INDENT "BuiltInKeyboardId: %d\n", mBuiltInKeyboardId);
Jeff Brownf2f487182010-10-01 17:46:21 -07001203
1204 dump.append(INDENT "Devices:\n");
1205
Jeff Brown90655042010-12-02 13:50:46 -08001206 for (size_t i = FIRST_ACTUAL_DEVICE_INDEX; i < mDevices.size(); i++) {
1207 const Device* device = mDevices[i];
Jeff Brownf2f487182010-10-01 17:46:21 -07001208 if (device) {
Jeff Brown90655042010-12-02 13:50:46 -08001209 if (mBuiltInKeyboardId == device->id) {
1210 dump.appendFormat(INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n",
1211 device->id, device->identifier.name.string());
Jeff Brownf2f487182010-10-01 17:46:21 -07001212 } else {
Jeff Brown90655042010-12-02 13:50:46 -08001213 dump.appendFormat(INDENT2 "%d: %s\n", device->id,
1214 device->identifier.name.string());
Jeff Brownf2f487182010-10-01 17:46:21 -07001215 }
1216 dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes);
1217 dump.appendFormat(INDENT3 "Path: %s\n", device->path.string());
Jeff Brown90655042010-12-02 13:50:46 -08001218 dump.appendFormat(INDENT3 "Location: %s\n", device->identifier.location.string());
1219 dump.appendFormat(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string());
1220 dump.appendFormat(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, "
1221 "product=0x%04x, version=0x%04x\n",
1222 device->identifier.bus, device->identifier.vendor,
1223 device->identifier.product, device->identifier.version);
Jeff Brown6b53e8d2010-11-10 16:03:06 -08001224 dump.appendFormat(INDENT3 "KeyLayoutFile: %s\n",
Jeff Brown90655042010-12-02 13:50:46 -08001225 device->keyMap.keyLayoutFile.string());
Jeff Brown6b53e8d2010-11-10 16:03:06 -08001226 dump.appendFormat(INDENT3 "KeyCharacterMapFile: %s\n",
Jeff Brown90655042010-12-02 13:50:46 -08001227 device->keyMap.keyCharacterMapFile.string());
Jeff Brown47e6b1b2010-11-29 17:37:49 -08001228 dump.appendFormat(INDENT3 "ConfigurationFile: %s\n",
1229 device->configurationFile.string());
Jeff Brownf2f487182010-10-01 17:46:21 -07001230 }
1231 }
1232 } // release lock
1233}
1234
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001235}; // namespace android