blob: 59c9476287f019f71bf0a468e5b1a909a84f4e9c [file] [log] [blame]
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001//
2// Copyright 2005 The Android Open Source Project
3//
4// Handle events, like key input and vsync.
5//
6// The goal is to provide an optimized solution for Linux, not an
7// implementation that works well across all platforms. We expect
8// events to arrive on file descriptors, so that we can use a select()
9// select() call to sleep.
10//
11// We can't select() on anything but network sockets in Windows, so we
12// provide an alternative implementation of waitEvent for that platform.
13//
14#define LOG_TAG "EventHub"
15
16//#define LOG_NDEBUG 0
17
18#include <ui/EventHub.h>
19#include <hardware_legacy/power.h>
20
21#include <cutils/properties.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080022#include <utils/Log.h>
23#include <utils/Timers.h>
Mathias Agopiane0c32202009-05-31 19:13:00 -070024#include <utils/threads.h>
Mathias Agopiane0c32202009-05-31 19:13:00 -070025#include <utils/Errors.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080026
27#include <stdlib.h>
28#include <stdio.h>
29#include <unistd.h>
30#include <fcntl.h>
31#include <memory.h>
32#include <errno.h>
33#include <assert.h>
34
35#include "KeyLayoutMap.h"
36
37#include <string.h>
38#include <stdint.h>
39#include <dirent.h>
40#ifdef HAVE_INOTIFY
41# include <sys/inotify.h>
42#endif
43#ifdef HAVE_ANDROID_OS
44# include <sys/limits.h> /* not part of Linux */
45#endif
46#include <sys/poll.h>
47#include <sys/ioctl.h>
48
49/* this macro is used to tell if "bit" is set in "array"
50 * it selects a byte from the array, and does a boolean AND
51 * operation with a byte that only has the relevant bit set.
52 * eg. to check for the 12th bit, we do (array[1] & 1<<4)
53 */
54#define test_bit(bit, array) (array[bit/8] & (1<<(bit%8)))
55
56#define ID_MASK 0x0000ffff
57#define SEQ_MASK 0x7fff0000
58#define SEQ_SHIFT 16
59#define id_to_index(id) ((id&ID_MASK)+1)
60
61namespace android {
62
63static const char *WAKE_LOCK_ID = "KeyEvents";
64static const char *device_path = "/dev/input";
65
66/* return the larger integer */
67static inline int max(int v1, int v2)
68{
69 return (v1 > v2) ? v1 : v2;
70}
71
72EventHub::device_t::device_t(int32_t _id, const char* _path)
73 : id(_id), path(_path), classes(0)
74 , keyBitmask(NULL), layoutMap(new KeyLayoutMap()), next(NULL) {
75}
76
77EventHub::device_t::~device_t() {
78 delete [] keyBitmask;
79 delete layoutMap;
80}
81
82EventHub::EventHub(void)
83 : mError(NO_INIT), mHaveFirstKeyboard(false), mFirstKeyboardId(0)
84 , mDevicesById(0), mNumDevicesById(0)
85 , mOpeningDevices(0), mClosingDevices(0)
Mike Lockwoodb4411062009-07-16 11:11:18 -040086 , mDevices(0), mFDs(0), mFDCount(0), mOpened(false)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080087{
88 acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
89#ifdef EV_SW
90 memset(mSwitches, 0, sizeof(mSwitches));
91#endif
92}
93
94/*
95 * Clean up.
96 */
97EventHub::~EventHub(void)
98{
99 release_wake_lock(WAKE_LOCK_ID);
100 // we should free stuff here...
101}
102
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800103status_t EventHub::errorCheck() const
104{
105 return mError;
106}
107
108String8 EventHub::getDeviceName(int32_t deviceId) const
109{
110 AutoMutex _l(mLock);
111 device_t* device = getDevice(deviceId);
112 if (device == NULL) return String8();
113 return device->name;
114}
115
116uint32_t EventHub::getDeviceClasses(int32_t deviceId) const
117{
118 AutoMutex _l(mLock);
119 device_t* device = getDevice(deviceId);
120 if (device == NULL) return 0;
121 return device->classes;
122}
123
124int EventHub::getAbsoluteInfo(int32_t deviceId, int axis, int *outMinValue,
125 int* outMaxValue, int* outFlat, int* outFuzz) const
126{
127 AutoMutex _l(mLock);
128 device_t* device = getDevice(deviceId);
129 if (device == NULL) return -1;
130
131 struct input_absinfo info;
132
133 if(ioctl(mFDs[id_to_index(device->id)].fd, EVIOCGABS(axis), &info)) {
134 LOGE("Error reading absolute controller %d for device %s fd %d\n",
135 axis, device->name.string(), mFDs[id_to_index(device->id)].fd);
136 return -1;
137 }
138 *outMinValue = info.minimum;
139 *outMaxValue = info.maximum;
140 *outFlat = info.flat;
141 *outFuzz = info.fuzz;
142 return 0;
143}
144
145int EventHub::getSwitchState(int sw) const
146{
147#ifdef EV_SW
148 if (sw >= 0 && sw <= SW_MAX) {
149 int32_t devid = mSwitches[sw];
150 if (devid != 0) {
151 return getSwitchState(devid, sw);
152 }
153 }
154#endif
155 return -1;
156}
157
158int EventHub::getSwitchState(int32_t deviceId, int sw) const
159{
160#ifdef EV_SW
161 AutoMutex _l(mLock);
162 device_t* device = getDevice(deviceId);
163 if (device == NULL) return -1;
164
165 if (sw >= 0 && sw <= SW_MAX) {
166 uint8_t sw_bitmask[(SW_MAX+1)/8];
167 memset(sw_bitmask, 0, sizeof(sw_bitmask));
168 if (ioctl(mFDs[id_to_index(device->id)].fd,
169 EVIOCGSW(sizeof(sw_bitmask)), sw_bitmask) >= 0) {
170 return test_bit(sw, sw_bitmask) ? 1 : 0;
171 }
172 }
173#endif
174
175 return -1;
176}
177
178int EventHub::getScancodeState(int code) const
179{
180 return getScancodeState(mFirstKeyboardId, code);
181}
182
183int EventHub::getScancodeState(int32_t deviceId, int code) const
184{
185 AutoMutex _l(mLock);
186 device_t* device = getDevice(deviceId);
187 if (device == NULL) return -1;
188
189 if (code >= 0 && code <= KEY_MAX) {
190 uint8_t key_bitmask[(KEY_MAX+1)/8];
191 memset(key_bitmask, 0, sizeof(key_bitmask));
192 if (ioctl(mFDs[id_to_index(device->id)].fd,
193 EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
194 return test_bit(code, key_bitmask) ? 1 : 0;
195 }
196 }
197
198 return -1;
199}
200
201int EventHub::getKeycodeState(int code) const
202{
203 return getKeycodeState(mFirstKeyboardId, code);
204}
205
206int EventHub::getKeycodeState(int32_t deviceId, int code) const
207{
208 AutoMutex _l(mLock);
209 device_t* device = getDevice(deviceId);
210 if (device == NULL || device->layoutMap == NULL) return -1;
211
212 Vector<int32_t> scanCodes;
213 device->layoutMap->findScancodes(code, &scanCodes);
214
215 uint8_t key_bitmask[(KEY_MAX+1)/8];
216 memset(key_bitmask, 0, sizeof(key_bitmask));
217 if (ioctl(mFDs[id_to_index(device->id)].fd,
218 EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
219 #if 0
220 for (size_t i=0; i<=KEY_MAX; i++) {
221 LOGI("(Scan code %d: down=%d)", i, test_bit(i, key_bitmask));
222 }
223 #endif
224 const size_t N = scanCodes.size();
225 for (size_t i=0; i<N && i<=KEY_MAX; i++) {
226 int32_t sc = scanCodes.itemAt(i);
227 //LOGI("Code %d: down=%d", sc, test_bit(sc, key_bitmask));
228 if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, key_bitmask)) {
229 return 1;
230 }
231 }
232 }
233
234 return 0;
235}
236
Dianne Hackbornc968c3a2009-07-14 12:06:54 -0700237status_t EventHub::scancodeToKeycode(int32_t deviceId, int scancode,
238 int32_t* outKeycode, uint32_t* outFlags) const
239{
240 AutoMutex _l(mLock);
241 device_t* device = getDevice(deviceId);
242
243 if (device != NULL && device->layoutMap != NULL) {
244 status_t err = device->layoutMap->map(scancode, outKeycode, outFlags);
245 if (err == NO_ERROR) {
246 return NO_ERROR;
247 }
248 }
249
250 if (mHaveFirstKeyboard) {
251 device = getDevice(mFirstKeyboardId);
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
261 *outKeycode = 0;
262 *outFlags = 0;
263 return NAME_NOT_FOUND;
264}
265
Mike Lockwoodb4411062009-07-16 11:11:18 -0400266void EventHub::addExcludedDevice(const char* deviceName)
267{
268 String8 name(deviceName);
269 mExcludedDevices.push_back(name);
270}
271
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800272EventHub::device_t* EventHub::getDevice(int32_t deviceId) const
273{
274 if (deviceId == 0) deviceId = mFirstKeyboardId;
275 int32_t id = deviceId & ID_MASK;
276 if (id >= mNumDevicesById || id < 0) return NULL;
277 device_t* dev = mDevicesById[id].device;
Dianne Hackbornc3aa00b2009-03-25 16:21:55 -0700278 if (dev == NULL) return NULL;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800279 if (dev->id == deviceId) {
280 return dev;
281 }
282 return NULL;
283}
284
285bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
286 int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
287 int32_t* outValue, nsecs_t* outWhen)
288{
289 *outDeviceId = 0;
290 *outType = 0;
291 *outScancode = 0;
292 *outKeycode = 0;
293 *outFlags = 0;
294 *outValue = 0;
295 *outWhen = 0;
296
297 status_t err;
298
299 fd_set readfds;
300 int maxFd = -1;
301 int cc;
302 int i;
303 int res;
304 int pollres;
305 struct input_event iev;
306
307 // Note that we only allow one caller to getEvent(), so don't need
308 // to do locking here... only when adding/removing devices.
Mike Lockwoodb4411062009-07-16 11:11:18 -0400309
310 if (!mOpened) {
311 mError = openPlatformInput() ? NO_ERROR : UNKNOWN_ERROR;
312 mOpened = true;
313 }
314
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800315 while(1) {
316
317 // First, report any devices that had last been added/removed.
318 if (mClosingDevices != NULL) {
319 device_t* device = mClosingDevices;
320 LOGV("Reporting device closed: id=0x%x, name=%s\n",
321 device->id, device->path.string());
322 mClosingDevices = device->next;
323 *outDeviceId = device->id;
324 if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
325 *outType = DEVICE_REMOVED;
326 delete device;
327 return true;
328 }
329 if (mOpeningDevices != NULL) {
330 device_t* device = mOpeningDevices;
331 LOGV("Reporting device opened: id=0x%x, name=%s\n",
332 device->id, device->path.string());
333 mOpeningDevices = device->next;
334 *outDeviceId = device->id;
335 if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
336 *outType = DEVICE_ADDED;
337 return true;
338 }
339
340 release_wake_lock(WAKE_LOCK_ID);
341
342 pollres = poll(mFDs, mFDCount, -1);
343
344 acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
345
346 if (pollres <= 0) {
347 if (errno != EINTR) {
348 LOGW("select failed (errno=%d)\n", errno);
349 usleep(100000);
350 }
351 continue;
352 }
353
354 //printf("poll %d, returned %d\n", mFDCount, pollres);
355
356 // mFDs[0] is used for inotify, so process regular events starting at mFDs[1]
357 for(i = 1; i < mFDCount; i++) {
358 if(mFDs[i].revents) {
359 LOGV("revents for %d = 0x%08x", i, mFDs[i].revents);
360 if(mFDs[i].revents & POLLIN) {
361 res = read(mFDs[i].fd, &iev, sizeof(iev));
362 if (res == sizeof(iev)) {
363 LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d",
364 mDevices[i]->path.string(),
365 (int) iev.time.tv_sec, (int) iev.time.tv_usec,
366 iev.type, iev.code, iev.value);
367 *outDeviceId = mDevices[i]->id;
368 if (*outDeviceId == mFirstKeyboardId) *outDeviceId = 0;
369 *outType = iev.type;
370 *outScancode = iev.code;
371 if (iev.type == EV_KEY) {
372 err = mDevices[i]->layoutMap->map(iev.code, outKeycode, outFlags);
373 LOGV("iev.code=%d outKeycode=%d outFlags=0x%08x err=%d\n",
374 iev.code, *outKeycode, *outFlags, err);
375 if (err != 0) {
376 *outKeycode = 0;
377 *outFlags = 0;
378 }
379 } else {
380 *outKeycode = iev.code;
381 }
382 *outValue = iev.value;
383 *outWhen = s2ns(iev.time.tv_sec) + us2ns(iev.time.tv_usec);
384 return true;
385 } else {
386 if (res<0) {
387 LOGW("could not get event (errno=%d)", errno);
388 } else {
389 LOGE("could not get event (wrong size: %d)", res);
390 }
391 continue;
392 }
393 }
394 }
395 }
396
397 // read_notify() will modify mFDs and mFDCount, so this must be done after
398 // processing all other events.
399 if(mFDs[0].revents & POLLIN) {
400 read_notify(mFDs[0].fd);
401 }
402 }
403}
404
405/*
406 * Open the platform-specific input device.
407 */
408bool EventHub::openPlatformInput(void)
409{
410 /*
411 * Open platform-specific input device(s).
412 */
413 int res;
414
415 mFDCount = 1;
416 mFDs = (pollfd *)calloc(1, sizeof(mFDs[0]));
417 mDevices = (device_t **)calloc(1, sizeof(mDevices[0]));
418 mFDs[0].events = POLLIN;
419 mDevices[0] = NULL;
420#ifdef HAVE_INOTIFY
421 mFDs[0].fd = inotify_init();
422 res = inotify_add_watch(mFDs[0].fd, device_path, IN_DELETE | IN_CREATE);
423 if(res < 0) {
424 LOGE("could not add watch for %s, %s\n", device_path, strerror(errno));
425 }
426#else
427 /*
428 * The code in EventHub::getEvent assumes that mFDs[0] is an inotify fd.
429 * We allocate space for it and set it to something invalid.
430 */
431 mFDs[0].fd = -1;
432#endif
433
434 res = scan_dir(device_path);
435 if(res < 0) {
436 LOGE("scan dir failed for %s\n", device_path);
437 //open_device("/dev/input/event0");
438 }
439
440 return true;
441}
442
443/*
444 * Inspect the known devices to determine whether physical keys exist for the given
445 * framework-domain key codes.
446 */
447bool EventHub::hasKeys(size_t numCodes, int32_t* keyCodes, uint8_t* outFlags) {
448 for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) {
449 outFlags[codeIndex] = 0;
450
451 // check each available hardware device for support for this keycode
452 Vector<int32_t> scanCodes;
453 for (int n = 0; (n < mFDCount) && (outFlags[codeIndex] == 0); n++) {
454 if (mDevices[n]) {
455 status_t err = mDevices[n]->layoutMap->findScancodes(keyCodes[codeIndex], &scanCodes);
456 if (!err) {
457 // check the possible scan codes identified by the layout map against the
458 // map of codes actually emitted by the driver
459 for (size_t sc = 0; sc < scanCodes.size(); sc++) {
460 if (test_bit(scanCodes[sc], mDevices[n]->keyBitmask)) {
461 outFlags[codeIndex] = 1;
462 break;
463 }
464 }
465 }
466 }
467 }
468 }
469
470 return true;
471}
472
473// ----------------------------------------------------------------------------
474
475int EventHub::open_device(const char *deviceName)
476{
477 int version;
478 int fd;
479 struct pollfd *new_mFDs;
480 device_t **new_devices;
481 char **new_device_names;
482 char name[80];
483 char location[80];
484 char idstr[80];
485 struct input_id id;
486
487 LOGV("Opening device: %s", deviceName);
488
489 AutoMutex _l(mLock);
490
491 fd = open(deviceName, O_RDWR);
492 if(fd < 0) {
493 LOGE("could not open %s, %s\n", deviceName, strerror(errno));
494 return -1;
495 }
496
497 if(ioctl(fd, EVIOCGVERSION, &version)) {
498 LOGE("could not get driver version for %s, %s\n", deviceName, strerror(errno));
499 return -1;
500 }
501 if(ioctl(fd, EVIOCGID, &id)) {
502 LOGE("could not get driver id for %s, %s\n", deviceName, strerror(errno));
503 return -1;
504 }
505 name[sizeof(name) - 1] = '\0';
506 location[sizeof(location) - 1] = '\0';
507 idstr[sizeof(idstr) - 1] = '\0';
508 if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
509 //fprintf(stderr, "could not get device name for %s, %s\n", deviceName, strerror(errno));
510 name[0] = '\0';
511 }
Mike Lockwood24a7e042009-07-17 00:10:10 -0400512
513 // check to see if the device is on our excluded list
514 List<String8>::iterator iter = mExcludedDevices.begin();
515 List<String8>::iterator end = mExcludedDevices.end();
516 for ( ; iter != end; iter++) {
517 const char* test = *iter;
518 if (strcmp(name, test) == 0) {
519 LOGI("ignoring event id %s driver %s\n", deviceName, test);
520 close(fd);
521 fd = -1;
522 return -1;
523 }
524 }
525
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800526 if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
527 //fprintf(stderr, "could not get location for %s, %s\n", deviceName, strerror(errno));
528 location[0] = '\0';
529 }
530 if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
531 //fprintf(stderr, "could not get idstring for %s, %s\n", deviceName, strerror(errno));
532 idstr[0] = '\0';
533 }
534
535 int devid = 0;
536 while (devid < mNumDevicesById) {
537 if (mDevicesById[devid].device == NULL) {
538 break;
539 }
540 devid++;
541 }
542 if (devid >= mNumDevicesById) {
543 device_ent* new_devids = (device_ent*)realloc(mDevicesById,
544 sizeof(mDevicesById[0]) * (devid + 1));
545 if (new_devids == NULL) {
546 LOGE("out of memory");
547 return -1;
548 }
549 mDevicesById = new_devids;
550 mNumDevicesById = devid+1;
551 mDevicesById[devid].device = NULL;
552 mDevicesById[devid].seq = 0;
553 }
554
555 mDevicesById[devid].seq = (mDevicesById[devid].seq+(1<<SEQ_SHIFT))&SEQ_MASK;
556 if (mDevicesById[devid].seq == 0) {
557 mDevicesById[devid].seq = 1<<SEQ_SHIFT;
558 }
559
560 new_mFDs = (pollfd*)realloc(mFDs, sizeof(mFDs[0]) * (mFDCount + 1));
561 new_devices = (device_t**)realloc(mDevices, sizeof(mDevices[0]) * (mFDCount + 1));
562 if (new_mFDs == NULL || new_devices == NULL) {
563 LOGE("out of memory");
564 return -1;
565 }
566 mFDs = new_mFDs;
567 mDevices = new_devices;
568
569#if 0
570 LOGI("add device %d: %s\n", mFDCount, deviceName);
571 LOGI(" bus: %04x\n"
572 " vendor %04x\n"
573 " product %04x\n"
574 " version %04x\n",
575 id.bustype, id.vendor, id.product, id.version);
576 LOGI(" name: \"%s\"\n", name);
577 LOGI(" location: \"%s\"\n"
578 " id: \"%s\"\n", location, idstr);
579 LOGI(" version: %d.%d.%d\n",
580 version >> 16, (version >> 8) & 0xff, version & 0xff);
581#endif
582
583 device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName);
584 if (device == NULL) {
585 LOGE("out of memory");
586 return -1;
587 }
588
589 mFDs[mFDCount].fd = fd;
590 mFDs[mFDCount].events = POLLIN;
591
592 // figure out the kinds of events the device reports
593 uint8_t key_bitmask[(KEY_MAX+1)/8];
594 memset(key_bitmask, 0, sizeof(key_bitmask));
595 LOGV("Getting keys...");
596 if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) {
597 //LOGI("MAP\n");
598 //for (int i=0; i<((KEY_MAX+1)/8); i++) {
599 // LOGI("%d: 0x%02x\n", i, key_bitmask[i]);
600 //}
601 for (int i=0; i<((BTN_MISC+7)/8); i++) {
602 if (key_bitmask[i] != 0) {
603 device->classes |= CLASS_KEYBOARD;
604 // 'Q' key support = cheap test of whether this is an alpha-capable kbd
605 if (test_bit(KEY_Q, key_bitmask)) {
606 device->classes |= CLASS_ALPHAKEY;
607 }
608 break;
609 }
610 }
611 if ((device->classes & CLASS_KEYBOARD) != 0) {
612 device->keyBitmask = new uint8_t[(KEY_MAX+1)/8];
613 if (device->keyBitmask != NULL) {
614 memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
615 } else {
616 delete device;
617 LOGE("out of memory allocating key bitmask");
618 return -1;
619 }
620 }
621 }
622 if (test_bit(BTN_MOUSE, key_bitmask)) {
623 uint8_t rel_bitmask[(REL_MAX+1)/8];
624 memset(rel_bitmask, 0, sizeof(rel_bitmask));
625 LOGV("Getting relative controllers...");
626 if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0)
627 {
628 if (test_bit(REL_X, rel_bitmask) && test_bit(REL_Y, rel_bitmask)) {
629 device->classes |= CLASS_TRACKBALL;
630 }
631 }
632 }
633 if (test_bit(BTN_TOUCH, key_bitmask)) {
634 uint8_t abs_bitmask[(ABS_MAX+1)/8];
635 memset(abs_bitmask, 0, sizeof(abs_bitmask));
636 LOGV("Getting absolute controllers...");
637 if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0)
638 {
639 if (test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {
640 device->classes |= CLASS_TOUCHSCREEN;
641 }
642 }
643 }
644
645#ifdef EV_SW
646 // figure out the switches this device reports
647 uint8_t sw_bitmask[(SW_MAX+1)/8];
648 memset(sw_bitmask, 0, sizeof(sw_bitmask));
649 if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask) >= 0) {
650 for (int i=0; i<EV_SW; i++) {
651 //LOGI("Device 0x%x sw %d: has=%d", device->id, i, test_bit(i, sw_bitmask));
652 if (test_bit(i, sw_bitmask)) {
653 if (mSwitches[i] == 0) {
654 mSwitches[i] = device->id;
655 }
656 }
657 }
658 }
659#endif
660
661 LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
662 deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes);
663
664 if ((device->classes&CLASS_KEYBOARD) != 0) {
665 char devname[101];
666 char tmpfn[101];
667 char keylayoutFilename[300];
668
669 // a more descriptive name
670 ioctl(mFDs[mFDCount].fd, EVIOCGNAME(sizeof(devname)-1), devname);
671 devname[sizeof(devname)-1] = 0;
672 device->name = devname;
673
674 // replace all the spaces with underscores
675 strcpy(tmpfn, devname);
676 for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))
677 *p = '_';
678
679 // find the .kl file we need for this device
680 const char* root = getenv("ANDROID_ROOT");
681 snprintf(keylayoutFilename, sizeof(keylayoutFilename),
682 "%s/usr/keylayout/%s.kl", root, tmpfn);
683 bool defaultKeymap = false;
684 if (access(keylayoutFilename, R_OK)) {
685 snprintf(keylayoutFilename, sizeof(keylayoutFilename),
686 "%s/usr/keylayout/%s", root, "qwerty.kl");
687 defaultKeymap = true;
688 }
689 device->layoutMap->load(keylayoutFilename);
690
691 // tell the world about the devname (the descriptive name)
692 int32_t publicID;
693 if (!mHaveFirstKeyboard && !defaultKeymap) {
694 publicID = 0;
695 // the built-in keyboard has a well-known device ID of 0,
696 // this device better not go away.
697 mHaveFirstKeyboard = true;
698 mFirstKeyboardId = device->id;
699 } else {
700 publicID = device->id;
701 // ensure mFirstKeyboardId is set to -something-.
702 if (mFirstKeyboardId == 0) {
703 mFirstKeyboardId = device->id;
704 }
705 }
706 char propName[100];
707 sprintf(propName, "hw.keyboards.%u.devname", publicID);
708 property_set(propName, devname);
709
710 LOGI("New keyboard: publicID=%d device->id=%d devname='%s' propName='%s' keylayout='%s'\n",
711 publicID, device->id, devname, propName, keylayoutFilename);
712 }
713
714 LOGV("Adding device %s %p at %d, id = %d, classes = 0x%x\n",
715 deviceName, device, mFDCount, devid, device->classes);
716
717 mDevicesById[devid].device = device;
718 device->next = mOpeningDevices;
719 mOpeningDevices = device;
720 mDevices[mFDCount] = device;
721
722 mFDCount++;
723 return 0;
724}
725
726int EventHub::close_device(const char *deviceName)
727{
728 AutoMutex _l(mLock);
729
730 int i;
731 for(i = 1; i < mFDCount; i++) {
732 if(strcmp(mDevices[i]->path.string(), deviceName) == 0) {
733 //LOGD("remove device %d: %s\n", i, deviceName);
734 device_t* device = mDevices[i];
735 int count = mFDCount - i - 1;
736 int index = (device->id&ID_MASK);
737 mDevicesById[index].device = NULL;
738 memmove(mDevices + i, mDevices + i + 1, sizeof(mDevices[0]) * count);
739 memmove(mFDs + i, mFDs + i + 1, sizeof(mFDs[0]) * count);
740
741#ifdef EV_SW
742 for (int j=0; j<EV_SW; j++) {
743 if (mSwitches[j] == device->id) {
744 mSwitches[j] = 0;
745 }
746 }
747#endif
748
749 device->next = mClosingDevices;
750 mClosingDevices = device;
751
752 mFDCount--;
753
754 uint32_t publicID;
755 if (device->id == mFirstKeyboardId) {
756 LOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this",
757 device->path.string(), mFirstKeyboardId);
758 mFirstKeyboardId = 0;
759 publicID = 0;
760 } else {
761 publicID = device->id;
762 }
763 // clear the property
764 char propName[100];
765 sprintf(propName, "hw.keyboards.%u.devname", publicID);
766 property_set(propName, NULL);
767 return 0;
768 }
769 }
770 LOGE("remote device: %s not found\n", deviceName);
771 return -1;
772}
773
774int EventHub::read_notify(int nfd)
775{
776#ifdef HAVE_INOTIFY
777 int res;
778 char devname[PATH_MAX];
779 char *filename;
780 char event_buf[512];
781 int event_size;
782 int event_pos = 0;
783 struct inotify_event *event;
784
Mike Lockwoodb4411062009-07-16 11:11:18 -0400785LOGD("EventHub::read_notify nfd: %d\n", nfd);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800786 res = read(nfd, event_buf, sizeof(event_buf));
787 if(res < (int)sizeof(*event)) {
788 if(errno == EINTR)
789 return 0;
790 LOGW("could not get event, %s\n", strerror(errno));
791 return 1;
792 }
793 //printf("got %d bytes of event information\n", res);
794
795 strcpy(devname, device_path);
796 filename = devname + strlen(devname);
797 *filename++ = '/';
798
799 while(res >= (int)sizeof(*event)) {
800 event = (struct inotify_event *)(event_buf + event_pos);
801 //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
802 if(event->len) {
803 strcpy(filename, event->name);
804 if(event->mask & IN_CREATE) {
805 open_device(devname);
806 }
807 else {
808 close_device(devname);
809 }
810 }
811 event_size = sizeof(*event) + event->len;
812 res -= event_size;
813 event_pos += event_size;
814 }
815#endif
816 return 0;
817}
818
819
820int EventHub::scan_dir(const char *dirname)
821{
822 char devname[PATH_MAX];
823 char *filename;
824 DIR *dir;
825 struct dirent *de;
826 dir = opendir(dirname);
827 if(dir == NULL)
828 return -1;
829 strcpy(devname, dirname);
830 filename = devname + strlen(devname);
831 *filename++ = '/';
832 while((de = readdir(dir))) {
833 if(de->d_name[0] == '.' &&
834 (de->d_name[1] == '\0' ||
835 (de->d_name[1] == '.' && de->d_name[2] == '\0')))
836 continue;
837 strcpy(filename, de->d_name);
838 open_device(devname);
839 }
840 closedir(dir);
841 return 0;
842}
843
844}; // namespace android