#include <input/KeyCharacterMap.h>
#include <input/VirtualKeyMap.h>
+#include <linux/vt.h>
+
/* this macro is used to tell if "bit" is set in "array"
* it selects a byte from the array, and does a boolean AND
* operation with a byte that only has the relevant bit set.
fd(fd), id(id), path(path), identifier(identifier),
classes(0), configuration(NULL), virtualKeyMap(NULL),
ffEffectPlaying(false), ffEffectId(-1), controllerNumber(0),
- timestampOverrideSec(0), timestampOverrideUsec(0) {
+ timestampOverrideSec(0), timestampOverrideUsec(0), enabled(true),
+ isVirtual(fd < 0) {
memset(keyBitmask, 0, sizeof(keyBitmask));
memset(absBitmask, 0, sizeof(absBitmask));
memset(relBitmask, 0, sizeof(relBitmask));
}
}
+status_t EventHub::Device::enable() {
+ fd = open(path, O_RDWR | O_CLOEXEC | O_NONBLOCK);
+ if(fd < 0) {
+ ALOGE("could not open %s, %s\n", path.string(), strerror(errno));
+ return -errno;
+ }
+ enabled = true;
+ return OK;
+}
+
+status_t EventHub::Device::disable() {
+ close();
+ enabled = false;
+ return OK;
+}
+
+bool EventHub::Device::hasValidFd() {
+ return !isVirtual && enabled;
+}
// --- EventHub ---
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && !device->isVirtual() && test_bit(axis, device->absBitmask)) {
+ if (device && device->hasValidFd() && test_bit(axis, device->absBitmask)) {
struct input_absinfo info;
if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d",
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && !device->isVirtual() && test_bit(scanCode, device->keyBitmask)) {
+ if (device && device->hasValidFd() && test_bit(scanCode, device->keyBitmask)) {
uint8_t keyState[sizeof_bit_array(KEY_MAX + 1)];
memset(keyState, 0, sizeof(keyState));
if (ioctl(device->fd, EVIOCGKEY(sizeof(keyState)), keyState) >= 0) {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && !device->isVirtual() && device->keyMap.haveKeyLayout()) {
+ if (device && device->hasValidFd() && device->keyMap.haveKeyLayout()) {
Vector<int32_t> scanCodes;
device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode, &scanCodes);
if (scanCodes.size() != 0) {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && !device->isVirtual() && test_bit(sw, device->swBitmask)) {
+ if (device && device->hasValidFd() && test_bit(sw, device->swBitmask)) {
uint8_t swState[sizeof_bit_array(SW_MAX + 1)];
memset(swState, 0, sizeof(swState));
if (ioctl(device->fd, EVIOCGSW(sizeof(swState)), swState) >= 0) {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && !device->isVirtual() && test_bit(axis, device->absBitmask)) {
+ if (device && device->hasValidFd() && test_bit(axis, device->absBitmask)) {
struct input_absinfo info;
if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d",
void EventHub::setLedStateLocked(Device* device, int32_t led, bool on) {
int32_t sc;
- if (device && !device->isVirtual() && mapLed(device, led, &sc) != NAME_NOT_FOUND) {
+ if (device && device->hasValidFd() && mapLed(device, led, &sc) != NAME_NOT_FOUND) {
struct input_event ev;
ev.time.tv_sec = 0;
ev.time.tv_usec = 0;
void EventHub::vibrate(int32_t deviceId, nsecs_t duration) {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && !device->isVirtual()) {
+ if (device && device->hasValidFd()) {
ff_effect effect;
memset(&effect, 0, sizeof(effect));
effect.type = FF_RUMBLE;
void EventHub::cancelVibrate(int32_t deviceId) {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && !device->isVirtual()) {
+ if (device && device->hasValidFd()) {
if (device->ffEffectPlaying) {
device->ffEffectPlaying = false;
}
}
+#ifdef CONSOLE_MANAGER
+ struct vt_stat vs;
+ int fd_vt = open("/dev/tty0", O_RDWR | O_SYNC);
+ if (fd_vt >= 0) {
+ ioctl(fd_vt, VT_GETSTATE, &vs);
+ close(fd_vt);
+ }
+#endif
// Grab the next input event.
bool deviceChanged = false;
while (mPendingEventIndex < mPendingEventCount) {
} else if ((readSize % sizeof(struct input_event)) != 0) {
ALOGE("could not get event (wrong size: %d)", readSize);
} else {
+#ifdef CONSOLE_MANAGER
+ if (vs.v_active != ANDROID_VT) {
+ ALOGV("Skip a non Android VT event");
+ continue;
+ }
+#endif
int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
size_t count = size_t(readSize) / sizeof(struct input_event);
AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE,
};
+status_t EventHub::registerDeviceForEpollLocked(Device* device) {
+ struct epoll_event eventItem;
+ memset(&eventItem, 0, sizeof(eventItem));
+ eventItem.events = EPOLLIN;
+ if (mUsingEpollWakeup) {
+ eventItem.events |= EPOLLWAKEUP;
+ }
+ eventItem.data.u32 = device->id;
+ if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, device->fd, &eventItem)) {
+ ALOGE("Could not add device fd to epoll instance. errno=%d", errno);
+ return -errno;
+ }
+ return OK;
+}
+
+status_t EventHub::unregisterDeviceFromEpollLocked(Device* device) {
+ if (device->hasValidFd()) {
+ if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, NULL)) {
+ ALOGW("Could not remove device fd from epoll instance. errno=%d", errno);
+ return -errno;
+ }
+ }
+ return OK;
+}
+
status_t EventHub::openDeviceLocked(const char *devicePath) {
+ return openDeviceLocked(devicePath, false);
+}
+
+status_t EventHub::openDeviceLocked(const char *devicePath, bool ignoreAlreadyOpened) {
char buffer[80];
+ if (ignoreAlreadyOpened && (getDeviceByPathLocked(devicePath) != 0)) {
+ ALOGV("Ignoring device '%s' that has already been opened.", devicePath);
+ return 0;
+ }
+
ALOGV("Opening device: %s", devicePath);
- int fd = open(devicePath, O_RDWR | O_CLOEXEC);
+ int fd = open(devicePath, O_RDWR | O_CLOEXEC | O_NONBLOCK);
if(fd < 0) {
ALOGE("could not open %s, %s\n", devicePath, strerror(errno));
return -1;
// Fill in the descriptor.
assignDescriptorLocked(identifier);
- // Make file descriptor non-blocking for use with poll().
- if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
- ALOGE("Error %d making device file descriptor non-blocking.", errno);
- close(fd);
- return -1;
- }
-
// Allocate device. (The device object takes ownership of the fd at this point.)
int32_t deviceId = mNextDeviceId++;
Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
&& test_bit(REL_X, device->relBitmask)
&& test_bit(REL_Y, device->relBitmask)) {
device->classes |= INPUT_DEVICE_CLASS_CURSOR;
+ // Is this an absolute x-y axis with relative wheel mouse device?
+ } else if (test_bit(BTN_MOUSE, device->keyBitmask)
+ && test_bit(ABS_X, device->absBitmask)
+ && test_bit(ABS_Y, device->absBitmask)
+ && test_bit(REL_WHEEL, device->relBitmask)) {
+ device->classes |= INPUT_DEVICE_CLASS_CURSOR;
}
// See if this is a rotary encoder type device.
device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT;
}
// Is this an old style single-touch driver?
- } else if (test_bit(BTN_TOUCH, device->keyBitmask)
+ } else if ((test_bit(BTN_TOUCH, device->keyBitmask) || test_bit(BTN_LEFT, device->keyBitmask))
&& test_bit(ABS_X, device->absBitmask)
- && test_bit(ABS_Y, device->absBitmask)) {
+ && test_bit(ABS_Y, device->absBitmask)
+ && !test_bit(REL_WHEEL, device->relBitmask)) {
device->classes |= INPUT_DEVICE_CLASS_TOUCH;
// Is this a BT stylus?
} else if ((test_bit(ABS_PRESSURE, device->absBitmask) ||
// 'Q' key support = cheap test of whether this is an alpha-capable kbd
if (hasKeycodeLocked(device, AKEYCODE_Q)) {
- device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY;
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.ignore_atkbd", value, "0");
+ if ((device->identifier.name != "AT Translated Set 2 keyboard") || (!atoi(value))) {
+ device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY;
+ }
}
// See if this device has a DPAD.
break;
}
}
-
- // Disable kernel key repeat since we handle it ourselves
- unsigned int repeatRate[] = {0,0};
- if (ioctl(fd, EVIOCSREP, repeatRate)) {
- ALOGW("Unable to disable kernel key repeat for %s: %s", devicePath, strerror(errno));
- }
}
// If the device isn't recognized as something we handle, don't monitor it.
if (device->classes & (INPUT_DEVICE_CLASS_JOYSTICK | INPUT_DEVICE_CLASS_DPAD)
&& device->classes & INPUT_DEVICE_CLASS_GAMEPAD) {
device->controllerNumber = getNextControllerNumberLocked(device);
- setLedForController(device);
+ setLedForControllerLocked(device);
}
- // Register with epoll.
- struct epoll_event eventItem;
- memset(&eventItem, 0, sizeof(eventItem));
- eventItem.events = EPOLLIN;
- if (mUsingEpollWakeup) {
- eventItem.events |= EPOLLWAKEUP;
- }
- eventItem.data.u32 = deviceId;
- if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
- ALOGE("Could not add device fd to epoll instance. errno=%d", errno);
+
+ if (registerDeviceForEpollLocked(device) != OK) {
delete device;
return -1;
}
+ configureFd(device);
+
+ ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
+ "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, ",
+ deviceId, fd, devicePath, device->identifier.name.string(),
+ device->classes,
+ device->configurationFile.string(),
+ device->keyMap.keyLayoutFile.string(),
+ device->keyMap.keyCharacterMapFile.string(),
+ toString(mBuiltInKeyboardId == deviceId));
+
+ addDeviceLocked(device);
+ return OK;
+}
+
+void EventHub::configureFd(Device* device) {
+ // Set fd parameters with ioctl, such as key repeat, suspend block, and clock type
+ if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) {
+ // Disable kernel key repeat since we handle it ourselves
+ unsigned int repeatRate[] = {0, 0};
+ if (ioctl(device->fd, EVIOCSREP, repeatRate)) {
+ ALOGW("Unable to disable kernel key repeat for %s: %s",
+ device->path.string(), strerror(errno));
+ }
+ }
+
String8 wakeMechanism("EPOLLWAKEUP");
if (!mUsingEpollWakeup) {
#ifndef EVIOCSSUSPENDBLOCK
// this feature, we need to be prepared to define the ioctl ourselves.
#define EVIOCSSUSPENDBLOCK _IOW('E', 0x91, int)
#endif
- if (ioctl(fd, EVIOCSSUSPENDBLOCK, 1)) {
+ if (ioctl(device->fd, EVIOCSSUSPENDBLOCK, 1)) {
wakeMechanism = "<none>";
} else {
wakeMechanism = "EVIOCSSUSPENDBLOCK";
}
}
-
// Tell the kernel that we want to use the monotonic clock for reporting timestamps
// associated with input events. This is important because the input system
// uses the timestamps extensively and assumes they were recorded using the monotonic
// clock.
- //
- // In older kernel, before Linux 3.4, there was no way to tell the kernel which
- // clock to use to input event timestamps. The standard kernel behavior was to
- // record a real time timestamp, which isn't what we want. Android kernels therefore
- // contained a patch to the evdev_event() function in drivers/input/evdev.c to
- // replace the call to do_gettimeofday() with ktime_get_ts() to cause the monotonic
- // clock to be used instead of the real time clock.
- //
- // As of Linux 3.4, there is a new EVIOCSCLOCKID ioctl to set the desired clock.
- // Therefore, we no longer require the Android-specific kernel patch described above
- // as long as we make sure to set select the monotonic clock. We do that here.
int clockId = CLOCK_MONOTONIC;
- bool usingClockIoctl = !ioctl(fd, EVIOCSCLOCKID, &clockId);
+ bool usingClockIoctl = !ioctl(device->fd, EVIOCSCLOCKID, &clockId);
+ ALOGI("wakeMechanism=%s, usingClockIoctl=%s", wakeMechanism.string(),
+ toString(usingClockIoctl));
+}
- ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
- "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, "
- "wakeMechanism=%s, usingClockIoctl=%s",
- deviceId, fd, devicePath, device->identifier.name.string(),
- device->classes,
- device->configurationFile.string(),
- device->keyMap.keyLayoutFile.string(),
- device->keyMap.keyCharacterMapFile.string(),
- toString(mBuiltInKeyboardId == deviceId),
- wakeMechanism.string(), toString(usingClockIoctl));
+bool EventHub::isDeviceEnabled(int32_t deviceId) {
+ AutoMutex _l(mLock);
+ Device* device = getDeviceLocked(deviceId);
+ if (device == NULL) {
+ ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
+ return false;
+ }
+ return device->enabled;
+}
- addDeviceLocked(device);
- return 0;
+status_t EventHub::enableDevice(int32_t deviceId) {
+ AutoMutex _l(mLock);
+ Device* device = getDeviceLocked(deviceId);
+ if (device == NULL) {
+ ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
+ return BAD_VALUE;
+ }
+ if (device->enabled) {
+ ALOGW("Duplicate call to %s, input device %" PRId32 " already enabled", __func__, deviceId);
+ return OK;
+ }
+ status_t result = device->enable();
+ if (result != OK) {
+ ALOGE("Failed to enable device %" PRId32, deviceId);
+ return result;
+ }
+
+ configureFd(device);
+
+ return registerDeviceForEpollLocked(device);
+}
+
+status_t EventHub::disableDevice(int32_t deviceId) {
+ AutoMutex _l(mLock);
+ Device* device = getDeviceLocked(deviceId);
+ if (device == NULL) {
+ ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
+ return BAD_VALUE;
+ }
+ if (!device->enabled) {
+ ALOGW("Duplicate call to %s, input device already disabled", __func__);
+ return OK;
+ }
+ unregisterDeviceFromEpollLocked(device);
+ return device->disable();
}
void EventHub::createVirtualKeyboardLocked() {
mControllerNumbers.clearBit(static_cast<uint32_t>(num - 1));
}
-void EventHub::setLedForController(Device* device) {
+void EventHub::setLedForControllerLocked(Device* device) {
for (int i = 0; i < MAX_CONTROLLER_LEDS; i++) {
setLedStateLocked(device, ALED_CONTROLLER_1 + i, device->controllerNumber == i + 1);
}
if (!device->keyMap.haveKeyLayout()) {
return false;
}
-
+
Vector<int32_t> scanCodes;
device->keyMap.keyLayoutMap->findScanCodesForKey(keycode, &scanCodes);
const size_t N = scanCodes.size();
return true;
}
}
-
+
return false;
}
mBuiltInKeyboardId = NO_BUILT_IN_KEYBOARD;
}
- if (!device->isVirtual()) {
- if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, NULL)) {
- ALOGW("Could not remove device fd from epoll instance. errno=%d", errno);
- }
- }
+ unregisterDeviceFromEpollLocked(device);
releaseControllerNumberLocked(device);
if(event->len) {
strcpy(filename, event->name);
if(event->mask & IN_CREATE) {
- openDeviceLocked(devname);
+ openDeviceLocked(devname, true);
} else {
ALOGI("Removing device '%s' due to inotify event\n", devname);
closeDeviceByPathLocked(devname);
}
dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes);
dump.appendFormat(INDENT3 "Path: %s\n", device->path.string());
+ dump.appendFormat(INDENT3 "Enabled: %s\n", toString(device->enabled));
dump.appendFormat(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.string());
dump.appendFormat(INDENT3 "Location: %s\n", device->identifier.location.string());
dump.appendFormat(INDENT3 "ControllerNumber: %d\n", device->controllerNumber);