// An all-in-one function for describing an input device static PyObject * ioctl_devinfo(PyObject *self, PyObject *args) { int fd; struct input_id iid; char name[MAX_NAME_SIZE]; char phys[MAX_NAME_SIZE] = {0}; char uniq[MAX_NAME_SIZE] = {0}; int ret = PyArg_ParseTuple(args, "i", &fd); if (!ret) return NULL; memset(&iid, 0, sizeof(iid)); if (ioctl(fd, EVIOCGID, &iid) < 0) goto on_err; if (ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0) goto on_err; // Some devices do not have a physical topology associated with them ioctl(fd, EVIOCGPHYS(sizeof(phys)), phys); // Some kernels have started reporting bluetooth controller MACs as phys. // This lets us get the real physical address. As with phys, it may be blank. ioctl(fd, EVIOCGUNIQ(sizeof(uniq)), uniq); return Py_BuildValue("hhhhsss", iid.bustype, iid.vendor, iid.product, iid.version, name, phys, uniq); on_err: PyErr_SetFromErrno(PyExc_IOError); return NULL; }
static int open_device(const char* device) { int version; int fd; struct pollfd* new_ufds; char** new_device_names; char name[80]; char location[80]; char idstr[80]; struct input_id id; fd = open(device, O_RDWR); if (fd < 0) { return -1; } if (ioctl(fd, EVIOCGVERSION, &version)) { return -1; } if (ioctl(fd, EVIOCGID, &id)) { return -1; } name[sizeof(name) - 1] = '\0'; location[sizeof(location) - 1] = '\0'; idstr[sizeof(idstr) - 1] = '\0'; if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) { name[0] = '\0'; } if (ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) { location[0] = '\0'; } if (ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) { idstr[0] = '\0'; } new_ufds = reinterpret_cast<pollfd*>(realloc(ufds, sizeof(ufds[0]) * (nfds + 1))); if (new_ufds == NULL) { fprintf(stderr, "out of memory\n"); return -1; } ufds = new_ufds; new_device_names = reinterpret_cast<char**>(realloc( device_names, sizeof(device_names[0]) * (nfds + 1))); if (new_device_names == NULL) { fprintf(stderr, "out of memory\n"); return -1; } device_names = new_device_names; ufds[nfds].fd = fd; ufds[nfds].events = POLLIN; device_names[nfds] = strdup(device); nfds++; return 0; }
int SC_LID::getInfo(struct input_id *info, char *bufPhys, size_t sizePhys, char *bufUniq, size_t sizeUniq) { if (ioctl(m_fd, EVIOCGID, info) == -1) { error("LID (6): %s\n", strerror(errno)); return errFailed; } if (ioctl(m_fd, EVIOCGPHYS(sizePhys), bufPhys) == -1) { // strcpy( sizePhys, strerror(errno)); post("LID could not retrieve physical location (error: %s)\n", strerror(errno)); sprintf(bufPhys, ""); // return errFailed; } if (ioctl(m_fd, EVIOCGUNIQ(sizeUniq), bufUniq) == -1) { // strcpy( strerror(errno), sizeof( strerror(errno)), sizeUniq ); post("LID could not get unique identifier (error: %s)\n", strerror(errno)); sprintf(bufUniq, ""); // return errFailed; } return errNone; }
int main(int argc,char* argv[]) { int fd; int read_num = 0, opt = 0; fprintf(stderr,"input device test v0.1\n"); fprintf(stderr,"This program was compiled at %s %s\n",__DATE__,__TIME__); fprintf(stderr,"Author: [email protected]\n"); while ((opt = getopt(argc, argv, "hr:")) != -1) { switch (opt) { case 'r': read_num = atoi(optarg); break; case 'h': default: usage(argv[0]); return 0; } } if (optind >= argc) { usage(argv[0]); return -1; } char devpath[256] = "\0"; if(argv[optind][0] != '/'){ strcpy(devpath,"/dev/input/"); } strcat(devpath,argv[optind]); printf("event driver: %s\n", devpath); // if((file = open(str, O_RDWR|O_NONBLOCK)) < 0) if((fd = open(devpath, O_RDWR)) < 0) { perror("device can not open"); return -2; } //Listing 1. Sample EVIOCGVERSION Function /* ioctl() accesses the underlying driver */ int version = 0; if (ioctl(fd, EVIOCGVERSION, &version)) { perror("EVIOCGVERSION"); } /* the EVIOCGVERSION ioctl() returns an int */ /* so we unpack it and display it */ printf("\tversion is %d.%d.%d\n", version >> 16, (version >> 8) & 0xff, version & 0xff); //Listing 3. Sample EVIOCGID ioctl /* suck out some device information */ struct input_id device_info; if(ioctl(fd, EVIOCGID, &device_info)) { perror("EVIOCGVERSION"); } /* the EVIOCGID ioctl() returns input_devinfo * structure - see <linux/input.h> * So we work through the various elements, * displaying each of them */ printf("\tvendor %04hx product %04hx version %04hx", device_info.vendor, device_info.product, device_info.version); switch ( device_info.bustype) { case BUS_PCI : printf(" is on a PCI bus\n"); break; case BUS_USB : printf(" is on a Universal Serial Bus\n"); break; case BUS_I2C : printf(" is on BUS_I2C\n"); break; default: printf(" is on an unknow bus %x\n",(unsigned int)device_info.bustype); break; } //Listing 4. get name char name[256]= "Unknown"; if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0) { perror("EVIOCGNAME"); } printf("\tname is %s\n", name); //Listing 5. Using EVIOCGPHYS for Topology Information char phys[256]= "\0"; if(ioctl(fd, EVIOCGPHYS(sizeof(phys)), phys) < 0) { //perror("EVIOCGPHYS "); } printf("\tphys is %s\n", phys); //Listing 6. Finding a Unique Identifier char uniq[256]= "\0"; if(ioctl(fd, EVIOCGUNIQ(sizeof(uniq)), uniq) < 0) { //perror("EVIOCGUNIQ"); } printf("\tidentity is %s\n", uniq); printf("\n"); //Listing 7. Determining Features with EVIOCGBIT unsigned char evtype_b[(EV_MAX >> 3) +1]; memset(evtype_b, 0, sizeof(evtype_b)); if (ioctl(fd, EVIOCGBIT(0, EV_MAX), evtype_b) < 0) { perror("EVIOCGBIT"); } printf("Supported event types %x:\n",evtype_b[0]); int yalv = 0; for (yalv = 0; yalv < EV_MAX; yalv++) { if (test_bit(yalv, evtype_b)) { /* the bit is set in the event types list */ printf(" Event type 0x%02x ", yalv); switch ( yalv) { case EV_SYN : printf(" (Synch Events)\n"); break; case EV_KEY : printf(" (Keys or Buttons)\n"); break; case EV_REL : printf(" (Relative Axes)\n"); break; case EV_ABS : printf(" (Absolute Axes)\n"); break; case EV_MSC : printf(" (Miscellaneous)\n"); break; case EV_LED : printf(" (LEDs)\n"); break; case EV_SND : printf(" (Sounds)\n"); break; case EV_REP : printf(" (Repeat)\n"); break; case EV_FF : case EV_FF_STATUS: printf(" (Force Feedback)\n"); break; case EV_PWR: printf(" (Power Management)\n"); break; default: printf(" (Unknown: 0x%04hx)\n", yalv); } } } //Listing 11. Using EVIOCGLED unsigned char led_b[64]; memset(led_b, 0, sizeof(led_b)); if(ioctl(fd, EVIOCGLED(sizeof(led_b)), led_b)<0){ perror("EVIOCGLED"); return -11; } for (yalv = 0; yalv < LED_MAX; yalv++) { if (test_bit(yalv, led_b)) { /* the bit is set in the LED state */ printf(" LED 0x%02x ", yalv); switch ( yalv) { case LED_NUML : printf(" (Num Lock)\n"); break; case LED_CAPSL : printf(" (Caps Lock)\n"); break; /* other LEDs not shown here*/ default: printf(" (Unknown LED: 0x%04hx)\n", yalv); } } } printf("\n"); //Listing 8. Checking for Busy Spots /* how many bytes were read */ size_t rb; /* the events (up to 64 at once) */ struct input_event ev[64]; while(read_num-- > 0){ rb=read(fd,ev,sizeof(struct input_event)*64); if (rb < (int) sizeof(struct input_event)) { perror("evtest: short read"); return -10; } for (yalv = 0; yalv < (int) (rb / sizeof(struct input_event)); yalv++) { printf("%ld.%06ld ",ev[yalv].time.tv_sec,ev[yalv].time.tv_usec); printf("type %d code %03d 0x%03x value %d\n", ev[yalv].type, ev[yalv].code,ev[yalv].code,ev[yalv].value); if (0 == ev[yalv].type) printf("\n"); } //printf("\n"); } close(fd); return 0; }
status_t EventHub::openDeviceLocked(const char *devicePath) { char buffer[80]; ALOGV("Opening device: %s", devicePath); int fd = open(devicePath, O_RDWR); if(fd < 0) { LOGE("could not open %s, %s\n", devicePath, strerror(errno)); return -1; } InputDeviceIdentifier identifier; // Get device name. if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) { //fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno)); } else { buffer[sizeof(buffer) - 1] = '\0'; identifier.name.setTo(buffer); } // Check to see if the device is on our excluded list for (size_t i = 0; i < mExcludedDevices.size(); i++) { const String8& item = mExcludedDevices.itemAt(i); if (identifier.name == item) { LOGI("ignoring event id %s driver %s\n", devicePath, item.string()); close(fd); return -1; } } // Get device driver version. int driverVersion; if(ioctl(fd, EVIOCGVERSION, &driverVersion)) { LOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno)); close(fd); return -1; } // Get device identifier. struct input_id inputId; if(ioctl(fd, EVIOCGID, &inputId)) { LOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno)); close(fd); return -1; } identifier.bus = inputId.bustype; identifier.product = inputId.product; identifier.vendor = inputId.vendor; identifier.version = inputId.version; // Get device physical location. if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) { //fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno)); } else { buffer[sizeof(buffer) - 1] = '\0'; identifier.location.setTo(buffer); } // Get device unique id. if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) { //fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno)); } else { buffer[sizeof(buffer) - 1] = '\0'; identifier.uniqueId.setTo(buffer); } // Make file descriptor non-blocking for use with poll(). if (fcntl(fd, F_SETFL, O_NONBLOCK)) { LOGE("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); #if 0 LOGI("add device %d: %s\n", deviceId, devicePath); LOGI(" bus: %04x\n" " vendor %04x\n" " product %04x\n" " version %04x\n", identifier.bus, identifier.vendor, identifier.product, identifier.version); LOGI(" name: \"%s\"\n", identifier.name.string()); LOGI(" location: \"%s\"\n", identifier.location.string()); LOGI(" unique id: \"%s\"\n", identifier.uniqueId.string()); LOGI(" driver: v%d.%d.%d\n", driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff); #endif // Load the configuration file for the device. loadConfigurationLocked(device); // Figure out the kinds of events the device reports. ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask); ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask); ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask); ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask); ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask); ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask); // See if this is a keyboard. Ignore everything in the button range except for // joystick and gamepad buttons which are handled like keyboards for the most part. bool haveKeyboardKeys = containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC)) || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(KEY_OK), sizeof_bit_array(KEY_MAX + 1)); bool haveGamepadButtons = containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC), sizeof_bit_array(BTN_MOUSE)) || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK), sizeof_bit_array(BTN_DIGI)); if (haveKeyboardKeys || haveGamepadButtons) { device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; } // See if this is a cursor device such as a trackball or mouse. if (test_bit(BTN_MOUSE, device->keyBitmask) && test_bit(REL_X, device->relBitmask) && test_bit(REL_Y, device->relBitmask)) { device->classes |= INPUT_DEVICE_CLASS_CURSOR; } // See if this is a touch pad. // Is this a new modern multi-touch driver? if (test_bit(ABS_MT_POSITION_X, device->absBitmask) && test_bit(ABS_MT_POSITION_Y, device->absBitmask)) { // Some joysticks such as the PS3 controller report axes that conflict // with the ABS_MT range. Try to confirm that the device really is // a touch screen. if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) { 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) && test_bit(ABS_X, device->absBitmask) && test_bit(ABS_Y, device->absBitmask)) { device->classes |= INPUT_DEVICE_CLASS_TOUCH; } // See if this device is a joystick. // Assumes that joysticks always have gamepad buttons in order to distinguish them // from other devices such as accelerometers that also have absolute axes. if (haveGamepadButtons) { uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK; for (int i = 0; i <= ABS_MAX; i++) { if (test_bit(i, device->absBitmask) && (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) { device->classes = assumedClasses; break; } } } // Check whether this device has switches. for (int i = 0; i <= SW_MAX; i++) { if (test_bit(i, device->swBitmask)) { device->classes |= INPUT_DEVICE_CLASS_SWITCH; break; } } // Configure virtual keys. if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) { // Load the virtual keys for the touch screen, if any. // We do this now so that we can make sure to load the keymap if necessary. status_t status = loadVirtualKeyMapLocked(device); if (!status) { device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; } } // Load the key map. // We need to do this for joysticks too because the key layout may specify axes. status_t keyMapStatus = NAME_NOT_FOUND; if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) { // Load the keymap for the device. keyMapStatus = loadKeyMapLocked(device); } // Configure the keyboard, gamepad or virtual keyboard. if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) { // Register the keyboard as a built-in keyboard if it is eligible. if (!keyMapStatus && mBuiltInKeyboardId == -1 && isEligibleBuiltInKeyboard(device->identifier, device->configuration, &device->keyMap)) { mBuiltInKeyboardId = device->id; } // 'Q' key support = cheap test of whether this is an alpha-capable kbd if (hasKeycodeLocked(device, AKEYCODE_Q)) { device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY; } // See if this device has a DPAD. if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) && hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) && hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) && hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) && hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) { device->classes |= INPUT_DEVICE_CLASS_DPAD; } // See if this device has a gamepad. for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) { if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) { device->classes |= INPUT_DEVICE_CLASS_GAMEPAD; break; } } } // If the device isn't recognized as something we handle, don't monitor it. if (device->classes == 0) { ALOGV("Dropping device: id=%d, path='%s', name='%s'", deviceId, devicePath, device->identifier.name.string()); delete device; return -1; } // Determine whether the device is external or internal. if (isExternalDeviceLocked(device)) { device->classes |= INPUT_DEVICE_CLASS_EXTERNAL; } // Register with epoll. struct epoll_event eventItem; memset(&eventItem, 0, sizeof(eventItem)); eventItem.events = EPOLLIN; eventItem.data.u32 = deviceId; if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) { LOGE("Could not add device fd to epoll instance. errno=%d", errno); delete device; return -1; } LOGI("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)); mDevices.add(deviceId, device); device->next = mOpeningDevices; mOpeningDevices = device; return 0; }
int main(void) { TEST_NULL_ARG(EVIOCGVERSION); TEST_NULL_ARG(EVIOCGEFFECTS); TEST_NULL_ARG(EVIOCGID); TEST_NULL_ARG(EVIOCGKEYCODE); TEST_NULL_ARG(EVIOCSKEYCODE); TEST_NULL_ARG(EVIOCSFF); # ifdef EVIOCGKEYCODE_V2 TEST_NULL_ARG(EVIOCGKEYCODE_V2); # endif # ifdef EVIOCSKEYCODE_V2 TEST_NULL_ARG(EVIOCSKEYCODE_V2); # endif # ifdef EVIOCGREP TEST_NULL_ARG(EVIOCGREP); # endif # ifdef EVIOCSREP TEST_NULL_ARG(EVIOCSREP); # endif # ifdef EVIOCSCLOCKID TEST_NULL_ARG(EVIOCSCLOCKID); # endif TEST_NULL_ARG(EVIOCGNAME(0)); TEST_NULL_ARG(EVIOCGPHYS(0)); TEST_NULL_ARG(EVIOCGUNIQ(0)); TEST_NULL_ARG(EVIOCGKEY(0)); TEST_NULL_ARG(EVIOCGLED(0)); # ifdef EVIOCGMTSLOTS TEST_NULL_ARG(EVIOCGMTSLOTS(0)); # endif # ifdef EVIOCGPROP TEST_NULL_ARG(EVIOCGPROP(0)); # endif TEST_NULL_ARG(EVIOCGSND(0)); # ifdef EVIOCGSW TEST_NULL_ARG(EVIOCGSW(0)); # endif TEST_NULL_ARG(EVIOCGABS(ABS_X)); TEST_NULL_ARG(EVIOCSABS(ABS_X)); TEST_NULL_ARG(EVIOCGBIT(EV_SYN, 0)); TEST_NULL_ARG(EVIOCGBIT(EV_KEY, 1)); TEST_NULL_ARG(EVIOCGBIT(EV_REL, 2)); TEST_NULL_ARG(EVIOCGBIT(EV_ABS, 3)); TEST_NULL_ARG(EVIOCGBIT(EV_MSC, 4)); # ifdef EV_SW TEST_NULL_ARG(EVIOCGBIT(EV_SW, 5)); # endif TEST_NULL_ARG(EVIOCGBIT(EV_LED, 6)); TEST_NULL_ARG(EVIOCGBIT(EV_SND, 7)); TEST_NULL_ARG(EVIOCGBIT(EV_REP, 8)); TEST_NULL_ARG(EVIOCGBIT(EV_FF, 9)); TEST_NULL_ARG(EVIOCGBIT(EV_PWR, 10)); TEST_NULL_ARG(EVIOCGBIT(EV_FF_STATUS, 11)); ioctl(-1, EVIOCGBIT(EV_MAX, 42), 0); printf("ioctl(-1, EVIOCGBIT(%#x /* EV_??? */, 42), NULL)" " = -1 EBADF (%m)\n", EV_MAX); ioctl(-1, EVIOCRMFF, lmagic); printf("ioctl(-1, EVIOCRMFF, %d) = -1 EBADF (%m)\n", (int) lmagic); ioctl(-1, EVIOCGRAB, lmagic); printf("ioctl(-1, EVIOCGRAB, %lu) = -1 EBADF (%m)\n", lmagic); # ifdef EVIOCREVOKE ioctl(-1, EVIOCREVOKE, lmagic); printf("ioctl(-1, EVIOCREVOKE, %lu) = -1 EBADF (%m)\n", lmagic); # endif const unsigned int size = get_page_size(); void *const page = tail_alloc(size); fill_memory(page, size); int *const val_int = tail_alloc(sizeof(*val_int)); *val_int = magic; # ifdef EVIOCSCLOCKID ioctl(-1, EVIOCSCLOCKID, val_int); printf("ioctl(-1, EVIOCSCLOCKID, [%u]) = -1 EBADF (%m)\n", *val_int); # endif int *pair_int = tail_alloc(sizeof(*pair_int) * 2); pair_int[0] = 0xdeadbeef; pair_int[1] = 0xbadc0ded; # ifdef EVIOSGREP ioctl(-1, EVIOCSREP, pair_int); printf("ioctl(-1, EVIOCSREP, [%u, %u]) = -1 EBADF (%m)\n", pair_int[0], pair_int[1]); # endif pair_int[1] = 1; ioctl(-1, EVIOCSKEYCODE, pair_int); printf("ioctl(-1, EVIOCSKEYCODE, [%u, %s]) = -1 EBADF (%m)\n", pair_int[0], "KEY_ESC"); # ifdef EVIOCSKEYCODE_V2 struct input_keymap_entry *const ike = tail_alloc(sizeof(*ike)); fill_memory(ike, sizeof(*ike)); ike->keycode = 2; ioctl(-1, EVIOCSKEYCODE_V2, ike); printf("ioctl(-1, EVIOCSKEYCODE_V2, {flags=%" PRIu8 ", len=%" PRIu8 ", ", ike->flags, ike->len); # if VERBOSE printf("index=%" PRIu16 ", keycode=%s, scancode=[", ike->index, "KEY_1"); unsigned int i; for (i = 0; i < ARRAY_SIZE(ike->scancode); ++i) { if (i > 0) printf(", "); printf("%" PRIx8, ike->scancode[i]); } printf("]"); # else printf("..."); # endif errno = EBADF; printf("}) = -1 EBADF (%m)\n"); # endif struct ff_effect *const ffe = tail_alloc(sizeof(*ffe)); fill_memory(ffe, sizeof(*ffe)); ffe->type = FF_CONSTANT; ioctl(-1, EVIOCSFF, ffe); print_ffe_common(ffe, "FF_CONSTANT"); # if VERBOSE printf(", constant={level=%hd", ffe->u.constant.level); print_envelope(&ffe->u.constant.envelope); printf("}"); # else printf("..."); # endif errno = EBADF; printf("}) = -1 EBADF (%m)\n"); # if VERBOSE ffe->type = FF_RAMP; ioctl(-1, EVIOCSFF, ffe); print_ffe_common(ffe, "FF_RAMP"); printf(", ramp={start_level=%hd, end_level=%hd", ffe->u.ramp.start_level, ffe->u.ramp.end_level); print_envelope(&ffe->u.ramp.envelope); errno = EBADF; printf("}}) = -1 EBADF (%m)\n"); ffe->type = FF_PERIODIC; ioctl(-1, EVIOCSFF, ffe); print_ffe_common(ffe, "FF_PERIODIC"); printf(", periodic={waveform=%hu, period=%hu, magnitude=%hd" ", offset=%hd, phase=%hu", ffe->u.periodic.waveform, ffe->u.periodic.period, ffe->u.periodic.magnitude, ffe->u.periodic.offset, ffe->u.periodic.phase); print_envelope(&ffe->u.periodic.envelope); printf(", custom_len=%u, custom_data=%p}", ffe->u.periodic.custom_len, ffe->u.periodic.custom_data); errno = EBADF; printf("}) = -1 EBADF (%m)\n"); ffe->type = FF_RUMBLE; ioctl(-1, EVIOCSFF, ffe); print_ffe_common(ffe, "FF_RUMBLE"); printf(", rumble={strong_magnitude=%hu, weak_magnitude=%hu}", ffe->u.rumble.strong_magnitude, ffe->u.rumble.weak_magnitude); errno = EBADF; printf("}) = -1 EBADF (%m)\n"); ffe->type = 0xff; ioctl(-1, EVIOCSFF, ffe); print_ffe_common(ffe, "0xff /* FF_??? */"); errno = EBADF; printf("}) = -1 EBADF (%m)\n"); # endif ioctl(-1, _IOC(_IOC_READ, 0x45, 0x1, 0xff), lmagic); printf("ioctl(-1, %s, %#lx) = -1 EBADF (%m)\n", "_IOC(_IOC_READ, 0x45, 0x1, 0xff)", lmagic); ioctl(-1, _IOC(_IOC_WRITE, 0x45, 0x1, 0xff), lmagic); printf("ioctl(-1, %s, %#lx) = -1 EBADF (%m)\n", "_IOC(_IOC_WRITE, 0x45, 0x1, 0xff)", lmagic); ioctl(-1, _IOC(_IOC_READ|_IOC_WRITE, 0x45, 0xfe, 0xff), lmagic); printf("ioctl(-1, %s, %#lx) = -1 EBADF (%m)\n", "_IOC(_IOC_READ|_IOC_WRITE, 0x45, 0xfe, 0xff)", lmagic); ioctl(-1, _IOC(_IOC_READ|_IOC_WRITE, 0x45, 0, 0), lmagic); printf("ioctl(-1, %s, %#lx) = -1 EBADF (%m)\n", "_IOC(_IOC_READ|_IOC_WRITE, 0x45, 0, 0)", lmagic); puts("+++ exited with 0 +++"); return 0; }
static struct orng_device_info * read_devinfo(struct orng_device_info *devinfo, int with_scancodes, int fd) { int i; char buf[1024]; __u32 sc; __u16 j; int res = 0; __u32 nsc; memset(devinfo, 0, sizeof(*devinfo)); /* device identifier */ if (ioctl(fd, EVIOCGID, &devinfo->id) < 0) { fprintf(stderr, "ioctl(EVIOCGID): %s\n", strerror(errno)); goto err_ioctl; } /* event bits */ if (ioctl(fd, EVIOCGBIT(0, sizeof(devinfo->evbit)), devinfo->evbit) < 0) { fprintf(stderr, "ioctl(EVIOCGBIT(0)): %s\n", strerror(errno)); goto err_ioctl; } /* keys */ if (TEST_ARRAY_BIT(devinfo->evbit, EV_KEY)) { if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(devinfo->keybit)), devinfo->keybit) < 0) { fprintf(stderr, "ioctl(EVIOCGBIT(EV_KEY)): %s\n", strerror(errno)); goto err_ioctl; } /* key state */ if (TEST_ARRAY_BIT(devinfo->evbit, EV_KEY)) { if (ioctl(fd, EVIOCGKEY(sizeof(devinfo->key)), devinfo->key) < 0) { fprintf(stderr, "ioctl(EVIOCGKEY(%zu)): %s\n", sizeof(buf), strerror(errno)); goto err_ioctl; } } /* read mapping between scan codes and key codes */ if (with_scancodes) { nsc = 1ul<<((CHAR_BIT*sizeof(devinfo->keymap[0][0]))-1); for (sc = 0, j = 0; sc < nsc; ++sc) { int map[2] = {sc, 0}; int res = ioctl(fd, EVIOCGKEYCODE, map); if (res < 0) { if (errno != EINVAL) { fprintf(stderr, "ioctl: %s\n", strerror(errno)); goto err_ioctl; } } else { /* save mapping */ devinfo->keymap[j][0] = map[0]; /* scan code */ devinfo->keymap[j][1] = map[1]; /* key code */ ++j; if (j >= sizeof(devinfo->keymap)/sizeof(devinfo->keymap[0])) { break; } } } } } /* relative positioning */ if (TEST_ARRAY_BIT(devinfo->evbit, EV_REL)) { if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(devinfo->relbit)), devinfo->relbit) < 0) { fprintf(stderr, "ioctl(EVIOCGBIT(EV_REL)): %s\n", strerror(errno)); goto err_ioctl; } } /* absolute positioning */ if (TEST_ARRAY_BIT(devinfo->evbit, EV_ABS)) { if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(devinfo->absbit)), devinfo->absbit) < 0) { fprintf(stderr, "ioctl(EVIOCGBIT(EV_ABS)): %s\n", strerror(errno)); goto err_ioctl; } /* limits */ for (i = 0; i <= ABS_MAX; ++i) { if (TEST_ARRAY_BIT(devinfo->absbit, i)) { if (ioctl(fd, EVIOCGABS(i), devinfo->absinfo+i) < 0) { fprintf(stderr, "ioctl(EVIOCGABS(%d)): %s\n", i, strerror(errno)); goto err_ioctl; } } } } /* misc */ if (TEST_ARRAY_BIT(devinfo->evbit, EV_MSC)) { if (ioctl(fd, EVIOCGBIT(EV_MSC, sizeof(devinfo->mscbit)), devinfo->mscbit) < 0) { fprintf(stderr, "ioctl(EVIOCGBIT(EV_MSC)): %s\n", strerror(errno)); goto err_ioctl; } } /* LEDs */ if (TEST_ARRAY_BIT(devinfo->evbit, EV_LED)) { if (ioctl(fd, EVIOCGBIT(EV_LED, sizeof(devinfo->ledbit)), devinfo->ledbit) < 0) { fprintf(stderr, "ioctl(EVIOCGBIT(EV_LED)): %s\n", strerror(errno)); goto err_ioctl; } /* LED state */ if (TEST_ARRAY_BIT(devinfo->evbit, EV_LED)) { if (ioctl(fd, EVIOCGLED(sizeof(devinfo->led)), devinfo->led) < 0) { fprintf(stderr, "ioctl(EVIOCGLED(%zu)): %s\n", sizeof(buf), strerror(errno)); goto err_ioctl; } } } /* sound */ if (TEST_ARRAY_BIT(devinfo->evbit, EV_SND)) { if (ioctl(fd, EVIOCGBIT(EV_SND, sizeof(devinfo->sndbit)), devinfo->sndbit) < 0) { fprintf(stderr, "ioctl(EVIOCGBIT(EV_SND)): %s\n", strerror(errno)); goto err_ioctl; } /* sound state */ if (TEST_ARRAY_BIT(devinfo->evbit, EV_SW)) { if (ioctl(fd, EVIOCGSND(sizeof(devinfo->snd)), devinfo->snd) < 0) { fprintf(stderr, "ioctl(EVIOCGSND(%zu)): %s\n", sizeof(buf), strerror(errno)); goto err_ioctl; } } } /* force feedback */ if (TEST_ARRAY_BIT(devinfo->evbit, EV_FF)) { if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(devinfo->ffbit)), devinfo->ffbit) < 0) { fprintf(stderr, "ioctl(EVIOCGBIT(EV_FF)): %s\n", strerror(errno)); goto err_ioctl; } } /* switches */ if (TEST_ARRAY_BIT(devinfo->evbit, EV_SW)) { if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(devinfo->swbit)), devinfo->swbit) < 0) { fprintf(stderr, "ioctl(EVIOCGBIT(EV_SW)): %s\n", strerror(errno)); goto err_ioctl; } /* switch state */ if (TEST_ARRAY_BIT(devinfo->evbit, EV_SW)) { if (ioctl(fd, EVIOCGSW(sizeof(devinfo->sw)), devinfo->sw) < 0) { fprintf(stderr, "ioctl(EVIOCGSW(%zu)): %s\n", sizeof(buf), strerror(errno)); goto err_ioctl; } } } /* auto repeat */ if (TEST_ARRAY_BIT(devinfo->evbit, EV_REP)) { if (ioctl(fd, EVIOCGREP, devinfo->rep) < 0) { fprintf(stderr, "ioctl(EVIOCGREP): %s\n", strerror(errno)); goto err_ioctl; } } /* name */ memset(buf, 0, sizeof(buf)); do { res = ioctl(fd, EVIOCGNAME(sizeof(buf)), buf); } while ((res < 0) && (errno == EINTR)); if (res >= 0) { devinfo->name = strndup(buf, sizeof(buf)-1); if (!devinfo->name) { fprintf(stderr, "strdup: %s\n", strerror(errno)); goto err_strdup_name; } } else if (errno != ENOENT) { fprintf(stderr, "ioctl(EVIOCGPHYS(%lu)): %s\n", (unsigned long)sizeof(buf), strerror(errno)); goto err_ioctl; } /* physical location */ memset(buf, 0, sizeof(buf)); do { res = ioctl(fd, EVIOCGPHYS(sizeof(buf)), buf); } while ((res < 0) && (errno == EINTR)); if (res >= 0) { devinfo->phys = strndup(buf, sizeof(buf)-1); if (!devinfo->phys) { fprintf(stderr, "strdup: %s\n", strerror(errno)); goto err_strdup_phys; } } else if (errno != ENOENT) { fprintf(stderr, "ioctl(EVIOCGPHYS(%lu)): %s\n", (unsigned long)sizeof(buf), strerror(errno)); goto err_ioctl; } /* unique identifier */ memset(buf, 0, sizeof(buf)); do { res = ioctl(fd, EVIOCGUNIQ(sizeof(buf)), buf); } while ((res < 0) && (errno == EINTR)); if (res >= 0) { devinfo->uniq = strndup(buf, sizeof(buf)-1); if (!devinfo->uniq) { fprintf(stderr, "strdup: %s\n", strerror(errno)); goto err_strdup_uniq; } } else if (errno != ENOENT) { fprintf(stderr, "ioctl(EVIOCGUNIQ(%lu)): %s\n", (unsigned long)sizeof(buf), strerror(errno)); goto err_ioctl; } return devinfo; err_strdup_uniq: free(devinfo->phys); err_strdup_phys: err_ioctl_gphys: free(devinfo->name); err_strdup_name: err_ioctl: return NULL; }
int EventHub::open_device(const char *deviceName) { int version; int fd; struct pollfd *new_mFDs; device_t **new_devices; char **new_device_names; char name[80]; char location[80]; char idstr[80]; struct input_id id; LOGV("Opening device: %s", deviceName); AutoMutex _l(mLock); fd = open(deviceName, O_RDWR); if(fd < 0) { LOGE("could not open %s, %s\n", deviceName, strerror(errno)); return -1; } if(ioctl(fd, EVIOCGVERSION, &version)) { LOGE("could not get driver version for %s, %s\n", deviceName, strerror(errno)); return -1; } if(ioctl(fd, EVIOCGID, &id)) { LOGE("could not get driver id for %s, %s\n", deviceName, strerror(errno)); return -1; } name[sizeof(name) - 1] = '\0'; location[sizeof(location) - 1] = '\0'; idstr[sizeof(idstr) - 1] = '\0'; if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) { //fprintf(stderr, "could not get device name for %s, %s\n", deviceName, strerror(errno)); name[0] = '\0'; } // check to see if the device is on our excluded list List<String8>::iterator iter = mExcludedDevices.begin(); List<String8>::iterator end = mExcludedDevices.end(); for ( ; iter != end; iter++) { const char* test = *iter; if (strcmp(name, test) == 0) { LOGI("ignoring event id %s driver %s\n", deviceName, test); close(fd); return -1; } } if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) { //fprintf(stderr, "could not get location for %s, %s\n", deviceName, strerror(errno)); location[0] = '\0'; } if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) { //fprintf(stderr, "could not get idstring for %s, %s\n", deviceName, strerror(errno)); idstr[0] = '\0'; } int devid = 0; while (devid < mNumDevicesById) { if (mDevicesById[devid].device == NULL) { break; } devid++; } if (devid >= mNumDevicesById) { device_ent* new_devids = (device_ent*)realloc(mDevicesById, sizeof(mDevicesById[0]) * (devid + 1)); if (new_devids == NULL) { LOGE("out of memory"); return -1; } mDevicesById = new_devids; mNumDevicesById = devid+1; mDevicesById[devid].device = NULL; mDevicesById[devid].seq = 0; } mDevicesById[devid].seq = (mDevicesById[devid].seq+(1<<SEQ_SHIFT))&SEQ_MASK; if (mDevicesById[devid].seq == 0) { mDevicesById[devid].seq = 1<<SEQ_SHIFT; } new_mFDs = (pollfd*)realloc(mFDs, sizeof(mFDs[0]) * (mFDCount + 1)); new_devices = (device_t**)realloc(mDevices, sizeof(mDevices[0]) * (mFDCount + 1)); if (new_mFDs == NULL || new_devices == NULL) { LOGE("out of memory"); return -1; } mFDs = new_mFDs; mDevices = new_devices; #if 0 LOGI("add device %d: %s\n", mFDCount, deviceName); LOGI(" bus: %04x\n" " vendor %04x\n" " product %04x\n" " version %04x\n", id.bustype, id.vendor, id.product, id.version); LOGI(" name: \"%s\"\n", name); LOGI(" location: \"%s\"\n" " id: \"%s\"\n", location, idstr); LOGI(" version: %d.%d.%d\n", version >> 16, (version >> 8) & 0xff, version & 0xff); #endif device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName, name); if (device == NULL) { LOGE("out of memory"); return -1; } mFDs[mFDCount].fd = fd; mFDs[mFDCount].events = POLLIN; // figure out the kinds of events the device reports // See if this is a keyboard, and classify it. Note that we only // consider up through the function keys; we don't want to include // ones after that (play cd etc) so we don't mistakenly consider a // controller to be a keyboard. uint8_t key_bitmask[(KEY_MAX+7)/8]; memset(key_bitmask, 0, sizeof(key_bitmask)); LOGV("Getting keys..."); if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) { //LOGI("MAP\n"); //for (int i=0; i<((KEY_MAX+7)/8); i++) { // LOGI("%d: 0x%02x\n", i, key_bitmask[i]); //} for (int i=0; i<((BTN_MISC+7)/8); i++) { if (key_bitmask[i] != 0) { device->classes |= CLASS_KEYBOARD; break; } } if ((device->classes & CLASS_KEYBOARD) != 0) { device->keyBitmask = new uint8_t[sizeof(key_bitmask)]; if (device->keyBitmask != NULL) { memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask)); } else { delete device; LOGE("out of memory allocating key bitmask"); return -1; } } } // See if this is a trackball. if (test_bit(BTN_MOUSE, key_bitmask)) { uint8_t rel_bitmask[(REL_MAX+7)/8]; memset(rel_bitmask, 0, sizeof(rel_bitmask)); LOGV("Getting relative controllers..."); if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0) { if (test_bit(REL_X, rel_bitmask) && test_bit(REL_Y, rel_bitmask)) { if (test_bit(BTN_LEFT, key_bitmask) && test_bit(BTN_RIGHT, key_bitmask)) device->classes |= CLASS_MOUSE; else device->classes |= CLASS_TRACKBALL; } } } uint8_t abs_bitmask[(ABS_MAX+7)/8]; memset(abs_bitmask, 0, sizeof(abs_bitmask)); LOGV("Getting absolute controllers..."); ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask); // Is this a new modern multi-touch driver? if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask) && test_bit(ABS_MT_POSITION_X, abs_bitmask) && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) { device->classes |= CLASS_TOUCHSCREEN | CLASS_TOUCHSCREEN_MT; // Is this an old style single-touch driver? } else if (test_bit(BTN_TOUCH, key_bitmask) && test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) { device->classes |= CLASS_TOUCHSCREEN; #ifdef HAVE_TSLIB mTS->fd = fd; //Configure here LOGV("Device name = %s, fd = %d", deviceName,fd); LOGV("tslib: calling ts_config from eventhub\n"); if(ts_config(mTS)) { LOGE("Error in Configuring tslib. Device Name = %s \n", deviceName); } #endif } #ifdef EV_SW // figure out the switches this device reports uint8_t sw_bitmask[(SW_MAX+7)/8]; memset(sw_bitmask, 0, sizeof(sw_bitmask)); if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask) >= 0) { for (int i=0; i<EV_SW; i++) { //LOGI("Device 0x%x sw %d: has=%d", device->id, i, test_bit(i, sw_bitmask)); if (test_bit(i, sw_bitmask)) { if (mSwitches[i] == 0) { mSwitches[i] = device->id; } } } } #endif if ((device->classes&CLASS_KEYBOARD) != 0) { char tmpfn[sizeof(name)]; char keylayoutFilename[300]; // a more descriptive name device->name = name; // replace all the spaces with underscores strcpy(tmpfn, name); for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' ')) *p = '_'; // find the .kl file we need for this device const char* root = getenv("ANDROID_ROOT"); snprintf(keylayoutFilename, sizeof(keylayoutFilename), "%s/usr/keylayout/%s.kl", root, tmpfn); bool defaultKeymap = false; if (access(keylayoutFilename, R_OK)) { snprintf(keylayoutFilename, sizeof(keylayoutFilename), "%s/usr/keylayout/%s", root, "qwerty.kl"); defaultKeymap = true; } device->layoutMap->load(keylayoutFilename); // tell the world about the devname (the descriptive name) if (!mHaveFirstKeyboard && !defaultKeymap && strstr(name, "-keypad")) { // the built-in keyboard has a well-known device ID of 0, // this device better not go away. mHaveFirstKeyboard = true; mFirstKeyboardId = device->id; property_set("hw.keyboards.0.devname", name); } else { // ensure mFirstKeyboardId is set to -something-. if (mFirstKeyboardId == 0) { mFirstKeyboardId = device->id; } } char propName[100]; sprintf(propName, "hw.keyboards.%u.devname", device->id); property_set(propName, name); // 'Q' key support = cheap test of whether this is an alpha-capable kbd if (hasKeycode(device, kKeyCodeQ)) { device->classes |= CLASS_ALPHAKEY; } // See if this has a DPAD. if (hasKeycode(device, kKeyCodeDpadUp) && hasKeycode(device, kKeyCodeDpadDown) && hasKeycode(device, kKeyCodeDpadLeft) && hasKeycode(device, kKeyCodeDpadRight) && hasKeycode(device, kKeyCodeDpadCenter)) { device->classes |= CLASS_DPAD; } LOGI("New keyboard: device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n", device->id, name, propName, keylayoutFilename); } // If the device isn't recognized as something we handle, don't monitor it. if (device->classes == 0) { LOGV("Dropping device %s %p, id = %d\n", deviceName, device, devid); close(fd); delete device; return -1; } LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n", deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes); LOGV("Adding device %s %p at %d, id = %d, classes = 0x%x\n", deviceName, device, mFDCount, devid, device->classes); mDevicesById[devid].device = device; device->next = mOpeningDevices; mOpeningDevices = device; mDevices[mFDCount] = device; mFDCount++; return 0; }
static void input_sanitise(const struct ioctl_group *grp, int childno) { unsigned int u, r; pick_random_ioctl(grp, childno); switch (shm->syscall[childno].a2) { case EVIOCGNAME(0): u = rand(); shm->syscall[childno].a2 = EVIOCGNAME(u); break; case EVIOCGPHYS(0): u = rand(); shm->syscall[childno].a2 = EVIOCGPHYS(u); break; case EVIOCGUNIQ(0): u = rand(); shm->syscall[childno].a2 = EVIOCGUNIQ(u); break; #ifdef EVIOCGPROP case EVIOCGPROP(0): u = rand(); shm->syscall[childno].a2 = EVIOCGPROP(u); break; #endif #ifdef EVIOCGMTSLOTS case EVIOCGMTSLOTS(0): u = rand(); shm->syscall[childno].a2 = EVIOCGMTSLOTS(u); break; #endif case EVIOCGKEY(0): u = rand(); shm->syscall[childno].a2 = EVIOCGKEY(u); break; case EVIOCGLED(0): u = rand(); shm->syscall[childno].a2 = EVIOCGLED(u); break; case EVIOCGSND(0): u = rand(); shm->syscall[childno].a2 = EVIOCGSND(u); break; case EVIOCGSW(0): u = rand(); shm->syscall[childno].a2 = EVIOCGSW(u); break; case EVIOCGBIT(0,0): u = rand(); r = rand(); if (u % 10) u %= EV_CNT; if (r % 10) r /= 4; shm->syscall[childno].a2 = EVIOCGBIT(u, r); break; case EVIOCGABS(0): u = rand(); if (u % 10) u %= ABS_CNT; shm->syscall[childno].a2 = EVIOCGABS(u); break; case EVIOCSABS(0): u = rand(); if (u % 10) u %= ABS_CNT; shm->syscall[childno].a2 = EVIOCSABS(u); break; default: break; } }
static const struct ioctl input_ioctls[] = { IOCTL(EVIOCGVERSION), IOCTL(EVIOCGID), IOCTL(EVIOCGREP), IOCTL(EVIOCSREP), IOCTL(EVIOCGKEYCODE), #ifdef EVIOCGKEYCODE_V2 IOCTL(EVIOCGKEYCODE_V2), #endif IOCTL(EVIOCSKEYCODE), #ifdef EVIOCSKEYCODE_V2 IOCTL(EVIOCSKEYCODE_V2), #endif IOCTL(EVIOCGNAME(0)), IOCTL(EVIOCGPHYS(0)), IOCTL(EVIOCGUNIQ(0)), #ifdef EVIOCGPROP IOCTL(EVIOCGPROP(0)), #endif #ifdef EVIOCGMTSLOTS IOCTL(EVIOCGMTSLOTS(0)), #endif IOCTL(EVIOCGKEY(0)), IOCTL(EVIOCGLED(0)), IOCTL(EVIOCGSND(0)), IOCTL(EVIOCGSW(0)), IOCTL(EVIOCGBIT(0,0)), IOCTL(EVIOCGABS(0)), IOCTL(EVIOCSABS(0)), IOCTL(EVIOCSFF), IOCTL(EVIOCRMFF),
/* * It so happens that the pointer that gives us the trouble * is the last field in the structure. Since we don't support * custom waveforms in uinput anyway we can just copy the whole * thing (to the compat size) and ignore the pointer. */ memcpy(&ff_up_compat.effect, &ff_up->effect, sizeof(struct ff_effect_compat)); memcpy(&ff_up_compat.old, &ff_up->old, sizeof(struct ff_effect_compat)); if (copy_to_user(buffer, &ff_up_compat, sizeof(struct uinput_ff_upload_compat))) return -EFAULT; } else { if (copy_to_user(buffer, ff_up, sizeof(struct uinput_ff_upload))) return -EFAULT; } return 0; } static int uinput_ff_upload_from_user(const char __user *buffer, struct uinput_ff_upload *ff_up) { if (INPUT_COMPAT_TEST) { struct uinput_ff_upload_compat ff_up_compat; if (copy_from_user(&ff_up_compat, buffer, sizeof(struct uinput_ff_upload_compat))) return -EFAULT; ff_up->request_id = ff_up_compat.request_id; ff_up->retval = ff_up_compat.retval; memcpy(&ff_up->effect, &ff_up_compat.effect, sizeof(struct ff_effect_compat)); memcpy(&ff_up->old, &ff_up_compat.old, sizeof(struct ff_effect_compat)); } else { if (copy_from_user(ff_up, buffer, sizeof(struct uinput_ff_upload))) return -EFAULT; } return 0; } #else static int uinput_ff_upload_to_user(char __user *buffer, const struct uinput_ff_upload *ff_up) { if (copy_to_user(buffer, ff_up, sizeof(struct uinput_ff_upload))) return -EFAULT; return 0; } static int uinput_ff_upload_from_user(const char __user *buffer, struct uinput_ff_upload *ff_up) { if (copy_from_user(ff_up, buffer, sizeof(struct uinput_ff_upload))) return -EFAULT; return 0; } #endif #define uinput_set_bit(_arg, _bit, _max) \ ({ \ int __ret = 0; \ if (udev->state == UIST_CREATED) \ __ret = -EINVAL; \ else if ((_arg) > (_max)) \ __ret = -EINVAL; \ else set_bit((_arg), udev->dev->_bit); \ __ret; \ }) #ifdef CONFIG_FEATURE_PANTECH_MDS_MTC //|| defined(FEATURE_PANTECH_STABILITY) #ifdef CONFIG_COMPAT #define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8) #define BITS_TO_LONGS_COMPAT(x) ((((x) - 1) / BITS_PER_LONG_COMPAT) + 1) #ifdef __BIG_ENDIAN static int bits_to_user(unsigned long *bits, unsigned int maxbit, unsigned int maxlen, void __user *p, int compat) { int len, i; if (compat) { len = BITS_TO_LONGS_COMPAT(maxbit) * sizeof(compat_long_t); if (len > maxlen) len = maxlen; for (i = 0; i < len / sizeof(compat_long_t); i++) if (copy_to_user((compat_long_t __user *) p + i, (compat_long_t *) bits + i + 1 - ((i % 2) << 1), sizeof(compat_long_t))) return -EFAULT; } else { len = BITS_TO_LONGS(maxbit) * sizeof(long); if (len > maxlen) len = maxlen; if (copy_to_user(p, bits, len)) return -EFAULT; } return len; } #else static int bits_to_user(unsigned long *bits, unsigned int maxbit, unsigned int maxlen, void __user *p, int compat) { int len = compat ? BITS_TO_LONGS_COMPAT(maxbit) * sizeof(compat_long_t) : BITS_TO_LONGS(maxbit) * sizeof(long); if (len > maxlen) len = maxlen; return copy_to_user(p, bits, len) ? -EFAULT : len; } #endif /* __BIG_ENDIAN */ #else static int bits_to_user(unsigned long *bits, unsigned int maxbit, unsigned int maxlen, void __user *p, int compat) { int len = BITS_TO_LONGS(maxbit) * sizeof(long); if (len > maxlen) len = maxlen; return copy_to_user(p, bits, len) ? -EFAULT : len; } #endif /* CONFIG_COMPAT */ static int str_to_user(const char *str, unsigned int maxlen, void __user *p) { int len; if (!str) return -ENOENT; len = strlen(str) + 1; if (len > maxlen) len = maxlen; return copy_to_user(p, str, len) ? -EFAULT : len; } #define OLD_KEY_MAX 0x1ff static int handle_eviocgbit(struct input_dev *dev, unsigned int cmd, void __user *p, int compat_mode) { unsigned long *bits; int len; switch (_IOC_NR(cmd) & EV_MAX) { case 0: bits = dev->evbit; len = EV_MAX; break; case EV_KEY: bits = dev->keybit; len = KEY_MAX; break; case EV_REL: bits = dev->relbit; len = REL_MAX; break; case EV_ABS: bits = dev->absbit; len = ABS_MAX; break; case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break; case EV_LED: bits = dev->ledbit; len = LED_MAX; break; case EV_SND: bits = dev->sndbit; len = SND_MAX; break; case EV_FF: bits = dev->ffbit; len = FF_MAX; break; case EV_SW: bits = dev->swbit; len = SW_MAX; break; default: return -EINVAL; } if ((_IOC_NR(cmd) & EV_MAX) == EV_KEY && _IOC_SIZE(cmd) == OLD_KEY_MAX) { len = OLD_KEY_MAX; } return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode); } #undef OLD_KEY_MAX #endif/*CONFIG_FEATURE_PANTECH_MDS_MTC || FEATURE_PANTECH_STABILITY*/ static long uinput_ioctl_handler(struct file *file, unsigned int cmd, unsigned long arg, void __user *p) { int retval; struct uinput_device *udev = file->private_data; struct uinput_ff_upload ff_up; struct uinput_ff_erase ff_erase; struct uinput_request *req; char *phys; retval = mutex_lock_interruptible(&udev->mutex); if (retval) return retval; if (!udev->dev) { retval = uinput_allocate_device(udev); if (retval) goto out; } switch (cmd) { case UI_DEV_CREATE: retval = uinput_create_device(udev); break; case UI_DEV_DESTROY: uinput_destroy_device(udev); break; #ifdef CONFIG_FEATURE_PANTECH_MDS_MTC //|| defined(FEATURE_PANTECH_STABILITY) case EVIOCGVERSION: if (udev->state != UIST_CREATED) retval = -ENODEV; else put_user(EV_VERSION, (int __user *)p); break; case EVIOCGID: if (udev->state != UIST_CREATED) retval = -ENODEV; else if (copy_to_user(p, &udev->dev->id, sizeof(struct input_id))) retval = -EFAULT; break; #endif/*CONFIG_FEATURE_PANTECH_MDS_MTC || FEATURE_PANTECH_STABILITY*/ case UI_SET_EVBIT: retval = uinput_set_bit(arg, evbit, EV_MAX); break; case UI_SET_KEYBIT: retval = uinput_set_bit(arg, keybit, KEY_MAX); break; case UI_SET_RELBIT: retval = uinput_set_bit(arg, relbit, REL_MAX); break; case UI_SET_ABSBIT: retval = uinput_set_bit(arg, absbit, ABS_MAX); break; case UI_SET_MSCBIT: retval = uinput_set_bit(arg, mscbit, MSC_MAX); break; case UI_SET_LEDBIT: retval = uinput_set_bit(arg, ledbit, LED_MAX); break; case UI_SET_SNDBIT: retval = uinput_set_bit(arg, sndbit, SND_MAX); break; case UI_SET_FFBIT: retval = uinput_set_bit(arg, ffbit, FF_MAX); break; case UI_SET_SWBIT: retval = uinput_set_bit(arg, swbit, SW_MAX); break; case UI_SET_PROPBIT: retval = uinput_set_bit(arg, propbit, INPUT_PROP_MAX); break; case UI_SET_PHYS: if (udev->state == UIST_CREATED) { retval = -EINVAL; goto out; } phys = strndup_user(p, 1024); if (IS_ERR(phys)) { retval = PTR_ERR(phys); goto out; } kfree(udev->dev->phys); udev->dev->phys = phys; break; case UI_BEGIN_FF_UPLOAD: retval = uinput_ff_upload_from_user(p, &ff_up); if (retval) break; req = uinput_request_find(udev, ff_up.request_id); if (!req || req->code != UI_FF_UPLOAD || !req->u.upload.effect) { retval = -EINVAL; break; } ff_up.retval = 0; ff_up.effect = *req->u.upload.effect; if (req->u.upload.old) ff_up.old = *req->u.upload.old; else memset(&ff_up.old, 0, sizeof(struct ff_effect)); retval = uinput_ff_upload_to_user(p, &ff_up); break; case UI_BEGIN_FF_ERASE: if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) { retval = -EFAULT; break; } req = uinput_request_find(udev, ff_erase.request_id); if (!req || req->code != UI_FF_ERASE) { retval = -EINVAL; break; } ff_erase.retval = 0; ff_erase.effect_id = req->u.effect_id; if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) { retval = -EFAULT; break; } break; case UI_END_FF_UPLOAD: retval = uinput_ff_upload_from_user(p, &ff_up); if (retval) break; req = uinput_request_find(udev, ff_up.request_id); if (!req || req->code != UI_FF_UPLOAD || !req->u.upload.effect) { retval = -EINVAL; break; } req->retval = ff_up.retval; uinput_request_done(udev, req); break; case UI_END_FF_ERASE: if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) { retval = -EFAULT; break; } req = uinput_request_find(udev, ff_erase.request_id); if (!req || req->code != UI_FF_ERASE) { retval = -EINVAL; break; } req->retval = ff_erase.retval; uinput_request_done(udev, req); break; default: #ifdef CONFIG_FEATURE_PANTECH_MDS_MTC // || defined(FEATURE_PANTECH_STABILITY) { if (udev->state != UIST_CREATED){ retval = -ENODEV; break; } if (_IOC_DIR(cmd) == _IOC_READ) { if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0))) handle_eviocgbit(udev->dev, cmd, p, 0); if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) bits_to_user(udev->dev->key, KEY_MAX, _IOC_SIZE(cmd), p, 0); if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) bits_to_user(udev->dev->led, LED_MAX, _IOC_SIZE(cmd), p, 0); if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) bits_to_user(udev->dev->snd, SND_MAX, _IOC_SIZE(cmd), p, 0); if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) bits_to_user(udev->dev->sw, SW_MAX, _IOC_SIZE(cmd), p, 0); if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) str_to_user(udev->dev->name, _IOC_SIZE(cmd), p); if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) str_to_user(udev->dev->phys, _IOC_SIZE(cmd), p); if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) str_to_user(udev->dev->uniq, _IOC_SIZE(cmd), p); if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { int t; struct input_absinfo abs; t = _IOC_NR(cmd) & ABS_MAX; abs.value = input_abs_get_val(udev->dev,t); abs.minimum = input_abs_get_min(udev->dev,t); abs.maximum = input_abs_get_max(udev->dev,t); abs.fuzz = input_abs_get_fuzz(udev->dev,t); abs.flat = input_abs_get_flat(udev->dev,t); /* abs.value = udev->dev->abs[t]; abs.minimum = udev->dev->absmin[t]; abs.maximum = udev->dev->absmax[t]; abs.fuzz = udev->dev->absfuzz[t]; abs.flat = udev->dev->absflat[t]; */ if (copy_to_user(p, &abs, sizeof(struct input_absinfo))) retval= -EFAULT; } } } #else retval = -EINVAL; #endif/*CONFIG_FEATURE_PANTECH_MDS_MTC || FEATURE_PANTECH_STABILITY*/ } out: mutex_unlock(&udev->mutex); return retval; }
int EventHub::openDevice(const char *deviceName) { int version; int fd; struct pollfd *new_mFDs; device_t **new_devices; char **new_device_names; char name[80]; char location[80]; char idstr[80]; struct input_id id; LOGV("Opening device: %s", deviceName); AutoMutex _l(mLock); fd = open(deviceName, O_RDWR); if(fd < 0) { LOGE("could not open %s, %s\n", deviceName, strerror(errno)); return -1; } if(ioctl(fd, EVIOCGVERSION, &version)) { LOGE("could not get driver version for %s, %s\n", deviceName, strerror(errno)); return -1; } if(ioctl(fd, EVIOCGID, &id)) { LOGE("could not get driver id for %s, %s\n", deviceName, strerror(errno)); return -1; } name[sizeof(name) - 1] = '\0'; location[sizeof(location) - 1] = '\0'; idstr[sizeof(idstr) - 1] = '\0'; if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) { //fprintf(stderr, "could not get device name for %s, %s\n", deviceName, strerror(errno)); name[0] = '\0'; } // check to see if the device is on our excluded list List<String8>::iterator iter = mExcludedDevices.begin(); List<String8>::iterator end = mExcludedDevices.end(); for ( ; iter != end; iter++) { const char* test = *iter; if (strcmp(name, test) == 0) { LOGI("ignoring event id %s driver %s\n", deviceName, test); close(fd); return -1; } } if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) { //fprintf(stderr, "could not get location for %s, %s\n", deviceName, strerror(errno)); location[0] = '\0'; } if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) { //fprintf(stderr, "could not get idstring for %s, %s\n", deviceName, strerror(errno)); idstr[0] = '\0'; } if (fcntl(fd, F_SETFL, O_NONBLOCK)) { LOGE("Error %d making device file descriptor non-blocking.", errno); close(fd); return -1; } int devid = 0; while (devid < mNumDevicesById) { if (mDevicesById[devid].device == NULL) { break; } devid++; } if (devid >= mNumDevicesById) { device_ent* new_devids = (device_ent*)realloc(mDevicesById, sizeof(mDevicesById[0]) * (devid + 1)); if (new_devids == NULL) { LOGE("out of memory"); return -1; } mDevicesById = new_devids; mNumDevicesById = devid+1; mDevicesById[devid].device = NULL; mDevicesById[devid].seq = 0; } mDevicesById[devid].seq = (mDevicesById[devid].seq+(1<<SEQ_SHIFT))&SEQ_MASK; if (mDevicesById[devid].seq == 0) { mDevicesById[devid].seq = 1<<SEQ_SHIFT; } new_mFDs = (pollfd*)realloc(mFDs, sizeof(mFDs[0]) * (mFDCount + 1)); new_devices = (device_t**)realloc(mDevices, sizeof(mDevices[0]) * (mFDCount + 1)); if (new_mFDs == NULL || new_devices == NULL) { LOGE("out of memory"); return -1; } mFDs = new_mFDs; mDevices = new_devices; #if 0 LOGI("add device %d: %s\n", mFDCount, deviceName); LOGI(" bus: %04x\n" " vendor %04x\n" " product %04x\n" " version %04x\n", id.bustype, id.vendor, id.product, id.version); LOGI(" name: \"%s\"\n", name); LOGI(" location: \"%s\"\n" " id: \"%s\"\n", location, idstr); LOGI(" version: %d.%d.%d\n", version >> 16, (version >> 8) & 0xff, version & 0xff); #endif device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName, name, BUS_BLUETOOTH == id.bustype); if (device == NULL) { LOGE("out of memory"); return -1; } device->fd = fd; mFDs[mFDCount].fd = fd; mFDs[mFDCount].events = POLLIN; mFDs[mFDCount].revents = 0; // Figure out the kinds of events the device reports. uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)]; memset(key_bitmask, 0, sizeof(key_bitmask)); LOGV("Getting keys..."); if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) { //LOGI("MAP\n"); //for (int i = 0; i < sizeof(key_bitmask); i++) { // LOGI("%d: 0x%02x\n", i, key_bitmask[i]); //} // See if this is a keyboard. Ignore everything in the button range except for // gamepads which are also considered keyboards. if (containsNonZeroByte(key_bitmask, 0, sizeof_bit_array(BTN_MISC)) || containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_GAMEPAD), sizeof_bit_array(BTN_DIGI)) || containsNonZeroByte(key_bitmask, sizeof_bit_array(KEY_OK), sizeof_bit_array(KEY_MAX + 1))) { device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; device->keyBitmask = new uint8_t[sizeof(key_bitmask)]; if (device->keyBitmask != NULL) { memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask)); } else { delete device; LOGE("out of memory allocating key bitmask"); return -1; } } } // See if this is a trackball (or mouse). if (test_bit(BTN_MOUSE, key_bitmask)) { uint8_t rel_bitmask[sizeof_bit_array(REL_MAX + 1)]; memset(rel_bitmask, 0, sizeof(rel_bitmask)); LOGV("Getting relative controllers..."); if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0) { if (test_bit(REL_X, rel_bitmask) && test_bit(REL_Y, rel_bitmask)) { if (test_bit(BTN_LEFT, key_bitmask) && test_bit(BTN_RIGHT, key_bitmask)) device->classes |= INPUT_DEVICE_CLASS_MOUSE; else device->classes |= INPUT_DEVICE_CLASS_TRACKBALL; } } } // See if this is a touch pad. uint8_t abs_bitmask[sizeof_bit_array(ABS_MAX + 1)]; memset(abs_bitmask, 0, sizeof(abs_bitmask)); LOGV("Getting absolute controllers..."); if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0) { // Is this a new modern multi-touch driver? if (test_bit(ABS_MT_POSITION_X, abs_bitmask) && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) { device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT; // Is this an old style single-touch driver? } else if (test_bit(BTN_TOUCH, key_bitmask) && test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) { device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN; } } #ifdef EV_SW // figure out the switches this device reports uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)]; memset(sw_bitmask, 0, sizeof(sw_bitmask)); bool hasSwitches = false; if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask) >= 0) { for (int i=0; i<EV_SW; i++) { //LOGI("Device 0x%x sw %d: has=%d", device->id, i, test_bit(i, sw_bitmask)); if (test_bit(i, sw_bitmask)) { hasSwitches = true; if (mSwitches[i] == 0) { mSwitches[i] = device->id; } } } } if (hasSwitches) { device->classes |= INPUT_DEVICE_CLASS_SWITCH; } #endif if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) { char tmpfn[sizeof(name)]; char keylayoutFilename[300]; // a more descriptive name device->name = name; // replace all the spaces with underscores strcpy(tmpfn, name); for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' ')) *p = '_'; // find the .kl file we need for this device const char* root = getenv("ANDROID_ROOT"); snprintf(keylayoutFilename, sizeof(keylayoutFilename), "%s/usr/keylayout/%s.kl", root, tmpfn); bool defaultKeymap = false; if (access(keylayoutFilename, R_OK)) { snprintf(keylayoutFilename, sizeof(keylayoutFilename), "%s/usr/keylayout/%s", root, "qwerty.kl"); defaultKeymap = true; } status_t status = device->layoutMap->load(keylayoutFilename); if (status) { LOGE("Error %d loading key layout.", status); } // tell the world about the devname (the descriptive name) if (!mHaveFirstKeyboard && !defaultKeymap && strstr(name, "-keypad")) { // the built-in keyboard has a well-known device ID of 0, // this device better not go away. mHaveFirstKeyboard = true; mFirstKeyboardId = device->id; property_set("hw.keyboards.0.devname", name); } else { // ensure mFirstKeyboardId is set to -something-. if (mFirstKeyboardId == 0) { mFirstKeyboardId = device->id; } } char propName[100]; sprintf(propName, "hw.keyboards.%u.devname", device->id); property_set(propName, name); // 'Q' key support = cheap test of whether this is an alpha-capable kbd if (hasKeycodeLocked(device, AKEYCODE_Q)) { device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY; } // See if this device has a DPAD. if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) && hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) && hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) && hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) && hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) { device->classes |= INPUT_DEVICE_CLASS_DPAD; } // See if this device has a gamepad. for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) { if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) { device->classes |= INPUT_DEVICE_CLASS_GAMEPAD; break; } } LOGI("New keyboard: device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n", device->id, name, propName, keylayoutFilename); } // If the device isn't recognized as something we handle, don't monitor it. if (device->classes == 0) { LOGV("Dropping device %s %p, id = %d\n", deviceName, device, devid); close(fd); delete device; return -1; } LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n", deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes); LOGV("Adding device %s %p at %d, id = %d, classes = 0x%x\n", deviceName, device, mFDCount, devid, device->classes); mDevicesById[devid].device = device; device->next = mOpeningDevices; mOpeningDevices = device; mDevices[mFDCount] = device; mFDCount++; return 0; }
I_NOSTATE(EVIOCGRAB, success), /* evdev */ I_SIMPLE_STRUCT_IN(EVIOCGVERSION, 0, ioctl_insertion_parent_stateless), I_SIMPLE_STRUCT_IN(EVIOCGID, 0, ioctl_insertion_parent_stateless), I_SIMPLE_STRUCT_IN(EVIOCGREP, 0, ioctl_insertion_parent_stateless), I_SIMPLE_STRUCT_IN(EVIOCGKEYCODE, 0, ioctl_insertion_parent_stateless), I_SIMPLE_STRUCT_IN(EVIOCGKEYCODE_V2, 0, ioctl_insertion_parent_stateless), I_SIMPLE_STRUCT_IN(EVIOCGEFFECTS, 0, ioctl_insertion_parent_stateless), I_NAMED_SIMPLE_STRUCT_IN(EVIOCGABS(0), "EVIOCGABS", ABS_MAX, ioctl_insertion_parent_stateless), /* we define these with len==32, but they apply to any len */ I_NAMED_SIMPLE_STRUCT_IN(EVIOCGBIT(0, 32), "EVIOCGBIT", EV_MAX, ioctl_insertion_parent_stateless), I_NAMED_SIMPLE_STRUCT_IN(EVIOCGNAME(32), "EVIOCGNAME", 0, ioctl_insertion_parent_stateless), I_NAMED_SIMPLE_STRUCT_IN(EVIOCGPHYS(32), "EVIOCGPHYS", 0, ioctl_insertion_parent_stateless), I_NAMED_SIMPLE_STRUCT_IN(EVIOCGUNIQ(32), "EVIOCGUNIQ", 0, ioctl_insertion_parent_stateless), I_NAMED_SIMPLE_STRUCT_IN(EVIOCGPROP(32), "EVIOCGPROP", 0, ioctl_insertion_parent_stateless), I_NAMED_SIMPLE_STRUCT_IN(EVIOCGKEY(32), "EVIOCGKEY", 0, ioctl_insertion_parent_stateless), I_NAMED_SIMPLE_STRUCT_IN(EVIOCGLED(32), "EVIOCGLED", 0, ioctl_insertion_parent_stateless), I_NAMED_SIMPLE_STRUCT_IN(EVIOCGSND(32), "EVIOCGSND", 0, ioctl_insertion_parent_stateless), I_NAMED_SIMPLE_STRUCT_IN(EVIOCGSW(32), "EVIOCGSW", 0, ioctl_insertion_parent_stateless), /* this was introduced not too long ago */ #ifdef EVIOCGMTSLOTS I_NAMED_SIMPLE_STRUCT_IN(EVIOCGMTSLOTS(32), "EVIOCGMTSLOTS", 0, ioctl_insertion_parent_stateless), #endif /* terminator */ {0, 0, 0, "", NULL, NULL, NULL, NULL, NULL} };
static Bool EvdevKbdInit (void) { int i; int fd; int n = 0; char name[100]; if (!EvdevInputType) EvdevInputType = KdAllocInputType (); for (i = 0; i < NUM_DEFAULT_EVDEV; i++) { fd = open (kdefaultEvdev1[i], 2); if (fd >= 0) { ioctl(fd, EVIOCGRAB, 1); ioctl(fd, EVIOCGNAME(sizeof(name)), name); ErrorF("Name is %s\n", name); ioctl(fd, EVIOCGPHYS(sizeof(name)), name); ErrorF("Phys Loc is %s\n", name); ioctl(fd, EVIOCGUNIQ(sizeof(name)), name); ErrorF("Unique is %s\n", name); } if (fd >= 0) { unsigned long ev[NBITS(EV_MAX)]; Kevdev *ke; if (ioctl (fd, EVIOCGBIT(0 /*EV*/, sizeof (ev)), ev) < 0) { perror ("EVIOCGBIT 0"); close (fd); continue; } ke = xalloc (sizeof (Kevdev)); if (!ke) { close (fd); continue; } memset (ke, '\0', sizeof (Kevdev)); if (ISBITSET (ev, EV_KEY)) { if (ioctl (fd, EVIOCGBIT (EV_KEY, sizeof (ke->keybits)), ke->keybits) < 0) { perror ("EVIOCGBIT EV_KEY"); xfree (ke); close (fd); continue; } } if (ISBITSET (ev, EV_REL)) { if (ioctl (fd, EVIOCGBIT (EV_REL, sizeof (ke->relbits)), ke->relbits) < 0) { perror ("EVIOCGBIT EV_REL"); xfree (ke); close (fd); continue; } for (ke->max_rel = REL_MAX; ke->max_rel >= 0; ke->max_rel--) if (ISBITSET(ke->relbits, ke->max_rel)) break; } if (ISBITSET (ev, EV_ABS)) { int i; if (ioctl (fd, EVIOCGBIT (EV_ABS, sizeof (ke->absbits)), ke->absbits) < 0) { perror ("EVIOCGBIT EV_ABS"); xfree (ke); close (fd); continue; } for (ke->max_abs = ABS_MAX; ke->max_abs >= 0; ke->max_abs--) if (ISBITSET(ke->absbits, ke->max_abs)) break; for (i = 0; i <= ke->max_abs; i++) { if (ISBITSET (ke->absbits, i)) if (ioctl (fd, EVIOCGABS(i), &ke->absinfo[i]) < 0) { perror ("EVIOCGABS"); break; } ke->prevabs[i] = ABS_UNSET; } if (i <= ke->max_abs) { xfree (ke); close (fd); continue; } } if (KdRegisterFd (EvdevInputType, fd, EvdevRead1, NULL)) n++; } } return TRUE; }
static int evdev_read_ioctl(struct tcb *const tcp, const unsigned int code, const kernel_ulong_t arg) { /* fixed-number fixed-length commands */ switch (code) { case EVIOCGVERSION: tprints(", "); printnum_int(tcp, arg, "%#x"); return 1; case EVIOCGEFFECTS: tprints(", "); printnum_int(tcp, arg, "%u"); return 1; case EVIOCGID: return getid_ioctl(tcp, arg); # ifdef EVIOCGREP case EVIOCGREP: return repeat_ioctl(tcp, arg); # endif case EVIOCGKEYCODE: return keycode_ioctl(tcp, arg); # ifdef EVIOCGKEYCODE_V2 case EVIOCGKEYCODE_V2: return keycode_V2_ioctl(tcp, arg); # endif } /* fixed-number variable-length commands */ switch (_IOC_NR(code)) { # ifdef EVIOCGMTSLOTS case _IOC_NR(EVIOCGMTSLOTS(0)): return mtslots_ioctl(tcp, code, arg); # endif case _IOC_NR(EVIOCGNAME(0)): case _IOC_NR(EVIOCGPHYS(0)): case _IOC_NR(EVIOCGUNIQ(0)): tprints(", "); if (syserror(tcp)) printaddr(arg); else printstrn(tcp, arg, tcp->u_rval); return 1; # ifdef EVIOCGPROP case _IOC_NR(EVIOCGPROP(0)): return decode_bitset(tcp, arg, evdev_prop, INPUT_PROP_MAX, "PROP_???"); # endif case _IOC_NR(EVIOCGSND(0)): return decode_bitset(tcp, arg, evdev_snd, SND_MAX, "SND_???"); # ifdef EVIOCGSW case _IOC_NR(EVIOCGSW(0)): return decode_bitset(tcp, arg, evdev_switch, SW_MAX, "SW_???"); # endif case _IOC_NR(EVIOCGKEY(0)): return decode_bitset(tcp, arg, evdev_keycode, KEY_MAX, "KEY_???"); case _IOC_NR(EVIOCGLED(0)): return decode_bitset(tcp, arg, evdev_leds, LED_MAX, "LED_???"); } /* multi-number fixed-length commands */ if ((_IOC_NR(code) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) return abs_ioctl(tcp, arg); /* multi-number variable-length commands */ if ((_IOC_NR(code) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0))) return bit_ioctl(tcp, _IOC_NR(code) & EV_MAX, arg); return 0; }
status_t EvdevDeviceNode::queryProperties() { char buffer[80]; if (TEMP_FAILURE_RETRY(ioctl(mFd, EVIOCGNAME(sizeof(buffer) - 1), buffer)) < 1) { ALOGV("could not get device name for %s.", mPath.c_str()); } else { buffer[sizeof(buffer) - 1] = '\0'; mName = buffer; } int driverVersion; if (TEMP_FAILURE_RETRY(ioctl(mFd, EVIOCGVERSION, &driverVersion))) { ALOGE("could not get driver version for %s. err=%d", mPath.c_str(), errno); return -errno; } struct input_id inputId; if (TEMP_FAILURE_RETRY(ioctl(mFd, EVIOCGID, &inputId))) { ALOGE("could not get device input id for %s. err=%d", mPath.c_str(), errno); return -errno; } mBusType = inputId.bustype; mVendorId = inputId.vendor; mProductId = inputId.product; mVersion = inputId.version; if (TEMP_FAILURE_RETRY(ioctl(mFd, EVIOCGPHYS(sizeof(buffer) - 1), buffer)) < 1) { ALOGV("could not get location for %s.", mPath.c_str()); } else { buffer[sizeof(buffer) - 1] = '\0'; mLocation = buffer; } if (TEMP_FAILURE_RETRY(ioctl(mFd, EVIOCGUNIQ(sizeof(buffer) - 1), buffer)) < 1) { ALOGV("could not get unique id for %s.", mPath.c_str()); } else { buffer[sizeof(buffer) - 1] = '\0'; mUniqueId = buffer; } ALOGV("add device %s", mPath.c_str()); ALOGV(" bus: %04x\n" " vendor: %04x\n" " product: %04x\n" " version: %04x\n", mBusType, mVendorId, mProductId, mVersion); ALOGV(" name: \"%s\"\n" " location: \"%s\"\n" " unique_id: \"%s\"\n" " descriptor: (TODO)\n" " driver: v%d.%d.%d", mName.c_str(), mLocation.c_str(), mUniqueId.c_str(), driverVersion >> 16, (driverVersion >> 8) & 0xff, (driverVersion >> 16) & 0xff); TEMP_FAILURE_RETRY(ioctl(mFd, EVIOCGBIT(EV_KEY, sizeof(mKeyBitmask)), mKeyBitmask)); TEMP_FAILURE_RETRY(ioctl(mFd, EVIOCGBIT(EV_ABS, sizeof(mAbsBitmask)), mAbsBitmask)); TEMP_FAILURE_RETRY(ioctl(mFd, EVIOCGBIT(EV_REL, sizeof(mRelBitmask)), mRelBitmask)); TEMP_FAILURE_RETRY(ioctl(mFd, EVIOCGBIT(EV_SW, sizeof(mSwBitmask)), mSwBitmask)); TEMP_FAILURE_RETRY(ioctl(mFd, EVIOCGBIT(EV_LED, sizeof(mLedBitmask)), mLedBitmask)); TEMP_FAILURE_RETRY(ioctl(mFd, EVIOCGBIT(EV_FF, sizeof(mFfBitmask)), mFfBitmask)); TEMP_FAILURE_RETRY(ioctl(mFd, EVIOCGPROP(sizeof(mPropBitmask)), mPropBitmask)); queryAxisInfo(); return OK; }
static unsigned char send_device_info(IEContext* ctx, unsigned int reply_id) { dterm_mark_t msg; dterm_t dt; int len = 0; char name[256]; char topology[256]; char uniq_id[256]; struct input_id id; // Get device id. if (ioctl(ctx->mDescriptor, EVIOCGID, &id) < 0) { return IEDRV_RES_IO_ERROR; } if ((len = ioctl(ctx->mDescriptor, EVIOCGNAME(sizeof(name) - 1), name)) < 0) { return IEDRV_RES_IO_ERROR; } name[len] = 0; if ((len = ioctl(ctx->mDescriptor, EVIOCGPHYS(sizeof(topology) - 1), topology)) < 0) { return IEDRV_RES_IO_ERROR; } topology[len] = 0; if ((len = ioctl(ctx->mDescriptor, EVIOCGUNIQ(sizeof(uniq_id) - 1), uniq_id)) < 0) uniq_id[0] = 0; uniq_id[len] = 0; dterm_init(&dt); dterm_tuple_begin(&dt, &msg); { dterm_mark_t prop; dterm_atom(&dt, ie_device_info); dterm_port(&dt, ctx->mDport); dterm_int(&dt, reply_id); // // Setup { id, Bustype, Vendor, Product, Version, Name} // dterm_tuple_begin(&dt, &prop); { dterm_atom(&dt, ie_drv_dev_id); dterm_string(&dt, uniq_id, strlen(uniq_id)); dterm_string(&dt, name, strlen(name)); dterm_atom(&dt, *bus_atoms[id.bustype]); dterm_int(&dt, id.vendor); dterm_int(&dt, id.product); dterm_int(&dt, id.version); dterm_string(&dt, topology, strlen(topology)); // // Setup [{ capability, [ { Cap, [X] }, { Cap, [Y] }, ...}, ...] // add_cap(&dt, ctx->mDescriptor); dterm_tuple_end(&dt, &prop); } } dterm_tuple_end(&dt, &msg); driver_output_term(ctx->mPort, dterm_data(&dt), dterm_used_size(&dt)); dterm_finish(&dt); return IEDRV_RES_OK; }
static int open_device(const char *device, int print_flags) { int version; int fd; int clkid = CLOCK_MONOTONIC; struct pollfd *new_ufds; char **new_device_names; char name[80]; char location[80]; char idstr[80]; struct input_id id; fd = open(device, O_RDONLY | O_CLOEXEC); if(fd < 0) { if(print_flags & PRINT_DEVICE_ERRORS) fprintf(stderr, "could not open %s, %s\n", device, strerror(errno)); return -1; } if(ioctl(fd, EVIOCGVERSION, &version)) { if(print_flags & PRINT_DEVICE_ERRORS) fprintf(stderr, "could not get driver version for %s, %s\n", device, strerror(errno)); return -1; } if(ioctl(fd, EVIOCGID, &id)) { if(print_flags & PRINT_DEVICE_ERRORS) fprintf(stderr, "could not get driver id for %s, %s\n", device, strerror(errno)); return -1; } name[sizeof(name) - 1] = '\0'; location[sizeof(location) - 1] = '\0'; idstr[sizeof(idstr) - 1] = '\0'; if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) { //fprintf(stderr, "could not get device name for %s, %s\n", device, strerror(errno)); name[0] = '\0'; } if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) { //fprintf(stderr, "could not get location for %s, %s\n", device, strerror(errno)); location[0] = '\0'; } if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) { //fprintf(stderr, "could not get idstring for %s, %s\n", device, strerror(errno)); idstr[0] = '\0'; } if (ioctl(fd, EVIOCSCLOCKID, &clkid) != 0) { fprintf(stderr, "Can't enable monotonic clock reporting: %s\n", strerror(errno)); // a non-fatal error } new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1)); if(new_ufds == NULL) { fprintf(stderr, "out of memory\n"); return -1; } ufds = new_ufds; new_device_names = realloc(device_names, sizeof(device_names[0]) * (nfds + 1)); if(new_device_names == NULL) { fprintf(stderr, "out of memory\n"); return -1; } device_names = new_device_names; if(print_flags & PRINT_DEVICE) printf("add device %d: %s\n", nfds, device); if(print_flags & PRINT_DEVICE_INFO) printf(" bus: %04x\n" " vendor %04x\n" " product %04x\n" " version %04x\n", id.bustype, id.vendor, id.product, id.version); if(print_flags & PRINT_DEVICE_NAME) printf(" name: \"%s\"\n", name); if(print_flags & PRINT_DEVICE_INFO) printf(" location: \"%s\"\n" " id: \"%s\"\n", location, idstr); if(print_flags & PRINT_VERSION) printf(" version: %d.%d.%d\n", version >> 16, (version >> 8) & 0xff, version & 0xff); if(print_flags & PRINT_POSSIBLE_EVENTS) { print_possible_events(fd, print_flags); } if(print_flags & PRINT_INPUT_PROPS) { print_input_props(fd); } if(print_flags & PRINT_HID_DESCRIPTOR) { print_hid_descriptor(id.bustype, id.vendor, id.product); } ufds[nfds].fd = fd; ufds[nfds].events = POLLIN; device_names[nfds] = strdup(device); nfds++; return 0; }
/* another option to this mess (as the hashing thing doesn't seem to work out * is to move identification/etc. to another level and just let whatever device * node generator is active populate with coherent names. and use a hash of that * name as the ID */ static bool identify(int fd, const char* path, char* label, size_t label_sz, unsigned short* dnum) { if (-1 == ioctl(fd, EVIOCGNAME(label_sz), label)){ debug_print("input/identify: bad EVIOCGNAME, setting unknown\n"); snprintf(label, label_sz, "unknown"); } else verbose_print( "input/identify(%d): %s name resolved to %s", fd, path, label); struct input_id nodeid; if (-1 == ioctl(fd, EVIOCGID, &nodeid)){ debug_print( "input/identify(%d): no EVIOCGID, reason:%s", fd, strerror(errno)); return false; } /* * first, check if any other subsystem knows about this one and ignore if so */ if (arcan_led_known(nodeid.vendor, nodeid.product)){ debug_print( "led subsys know %d, %d\n", (int)nodeid.vendor, (int)nodeid.product); arcan_led_init(); return false; } /* didn't find much on how unique eviocguniq actually was, nor common lengths * or what not so just mix them in a buffer, hash and let unsigned overflow * modulo take us down to 16bit */ size_t bpl = sizeof(long) * 8; size_t nbits = ((EV_MAX)-1) / bpl + 1; char buf[12 + nbits * sizeof(long)]; char bbuf[sizeof(buf)]; memset(buf, '\0', sizeof(buf)); memset(bbuf, '\0', sizeof(bbuf)); /* some test devices here answered to the ioctl and returned full empty UNIQs, * do something to lower the likelihood of collisions */ unsigned long hash = 5381; if (-1 == ioctl(fd, EVIOCGUNIQ(sizeof(buf)), buf) || memcmp(buf, bbuf, sizeof(buf)) == 0){ size_t llen = strlen(label); for (size_t i = 0; i < llen; i++) hash = ((hash << 5) + hash) + label[i]; llen = strlen(path); for (size_t i = 0; i < llen; i++) hash = ((hash << 5) + hash) + path[i]; buf[11] ^= nodeid.vendor >> 8; buf[10] ^= nodeid.vendor; buf[9] ^= nodeid.product >> 8; buf[8] ^= nodeid.product; buf[7] ^= nodeid.version >> 8; buf[6] ^= nodeid.version; /* even this point has a few collisions, particularly some keyboards and mice * that don't respond to CGUNIQ and expose multiple- subdevices but with * different button/axis count */ ioctl(fd, EVIOCGBIT(0, EV_MAX), &buf); }
static int open_device(const char *device) { int version; int fd; struct pollfd *new_ufds; char **new_device_names; char name[80]; char location[80]; char idstr[80]; struct input_id id; fd = open(device, O_RDWR); if(fd < 0) { fprintf(stderr, "could not open %s, %s\n", device, strerror(errno)); return -1; } if(ioctl(fd, EVIOCGVERSION, &version)) { fprintf(stderr, "could not get driver version for %s, %s\n", device, strerror(errno)); return -1; } if(ioctl(fd, EVIOCGID, &id)) { fprintf(stderr, "could not get driver id for %s, %s\n", device, strerror(errno)); return -1; } name[sizeof(name) - 1] = '\0'; location[sizeof(location) - 1] = '\0'; idstr[sizeof(idstr) - 1] = '\0'; if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) { //fprintf(stderr, "could not get device name for %s, %s\n", device, strerror(errno)); name[0] = '\0'; } if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) { //fprintf(stderr, "could not get location for %s, %s\n", device, strerror(errno)); location[0] = '\0'; } if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) { //fprintf(stderr, "could not get idstring for %s, %s\n", device, strerror(errno)); idstr[0] = '\0'; } new_ufds = (pollfd*)realloc(ufds, sizeof(ufds[0]) * (nfds + 1)); if(new_ufds == NULL) { fprintf(stderr, "out of memory\n"); return -1; } ufds = new_ufds; new_device_names = (char**)realloc(device_names, sizeof(device_names[0]) * (nfds + 1)); if(new_device_names == NULL) { fprintf(stderr, "out of memory\n"); return -1; } device_names = new_device_names; printf("add device %d: %s \"%s\"\n", nfds, device, name); ufds[nfds].fd = fd; ufds[nfds].events = POLLIN; device_names[nfds] = strdup(device); nfds++; return 0; }