blob: 076e1d9804c5a39489f90db84426a91caf4d09fd [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001//
2// Copyright 2005 The Android Open Source Project
3//
4// Handle events, like key input and vsync.
5//
6// The goal is to provide an optimized solution for Linux, not an
7// implementation that works well across all platforms. We expect
8// events to arrive on file descriptors, so that we can use a select()
9// select() call to sleep.
10//
11// We can't select() on anything but network sockets in Windows, so we
12// provide an alternative implementation of waitEvent for that platform.
13//
14#define LOG_TAG "EventHub"
15
16//#define LOG_NDEBUG 0
17
18#include <ui/EventHub.h>
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070019#include <ui/KeycodeLabels.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020#include <hardware_legacy/power.h>
21
22#include <cutils/properties.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023#include <utils/Log.h>
24#include <utils/Timers.h>
Mathias Agopian3b4062e2009-05-31 19:13:00 -070025#include <utils/threads.h>
Mathias Agopian3b4062e2009-05-31 19:13:00 -070026#include <utils/Errors.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027
28#include <stdlib.h>
29#include <stdio.h>
30#include <unistd.h>
31#include <fcntl.h>
32#include <memory.h>
33#include <errno.h>
34#include <assert.h>
35
36#include "KeyLayoutMap.h"
37
38#include <string.h>
39#include <stdint.h>
40#include <dirent.h>
41#ifdef HAVE_INOTIFY
42# include <sys/inotify.h>
43#endif
44#ifdef HAVE_ANDROID_OS
45# include <sys/limits.h> /* not part of Linux */
46#endif
47#include <sys/poll.h>
48#include <sys/ioctl.h>
49
50/* this macro is used to tell if "bit" is set in "array"
51 * it selects a byte from the array, and does a boolean AND
52 * operation with a byte that only has the relevant bit set.
53 * eg. to check for the 12th bit, we do (array[1] & 1<<4)
54 */
55#define test_bit(bit, array) (array[bit/8] & (1<<(bit%8)))
56
57#define ID_MASK 0x0000ffff
58#define SEQ_MASK 0x7fff0000
59#define SEQ_SHIFT 16
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -070061#ifndef ABS_MT_TOUCH_MAJOR
62#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
63#endif
64
65#ifndef ABS_MT_POSITION_X
66#define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */
67#endif
68
69#ifndef ABS_MT_POSITION_Y
70#define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */
71#endif
72
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073namespace android {
74
75static const char *WAKE_LOCK_ID = "KeyEvents";
76static const char *device_path = "/dev/input";
77
78/* return the larger integer */
79static inline int max(int v1, int v2)
80{
81 return (v1 > v2) ? v1 : v2;
82}
83
Iliyan Malchevfc2ebc42009-08-06 14:50:08 -070084EventHub::device_t::device_t(int32_t _id, const char* _path, const char* name)
85 : id(_id), path(_path), name(name), classes(0)
Jens Gulin6d85ea92010-06-22 22:21:57 +020086 , keyBitmask(NULL), layoutMap(new KeyLayoutMap()), fd(-1), next(NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087}
88
89EventHub::device_t::~device_t() {
90 delete [] keyBitmask;
91 delete layoutMap;
92}
93
94EventHub::EventHub(void)
95 : mError(NO_INIT), mHaveFirstKeyboard(false), mFirstKeyboardId(0)
96 , mDevicesById(0), mNumDevicesById(0)
97 , mOpeningDevices(0), mClosingDevices(0)
Mike Lockwood1d9dfc52009-07-16 11:11:18 -040098 , mDevices(0), mFDs(0), mFDCount(0), mOpened(false)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099{
100 acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
101#ifdef EV_SW
102 memset(mSwitches, 0, sizeof(mSwitches));
103#endif
104}
105
106/*
107 * Clean up.
108 */
109EventHub::~EventHub(void)
110{
111 release_wake_lock(WAKE_LOCK_ID);
112 // we should free stuff here...
113}
114
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115status_t EventHub::errorCheck() const
116{
117 return mError;
118}
119
120String8 EventHub::getDeviceName(int32_t deviceId) const
121{
122 AutoMutex _l(mLock);
123 device_t* device = getDevice(deviceId);
124 if (device == NULL) return String8();
125 return device->name;
126}
127
128uint32_t EventHub::getDeviceClasses(int32_t deviceId) const
129{
130 AutoMutex _l(mLock);
131 device_t* device = getDevice(deviceId);
132 if (device == NULL) return 0;
133 return device->classes;
134}
135
136int EventHub::getAbsoluteInfo(int32_t deviceId, int axis, int *outMinValue,
137 int* outMaxValue, int* outFlat, int* outFuzz) const
138{
139 AutoMutex _l(mLock);
140 device_t* device = getDevice(deviceId);
141 if (device == NULL) return -1;
142
143 struct input_absinfo info;
144
Jens Gulin6d85ea92010-06-22 22:21:57 +0200145 if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146 LOGE("Error reading absolute controller %d for device %s fd %d\n",
Jens Gulin6d85ea92010-06-22 22:21:57 +0200147 axis, device->name.string(), device->fd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148 return -1;
149 }
Jens Gulin6d85ea92010-06-22 22:21:57 +0200150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151 *outMinValue = info.minimum;
152 *outMaxValue = info.maximum;
153 *outFlat = info.flat;
154 *outFuzz = info.fuzz;
155 return 0;
156}
157
158int EventHub::getSwitchState(int sw) const
159{
160#ifdef EV_SW
161 if (sw >= 0 && sw <= SW_MAX) {
162 int32_t devid = mSwitches[sw];
163 if (devid != 0) {
164 return getSwitchState(devid, sw);
165 }
166 }
167#endif
168 return -1;
169}
170
171int EventHub::getSwitchState(int32_t deviceId, int sw) const
172{
173#ifdef EV_SW
174 AutoMutex _l(mLock);
175 device_t* device = getDevice(deviceId);
176 if (device == NULL) return -1;
177
178 if (sw >= 0 && sw <= SW_MAX) {
Christopher Tateb776d5b2010-03-04 16:26:06 -0800179 uint8_t sw_bitmask[(SW_MAX+7)/8];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 memset(sw_bitmask, 0, sizeof(sw_bitmask));
Jens Gulin6d85ea92010-06-22 22:21:57 +0200181 if (ioctl(device->fd, EVIOCGSW(sizeof(sw_bitmask)), sw_bitmask) >= 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 return test_bit(sw, sw_bitmask) ? 1 : 0;
183 }
184 }
185#endif
186
187 return -1;
188}
189
190int EventHub::getScancodeState(int code) const
191{
192 return getScancodeState(mFirstKeyboardId, code);
193}
194
195int EventHub::getScancodeState(int32_t deviceId, int code) const
196{
197 AutoMutex _l(mLock);
198 device_t* device = getDevice(deviceId);
199 if (device == NULL) return -1;
200
201 if (code >= 0 && code <= KEY_MAX) {
Christopher Tateb776d5b2010-03-04 16:26:06 -0800202 uint8_t key_bitmask[(KEY_MAX+7)/8];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203 memset(key_bitmask, 0, sizeof(key_bitmask));
Jens Gulin6d85ea92010-06-22 22:21:57 +0200204 if (ioctl(device->fd, EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205 return test_bit(code, key_bitmask) ? 1 : 0;
206 }
207 }
208
209 return -1;
210}
211
212int EventHub::getKeycodeState(int code) const
213{
214 return getKeycodeState(mFirstKeyboardId, code);
215}
216
217int EventHub::getKeycodeState(int32_t deviceId, int code) const
218{
219 AutoMutex _l(mLock);
220 device_t* device = getDevice(deviceId);
221 if (device == NULL || device->layoutMap == NULL) return -1;
222
223 Vector<int32_t> scanCodes;
224 device->layoutMap->findScancodes(code, &scanCodes);
225
Christopher Tateb776d5b2010-03-04 16:26:06 -0800226 uint8_t key_bitmask[(KEY_MAX+7)/8];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227 memset(key_bitmask, 0, sizeof(key_bitmask));
Jens Gulin6d85ea92010-06-22 22:21:57 +0200228 if (ioctl(device->fd, EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229 #if 0
230 for (size_t i=0; i<=KEY_MAX; i++) {
231 LOGI("(Scan code %d: down=%d)", i, test_bit(i, key_bitmask));
232 }
233 #endif
234 const size_t N = scanCodes.size();
235 for (size_t i=0; i<N && i<=KEY_MAX; i++) {
236 int32_t sc = scanCodes.itemAt(i);
237 //LOGI("Code %d: down=%d", sc, test_bit(sc, key_bitmask));
238 if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, key_bitmask)) {
239 return 1;
240 }
241 }
242 }
243
244 return 0;
245}
246
Dianne Hackborne3dd8842009-07-14 12:06:54 -0700247status_t EventHub::scancodeToKeycode(int32_t deviceId, int scancode,
248 int32_t* outKeycode, uint32_t* outFlags) const
249{
250 AutoMutex _l(mLock);
251 device_t* device = getDevice(deviceId);
252
253 if (device != NULL && device->layoutMap != NULL) {
254 status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
255 if (err == NO_ERROR) {
256 return NO_ERROR;
257 }
258 }
259
260 if (mHaveFirstKeyboard) {
261 device = getDevice(mFirstKeyboardId);
262
263 if (device != NULL && device->layoutMap != NULL) {
264 status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
265 if (err == NO_ERROR) {
266 return NO_ERROR;
267 }
268 }
269 }
270
271 *outKeycode = 0;
272 *outFlags = 0;
273 return NAME_NOT_FOUND;
274}
275
Mike Lockwood1d9dfc52009-07-16 11:11:18 -0400276void EventHub::addExcludedDevice(const char* deviceName)
277{
278 String8 name(deviceName);
279 mExcludedDevices.push_back(name);
280}
281
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282EventHub::device_t* EventHub::getDevice(int32_t deviceId) const
283{
284 if (deviceId == 0) deviceId = mFirstKeyboardId;
285 int32_t id = deviceId & ID_MASK;
286 if (id >= mNumDevicesById || id < 0) return NULL;
287 device_t* dev = mDevicesById[id].device;
Dianne Hackborn4e829f02009-03-25 16:21:55 -0700288 if (dev == NULL) return NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289 if (dev->id == deviceId) {
290 return dev;
291 }
292 return NULL;
293}
294
295bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
296 int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
297 int32_t* outValue, nsecs_t* outWhen)
298{
299 *outDeviceId = 0;
300 *outType = 0;
301 *outScancode = 0;
302 *outKeycode = 0;
303 *outFlags = 0;
304 *outValue = 0;
305 *outWhen = 0;
306
307 status_t err;
308
309 fd_set readfds;
310 int maxFd = -1;
311 int cc;
312 int i;
313 int res;
314 int pollres;
315 struct input_event iev;
316
317 // Note that we only allow one caller to getEvent(), so don't need
318 // to do locking here... only when adding/removing devices.
Mike Lockwood1d9dfc52009-07-16 11:11:18 -0400319
320 if (!mOpened) {
321 mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
322 mOpened = true;
323 }
324
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 while(1) {
326
327 // First, report any devices that had last been added/removed.
328 if (mClosingDevices != NULL) {
329 device_t* device = mClosingDevices;
330 LOGV("Reporting device closed: id=0x%x, name=%s\n",
331 device->id, device->path.string());
332 mClosingDevices = device->next;
333 *outDeviceId = device->id;
334 if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
335 *outType = DEVICE_REMOVED;
336 delete device;
337 return true;
338 }
339 if (mOpeningDevices != NULL) {
340 device_t* device = mOpeningDevices;
341 LOGV("Reporting device opened: id=0x%x, name=%s\n",
342 device->id, device->path.string());
343 mOpeningDevices = device->next;
344 *outDeviceId = device->id;
345 if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
346 *outType = DEVICE_ADDED;
347 return true;
348 }
349
350 release_wake_lock(WAKE_LOCK_ID);
351
352 pollres = poll(mFDs, mFDCount, -1);
353
354 acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
355
356 if (pollres <= 0) {
357 if (errno != EINTR) {
358 LOGW("select failed (errno=%d)\n", errno);
359 usleep(100000);
360 }
361 continue;
362 }
363
364 //printf("poll %d, returned %d\n", mFDCount, pollres);
365
366 // mFDs[0] is used for inotify, so process regular events starting at mFDs[1]
367 for(i = 1; i < mFDCount; i++) {
368 if(mFDs[i].revents) {
369 LOGV("revents for %d = 0x%08x", i, mFDs[i].revents);
370 if(mFDs[i].revents & POLLIN) {
371 res = read(mFDs[i].fd, &iev, sizeof(iev));
372 if (res == sizeof(iev)) {
373 LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d",
374 mDevices[i]->path.string(),
375 (int) iev.time.tv_sec, (int) iev.time.tv_usec,
376 iev.type, iev.code, iev.value);
377 *outDeviceId = mDevices[i]->id;
378 if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
379 *outType = iev.type;
380 *outScancode = iev.code;
381 if (iev.type == EV_KEY) {
382 err = mDevices[i]->layoutMap->map(iev.code, outKeycode, outFlags);
383 LOGV("iev.code=%d outKeycode=%d outFlags=0x%08x err=%d\n",
384 iev.code, *outKeycode, *outFlags, err);
385 if (err != 0) {
386 *outKeycode = 0;
387 *outFlags = 0;
388 }
389 } else {
390 *outKeycode = iev.code;
391 }
392 *outValue = iev.value;
393 *outWhen = s2ns(iev.time.tv_sec) + us2ns(iev.time.tv_usec);
394 return true;
395 } else {
396 if (res<0) {
397 LOGW("could not get event (errno=%d)", errno);
398 } else {
399 LOGE("could not get event (wrong size: %d)", res);
400 }
401 continue;
402 }
403 }
404 }
405 }
406
407 // read_notify() will modify mFDs and mFDCount, so this must be done after
408 // processing all other events.
409 if(mFDs[0].revents & POLLIN) {
410 read_notify(mFDs[0].fd);
411 }
412 }
413}
414
415/*
416 * Open the platform-specific input device.
417 */
418bool EventHub::openPlatformInput(void)
419{
420 /*
421 * Open platform-specific input device(s).
422 */
423 int res;
424
425 mFDCount = 1;
426 mFDs = (pollfd *)calloc(1, sizeof(mFDs[0]));
427 mDevices = (device_t **)calloc(1, sizeof(mDevices[0]));
428 mFDs[0].events = POLLIN;
429 mDevices[0] = NULL;
430#ifdef HAVE_INOTIFY
431 mFDs[0].fd = inotify_init();
432 res = inotify_add_watch(mFDs[0].fd, device_path, IN_DELETE | IN_CREATE);
433 if(res < 0) {
434 LOGE("could not add watch for %s, %s\n", device_path, strerror(errno));
435 }
436#else
437 /*
438 * The code in EventHub::getEvent assumes that mFDs[0] is an inotify fd.
439 * We allocate space for it and set it to something invalid.
440 */
441 mFDs[0].fd = -1;
442#endif
443
444 res = scan_dir(device_path);
445 if(res < 0) {
446 LOGE("scan dir failed for %s\n", device_path);
447 //open_device("/dev/input/event0");
448 }
449
450 return true;
451}
452
453/*
454 * Inspect the known devices to determine whether physical keys exist for the given
455 * framework-domain key codes.
456 */
457bool EventHub::hasKeys(size_t numCodes, int32_t* keyCodes, uint8_t* outFlags) {
458 for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) {
459 outFlags[codeIndex] = 0;
460
461 // check each available hardware device for support for this keycode
462 Vector<int32_t> scanCodes;
463 for (int n = 0; (n < mFDCount) && (outFlags[codeIndex] == 0); n++) {
464 if (mDevices[n]) {
465 status_t err = mDevices[n]->layoutMap->findScancodes(keyCodes[codeIndex], &scanCodes);
466 if (!err) {
467 // check the possible scan codes identified by the layout map against the
468 // map of codes actually emitted by the driver
469 for (size_t sc = 0; sc < scanCodes.size(); sc++) {
470 if (test_bit(scanCodes[sc], mDevices[n]->keyBitmask)) {
471 outFlags[codeIndex] = 1;
472 break;
473 }
474 }
475 }
476 }
477 }
478 }
479
480 return true;
481}
482
483// ----------------------------------------------------------------------------
484
485int EventHub::open_device(const char *deviceName)
486{
487 int version;
488 int fd;
489 struct pollfd *new_mFDs;
490 device_t **new_devices;
491 char **new_device_names;
492 char name[80];
493 char location[80];
494 char idstr[80];
495 struct input_id id;
496
497 LOGV("Opening device: %s", deviceName);
498
499 AutoMutex _l(mLock);
Nick Pellye6b1bbd2010-01-20 19:36:49 -0800500
Nick Pellyc8b60d12010-01-26 10:27:15 -0800501 fd = open(deviceName, O_RDWR);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 if(fd < 0) {
503 LOGE("could not open %s, %s\n", deviceName, strerror(errno));
504 return -1;
505 }
506
507 if(ioctl(fd, EVIOCGVERSION, &version)) {
508 LOGE("could not get driver version for %s, %s\n", deviceName, strerror(errno));
509 return -1;
510 }
511 if(ioctl(fd, EVIOCGID, &id)) {
512 LOGE("could not get driver id for %s, %s\n", deviceName, strerror(errno));
513 return -1;
514 }
515 name[sizeof(name) - 1] = '\0';
516 location[sizeof(location) - 1] = '\0';
517 idstr[sizeof(idstr) - 1] = '\0';
518 if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
519 //fprintf(stderr, "could not get device name for %s, %s\n", deviceName, strerror(errno));
520 name[0] = '\0';
521 }
Mike Lockwood15431a92009-07-17 00:10:10 -0400522
523 // check to see if the device is on our excluded list
524 List<String8>::iterator iter = mExcludedDevices.begin();
525 List<String8>::iterator end = mExcludedDevices.end();
526 for ( ; iter != end; iter++) {
527 const char* test = *iter;
528 if (strcmp(name, test) == 0) {
529 LOGI("ignoring event id %s driver %s\n", deviceName, test);
530 close(fd);
531 fd = -1;
532 return -1;
533 }
534 }
535
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800536 if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
537 //fprintf(stderr, "could not get location for %s, %s\n", deviceName, strerror(errno));
538 location[0] = '\0';
539 }
540 if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
541 //fprintf(stderr, "could not get idstring for %s, %s\n", deviceName, strerror(errno));
542 idstr[0] = '\0';
543 }
544
545 int devid = 0;
546 while (devid < mNumDevicesById) {
547 if (mDevicesById[devid].device == NULL) {
548 break;
549 }
550 devid++;
551 }
552 if (devid >= mNumDevicesById) {
553 device_ent* new_devids = (device_ent*)realloc(mDevicesById,
554 sizeof(mDevicesById[0]) * (devid + 1));
555 if (new_devids == NULL) {
556 LOGE("out of memory");
557 return -1;
558 }
559 mDevicesById = new_devids;
560 mNumDevicesById = devid+1;
561 mDevicesById[devid].device = NULL;
562 mDevicesById[devid].seq = 0;
563 }
564
565 mDevicesById[devid].seq = (mDevicesById[devid].seq+(1<<SEQ_SHIFT))&SEQ_MASK;
566 if (mDevicesById[devid].seq == 0) {
567 mDevicesById[devid].seq = 1<<SEQ_SHIFT;
568 }
569
570 new_mFDs = (pollfd*)realloc(mFDs, sizeof(mFDs[0]) * (mFDCount + 1));
571 new_devices = (device_t**)realloc(mDevices, sizeof(mDevices[0]) * (mFDCount + 1));
572 if (new_mFDs == NULL || new_devices == NULL) {
573 LOGE("out of memory");
574 return -1;
575 }
576 mFDs = new_mFDs;
577 mDevices = new_devices;
578
579#if 0
580 LOGI("add device %d: %s\n", mFDCount, deviceName);
581 LOGI(" bus: %04x\n"
582 " vendor %04x\n"
583 " product %04x\n"
584 " version %04x\n",
585 id.bustype, id.vendor, id.product, id.version);
586 LOGI(" name: \"%s\"\n", name);
587 LOGI(" location: \"%s\"\n"
588 " id: \"%s\"\n", location, idstr);
589 LOGI(" version: %d.%d.%d\n",
590 version >> 16, (version >> 8) & 0xff, version & 0xff);
591#endif
592
Iliyan Malchevfc2ebc42009-08-06 14:50:08 -0700593 device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName, name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 if (device == NULL) {
595 LOGE("out of memory");
596 return -1;
597 }
598
Jens Gulin6d85ea92010-06-22 22:21:57 +0200599 device->fd = fd;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800600 mFDs[mFDCount].fd = fd;
601 mFDs[mFDCount].events = POLLIN;
602
603 // figure out the kinds of events the device reports
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700604
Dianne Hackborna2e92262010-03-02 17:19:29 -0800605 // See if this is a keyboard, and classify it. Note that we only
606 // consider up through the function keys; we don't want to include
607 // ones after that (play cd etc) so we don't mistakenly consider a
608 // controller to be a keyboard.
Christopher Tateb776d5b2010-03-04 16:26:06 -0800609 uint8_t key_bitmask[(KEY_MAX+7)/8];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610 memset(key_bitmask, 0, sizeof(key_bitmask));
611 LOGV("Getting keys...");
612 if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) {
613 //LOGI("MAP\n");
Christopher Tateb776d5b2010-03-04 16:26:06 -0800614 //for (int i=0; i<((KEY_MAX+7)/8); i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800615 // LOGI("%d: 0x%02x\n", i, key_bitmask[i]);
616 //}
617 for (int i=0; i<((BTN_MISC+7)/8); i++) {
618 if (key_bitmask[i] != 0) {
619 device->classes |= CLASS_KEYBOARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800620 break;
621 }
622 }
623 if ((device->classes & CLASS_KEYBOARD) != 0) {
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700624 device->keyBitmask = new uint8_t[sizeof(key_bitmask)];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800625 if (device->keyBitmask != NULL) {
626 memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
627 } else {
628 delete device;
629 LOGE("out of memory allocating key bitmask");
630 return -1;
631 }
632 }
633 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700634
635 // See if this is a trackball.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 if (test_bit(BTN_MOUSE, key_bitmask)) {
Christopher Tateb776d5b2010-03-04 16:26:06 -0800637 uint8_t rel_bitmask[(REL_MAX+7)/8];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800638 memset(rel_bitmask, 0, sizeof(rel_bitmask));
639 LOGV("Getting relative controllers...");
640 if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0)
641 {
642 if (test_bit(REL_X, rel_bitmask) && test_bit(REL_Y, rel_bitmask)) {
643 device->classes |= CLASS_TRACKBALL;
644 }
645 }
646 }
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700647
Christopher Tateb776d5b2010-03-04 16:26:06 -0800648 uint8_t abs_bitmask[(ABS_MAX+7)/8];
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700649 memset(abs_bitmask, 0, sizeof(abs_bitmask));
650 LOGV("Getting absolute controllers...");
651 ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask);
652
653 // Is this a new modern multi-touch driver?
654 if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask)
655 && test_bit(ABS_MT_POSITION_X, abs_bitmask)
656 && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) {
657 device->classes |= CLASS_TOUCHSCREEN | CLASS_TOUCHSCREEN_MT;
658
659 // Is this an old style single-touch driver?
660 } else if (test_bit(BTN_TOUCH, key_bitmask)
661 && test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {
662 device->classes |= CLASS_TOUCHSCREEN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800663 }
664
665#ifdef EV_SW
666 // figure out the switches this device reports
Christopher Tateb776d5b2010-03-04 16:26:06 -0800667 uint8_t sw_bitmask[(SW_MAX+7)/8];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 memset(sw_bitmask, 0, sizeof(sw_bitmask));
669 if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask) >= 0) {
670 for (int i=0; i<EV_SW; i++) {
671 //LOGI("Device 0x%x sw %d: has=%d", device->id, i, test_bit(i, sw_bitmask));
672 if (test_bit(i, sw_bitmask)) {
673 if (mSwitches[i] == 0) {
674 mSwitches[i] = device->id;
675 }
676 }
677 }
678 }
679#endif
680
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800681 if ((device->classes&CLASS_KEYBOARD) != 0) {
Iliyan Malchevfc2ebc42009-08-06 14:50:08 -0700682 char tmpfn[sizeof(name)];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683 char keylayoutFilename[300];
684
685 // a more descriptive name
Iliyan Malchevfc2ebc42009-08-06 14:50:08 -0700686 device->name = name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800687
688 // replace all the spaces with underscores
Iliyan Malchevfc2ebc42009-08-06 14:50:08 -0700689 strcpy(tmpfn, name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800690 for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))
691 *p = '_';
692
693 // find the .kl file we need for this device
694 const char* root = getenv("ANDROID_ROOT");
695 snprintf(keylayoutFilename, sizeof(keylayoutFilename),
696 "%s/usr/keylayout/%s.kl", root, tmpfn);
697 bool defaultKeymap = false;
698 if (access(keylayoutFilename, R_OK)) {
699 snprintf(keylayoutFilename, sizeof(keylayoutFilename),
700 "%s/usr/keylayout/%s", root, "qwerty.kl");
701 defaultKeymap = true;
702 }
703 device->layoutMap->load(keylayoutFilename);
704
705 // tell the world about the devname (the descriptive name)
Dianne Hackborna2e92262010-03-02 17:19:29 -0800706 if (!mHaveFirstKeyboard && !defaultKeymap && strstr(name, "-keypad")) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800707 // the built-in keyboard has a well-known device ID of 0,
708 // this device better not go away.
709 mHaveFirstKeyboard = true;
710 mFirstKeyboardId = device->id;
Dianne Hackborna2e92262010-03-02 17:19:29 -0800711 property_set("hw.keyboards.0.devname", name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800712 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800713 // ensure mFirstKeyboardId is set to -something-.
714 if (mFirstKeyboardId == 0) {
715 mFirstKeyboardId = device->id;
716 }
717 }
718 char propName[100];
Dianne Hackborna2e92262010-03-02 17:19:29 -0800719 sprintf(propName, "hw.keyboards.%u.devname", device->id);
Iliyan Malchevfc2ebc42009-08-06 14:50:08 -0700720 property_set(propName, name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800721
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700722 // 'Q' key support = cheap test of whether this is an alpha-capable kbd
723 if (hasKeycode(device, kKeyCodeQ)) {
724 device->classes |= CLASS_ALPHAKEY;
725 }
726
727 // See if this has a DPAD.
728 if (hasKeycode(device, kKeyCodeDpadUp) &&
729 hasKeycode(device, kKeyCodeDpadDown) &&
730 hasKeycode(device, kKeyCodeDpadLeft) &&
731 hasKeycode(device, kKeyCodeDpadRight) &&
732 hasKeycode(device, kKeyCodeDpadCenter)) {
733 device->classes |= CLASS_DPAD;
734 }
735
Dianne Hackborna2e92262010-03-02 17:19:29 -0800736 LOGI("New keyboard: device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n",
737 device->id, name, propName, keylayoutFilename);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 }
739
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700740 LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
741 deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes);
742
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 LOGV("Adding device %s %p at %d, id = %d, classes = 0x%x\n",
744 deviceName, device, mFDCount, devid, device->classes);
745
746 mDevicesById[devid].device = device;
747 device->next = mOpeningDevices;
748 mOpeningDevices = device;
749 mDevices[mFDCount] = device;
750
751 mFDCount++;
752 return 0;
753}
754
Dianne Hackborn0dd7cb42009-08-04 05:49:43 -0700755bool EventHub::hasKeycode(device_t* device, int keycode) const
756{
757 if (device->keyBitmask == NULL || device->layoutMap == NULL) {
758 return false;
759 }
760
761 Vector<int32_t> scanCodes;
762 device->layoutMap->findScancodes(keycode, &scanCodes);
763 const size_t N = scanCodes.size();
764 for (size_t i=0; i<N && i<=KEY_MAX; i++) {
765 int32_t sc = scanCodes.itemAt(i);
766 if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, device->keyBitmask)) {
767 return true;
768 }
769 }
770
771 return false;
772}
773
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800774int EventHub::close_device(const char *deviceName)
775{
776 AutoMutex _l(mLock);
777
778 int i;
779 for(i = 1; i < mFDCount; i++) {
780 if(strcmp(mDevices[i]->path.string(), deviceName) == 0) {
781 //LOGD("remove device %d: %s\n", i, deviceName);
782 device_t* device = mDevices[i];
Dianne Hackborna8f60182009-09-01 19:01:50 -0700783
784 LOGI("Removed device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
785 device->path.string(), device->name.string(), device->id,
786 mNumDevicesById, mFDCount, mFDs[i].fd, device->classes);
787
788 // Clear this device's entry.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800789 int index = (device->id&ID_MASK);
790 mDevicesById[index].device = NULL;
Dianne Hackborna8f60182009-09-01 19:01:50 -0700791
792 // Close the file descriptor and compact the fd array.
Mike Lockwood36dad722009-08-28 13:29:06 -0700793 close(mFDs[i].fd);
Dianne Hackborna8f60182009-09-01 19:01:50 -0700794 int count = mFDCount - i - 1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 memmove(mDevices + i, mDevices + i + 1, sizeof(mDevices[0]) * count);
796 memmove(mFDs + i, mFDs + i + 1, sizeof(mFDs[0]) * count);
Dianne Hackborna8f60182009-09-01 19:01:50 -0700797 mFDCount--;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800798
799#ifdef EV_SW
800 for (int j=0; j<EV_SW; j++) {
801 if (mSwitches[j] == device->id) {
802 mSwitches[j] = 0;
803 }
804 }
805#endif
806
807 device->next = mClosingDevices;
808 mClosingDevices = device;
809
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810 if (device->id == mFirstKeyboardId) {
811 LOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
812 device->path.string(), mFirstKeyboardId);
813 mFirstKeyboardId = 0;
Dianne Hackborna2e92262010-03-02 17:19:29 -0800814 property_set("hw.keyboards.0.devname", NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 }
816 // clear the property
817 char propName[100];
Dianne Hackborna2e92262010-03-02 17:19:29 -0800818 sprintf(propName, "hw.keyboards.%u.devname", device->id);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819 property_set(propName, NULL);
820 return 0;
821 }
822 }
Dianne Hackborna8f60182009-09-01 19:01:50 -0700823 LOGE("remove device: %s not found\n", deviceName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800824 return -1;
825}
826
827int EventHub::read_notify(int nfd)
828{
829#ifdef HAVE_INOTIFY
830 int res;
831 char devname[PATH_MAX];
832 char *filename;
833 char event_buf[512];
834 int event_size;
835 int event_pos = 0;
836 struct inotify_event *event;
837
Dianne Hackborna8f60182009-09-01 19:01:50 -0700838 LOGV("EventHub::read_notify nfd: %d\n", nfd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800839 res = read(nfd, event_buf, sizeof(event_buf));
840 if(res < (int)sizeof(*event)) {
841 if(errno == EINTR)
842 return 0;
843 LOGW("could not get event, %s\n", strerror(errno));
844 return 1;
845 }
846 //printf("got %d bytes of event information\n", res);
847
848 strcpy(devname, device_path);
849 filename = devname + strlen(devname);
850 *filename++ = '/';
851
852 while(res >= (int)sizeof(*event)) {
853 event = (struct inotify_event *)(event_buf + event_pos);
854 //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
855 if(event->len) {
856 strcpy(filename, event->name);
857 if(event->mask & IN_CREATE) {
858 open_device(devname);
859 }
860 else {
861 close_device(devname);
862 }
863 }
864 event_size = sizeof(*event) + event->len;
865 res -= event_size;
866 event_pos += event_size;
867 }
868#endif
869 return 0;
870}
871
872
873int EventHub::scan_dir(const char *dirname)
874{
875 char devname[PATH_MAX];
876 char *filename;
877 DIR *dir;
878 struct dirent *de;
879 dir = opendir(dirname);
880 if(dir == NULL)
881 return -1;
882 strcpy(devname, dirname);
883 filename = devname + strlen(devname);
884 *filename++ = '/';
885 while((de = readdir(dir))) {
886 if(de->d_name[0] == '.' &&
887 (de->d_name[1] == '\0' ||
888 (de->d_name[1] == '.' && de->d_name[2] == '\0')))
889 continue;
890 strcpy(filename, de->d_name);
891 open_device(devname);
892 }
893 closedir(dir);
894 return 0;
895}
896
897}; // namespace android