int evdev_is_suitable(int fd) { long evtype_bitmask[(EV_MAX/BITS_PER_LONG) + 1]; /* Clean evtype_bitmask structure */ memset(evtype_bitmask, 0, sizeof(evtype_bitmask)); /* Ask device features */ if (ioctl(fd, EVIOCGBIT(0, EV_MAX), evtype_bitmask) < 0) { log_msg(lg, "+ can't get evdev features: %s", ERRMSG); return 0; } #ifdef DEBUG int yalv; for (yalv = 0; yalv < EV_MAX; yalv++) { if (test_bit(yalv, evtype_bitmask)) { /* this means that the bit is set in the event types list */ switch (yalv) { case EV_SYN: log_msg(lg, " + Sync"); break; case EV_KEY: log_msg(lg, " + Keys or Buttons"); break; case EV_REL: log_msg(lg, " + Relative Axes"); break; case EV_ABS: log_msg(lg, " + Absolute Axes"); break; case EV_MSC: log_msg(lg, " + Something miscellaneous"); break; case EV_SW: log_msg(lg, " + Switch"); break; case EV_LED: log_msg(lg, " + LEDs"); break; case EV_SND: log_msg(lg, " + Sounds"); break; case EV_REP: log_msg(lg, " + Repeat"); break; case EV_FF: log_msg(lg, " + Force Feedback"); break; case EV_PWR: log_msg(lg, " + Power"); break; case EV_FF_STATUS: log_msg(lg, " + Force Feedback Status"); break; default: log_msg(lg, " + Unknown event type: 0x%04hx", yalv); break; } } } #endif /* Check that we have EV_KEY bit set */ if (test_bit(EV_KEY, evtype_bitmask)) return 1; /* device is not suitable */ log_msg(lg, "+ evdev have no EV_KEY bit, skipped"); return 0; }
compat_hat_offs = ev_abs_count; ev_hat_count++; } ev_abs_count++; } } //printf("%u\n", compat_hat_offs); CalcOldStyleID(ev_abs_count - ev_hat_count, 0, ev_hat_count / 2, num_buttons); } #if 0 uint8 keybits[(KEY_CNT + 7) / 8]; unsigned ev_button_count = 0; memset(keybits, 0, sizeof(keybits)); ioctl(evdev_fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits); hashie.update(keybits, sizeof(keybits)); for(unsigned kbt = 0; kbt < KEY_CNT; kbt++) { if(keybits[kbt >> 3] & (1 << (kbt & 0x7))) { ev_button_count++; } } printf("moo: %u\n", ev_button_count); } #endif rumble_supported = false; rumble_used = false;
void lightgun_event_abs_init(void) { int i; for (i = 0; i < GUN_MAX; i++) { char name[256] = "Unknown"; uint8_t abs_bitmask[ABS_MAX/8 + 1]; struct input_absinfo abs_features; if (!lg_devices[i].device) continue; if ((lg_devices[i].fd = open(lg_devices[i].device, O_RDONLY)) < 0) { fprintf(stderr_file, "Lightgun%d: %s[open]: %s", i + 1, lg_devices[i].device, strerror(errno)); continue; } if (ioctl(lg_devices[i].fd, EVIOCGNAME(sizeof(name)), name) < 0) { fprintf(stderr_file, "Lightgun%d: %s[ioctl/EVIOCGNAME]: %s\n", i + 1, lg_devices[i].device, strerror(errno)); lg_devices[i].device = NULL; continue; } memset(abs_bitmask, 0, sizeof(abs_bitmask)); if (ioctl(lg_devices[i].fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) < 0) { fprintf(stderr_file, "Lightgun%d: %s[ioctl/EVIOCGNAME]: %s\n", i + 1, lg_devices[i].device, strerror(errno)); lg_devices[i].device = NULL; continue; } /* Make sure we have an X and Y axis. Not much good * without it. */ if (!test_bit(ABS_X, abs_bitmask) || !test_bit(ABS_Y, abs_bitmask)) { fprintf(stderr_file, "Lightgun%d: %s: Does not contain both X and Y axis, " "ignoring\n", i + 1, lg_devices[i].device); lg_devices[i].device = NULL; continue; } if (ioctl(lg_devices[i].fd, EVIOCGABS(ABS_X), &abs_features)) { fprintf(stderr_file, "Lightgun%d: %s[ioctl/EVIOCGABS(ABX_X)]: %s\n", i + 1, lg_devices[i].device, strerror(errno)); lg_devices[i].device = NULL; continue; } lg_devices[i].min[LG_X_AXIS] = abs_features.minimum; lg_devices[i].range[LG_X_AXIS] = abs_features.maximum - abs_features.minimum; if (ioctl(lg_devices[i].fd, EVIOCGABS(ABS_Y), &abs_features)) { fprintf(stderr_file, "Lightgun%d: %s[ioctl/EVIOCGABS(ABX_Y)]: %s\n", i + 1, lg_devices[i].device, strerror(errno)); lg_devices[i].device = NULL; continue; } lg_devices[i].min[LG_Y_AXIS] = abs_features.minimum; lg_devices[i].range[LG_Y_AXIS] = abs_features.maximum - abs_features.minimum; fprintf(stderr_file, "Lightgun%d: %s\n", i + 1, name); fprintf(stderr_file, " X axis: min[%d] range[%d]\n", lg_devices[i].min[LG_X_AXIS], lg_devices[i].range[LG_X_AXIS]); fprintf(stderr_file, " Y axis: min[%d] range[%d]\n", lg_devices[i].min[LG_Y_AXIS], lg_devices[i].range[LG_Y_AXIS]); } }
/* * Fill device information. * Queries the input device and tries to classify it. */ void CLinuxInputDevice::GetInfo(int fd) { unsigned int num_keys = 0; unsigned int num_ext_keys = 0; unsigned int num_buttons = 0; unsigned int num_rels = 0; unsigned int num_abs = 0; unsigned long evbit[NBITS(EV_CNT)]; unsigned long keybit[NBITS(KEY_CNT)]; /* get device name */ bzero(m_deviceName, sizeof(m_deviceName)); ioctl(fd, EVIOCGNAME(sizeof(m_deviceName)-1), m_deviceName); if (strncmp(m_deviceName, "D-Link Boxee D-Link Boxee Receiver", strlen("D-Link Boxee D-Link Boxee Receiver")) == 0) { m_bSkipNonKeyEvents = true; } else { m_bSkipNonKeyEvents = false; } CLog::Log(LOGINFO, "opened device '%s' (file name %s), m_bSkipNonKeyEvents %d\n", m_deviceName, m_fileName.c_str(), m_bSkipNonKeyEvents); /* get event type bits */ ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit); if (test_bit( EV_KEY, evbit )) { int i; /* get keyboard bits */ ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit); /** count typical keyboard keys only */ for (i = KEY_Q; i <= KEY_M; i++) if (test_bit( i, keybit )) num_keys++; for (i = KEY_OK; i < KEY_CNT; i++) if (test_bit( i, keybit )) num_ext_keys++; for (i = BTN_MOUSE; i < BTN_JOYSTICK; i++) if (test_bit( i, keybit )) num_buttons++; } #ifndef HAS_INTELCE unsigned long relbit[NBITS(REL_CNT)]; unsigned long absbit[NBITS(ABS_CNT)]; if (test_bit( EV_REL, evbit )) { int i; /* get bits for relative axes */ ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit); for (i = 0; i < REL_CNT; i++) if (test_bit( i, relbit )) num_rels++; } if (test_bit( EV_ABS, evbit )) { int i; /* get bits for absolute axes */ ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit); for (i = 0; i < ABS_PRESSURE; i++) if (test_bit( i, absbit )) num_abs++; } /* Mouse, Touchscreen or Smartpad ? */ if ((test_bit( EV_KEY, evbit ) && (test_bit( BTN_TOUCH, keybit ) || test_bit( BTN_TOOL_FINGER, keybit ))) || ((num_rels >= 2 && num_buttons) || (num_abs == 2 && (num_buttons == 1)))) m_deviceType |= LI_DEVICE_MOUSE; else if (num_abs && num_buttons) /* Or a Joystick? */ m_deviceType |= LI_DEVICE_JOYSTICK; #endif /* A Keyboard, do we have at least some letters? */ if (num_keys > 20) { m_deviceType |= LI_DEVICE_KEYBOARD; m_deviceCaps |= LI_CAPS_KEYS; m_deviceMinKeyCode = 0; m_deviceMaxKeyCode = 127; } /* A Remote Control? */ if (num_ext_keys) { m_deviceType |= LI_DEVICE_REMOTE; m_deviceCaps |= LI_CAPS_KEYS; } /* Buttons */ if (num_buttons) { m_deviceCaps |= LI_CAPS_BUTTONS; m_deviceMaxKeyCode = num_buttons - 1; } /* Axes */ if (num_rels || num_abs) { m_deviceCaps |= LI_CAPS_AXES; m_deviceMaxAxis = std::max(num_rels, num_abs) - 1; } /* Decide which primary input device to be. */ if (m_deviceType & LI_DEVICE_KEYBOARD) m_devicePreferredId = LI_DEVICE_KEYBOARD; else if (m_deviceType & LI_DEVICE_REMOTE) m_devicePreferredId = LI_DEVICE_REMOTE; else if (m_deviceType & LI_DEVICE_JOYSTICK) m_devicePreferredId = LI_DEVICE_JOYSTICK; else if (m_deviceType & LI_DEVICE_MOUSE) m_devicePreferredId = LI_DEVICE_MOUSE; else m_devicePreferredId = LI_DEVICE_NONE; //printf("type: %d\n", m_deviceType); //printf("caps: %d\n", m_deviceCaps); //printf("pref: %d\n", m_devicePreferredId); }
int main(int argc, char ** argv) { int fd; unsigned long *evtype_b = malloc(sizeof(int)); int yalv; if ((fd = open(argv[1], O_RDONLY)) < 0) { perror("evdev open"); exit(1); } memset(evtype_b, 0, sizeof(evtype_b)); if (ioctl(fd, EVIOCGBIT(0, EV_MAX), evtype_b) < 0) { perror("evdev ioctl"); } printf("Supported event types:\n"); 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); } } } close(fd); }
static int evdev_handle_device(struct evdev_device *device) { struct input_absinfo absinfo; unsigned long ev_bits[NBITS(EV_MAX)]; unsigned long abs_bits[NBITS(ABS_MAX)]; unsigned long rel_bits[NBITS(REL_MAX)]; unsigned long key_bits[NBITS(KEY_MAX)]; int has_key, has_abs; unsigned int i; has_key = 0; has_abs = 0; device->caps = 0; ioctl(device->fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits); if (TEST_BIT(ev_bits, EV_ABS)) { has_abs = 1; ioctl(device->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits); if (TEST_BIT(abs_bits, ABS_X)) { ioctl(device->fd, EVIOCGABS(ABS_X), &absinfo); device->abs.min_x = absinfo.minimum; device->abs.max_x = absinfo.maximum; device->caps |= EVDEV_MOTION_ABS; } if (TEST_BIT(abs_bits, ABS_Y)) { ioctl(device->fd, EVIOCGABS(ABS_Y), &absinfo); device->abs.min_y = absinfo.minimum; device->abs.max_y = absinfo.maximum; device->caps |= EVDEV_MOTION_ABS; } if (TEST_BIT(abs_bits, ABS_MT_SLOT)) { ioctl(device->fd, EVIOCGABS(ABS_MT_POSITION_X), &absinfo); device->abs.min_x = absinfo.minimum; device->abs.max_x = absinfo.maximum; ioctl(device->fd, EVIOCGABS(ABS_MT_POSITION_Y), &absinfo); device->abs.min_y = absinfo.minimum; device->abs.max_y = absinfo.maximum; device->is_mt = 1; device->mt.slot = 0; device->caps |= EVDEV_TOUCH; } } if (TEST_BIT(ev_bits, EV_REL)) { ioctl(device->fd, EVIOCGBIT(EV_REL, sizeof(rel_bits)), rel_bits); if (TEST_BIT(rel_bits, REL_X) || TEST_BIT(rel_bits, REL_Y)) device->caps |= EVDEV_MOTION_REL; } if (TEST_BIT(ev_bits, EV_KEY)) { has_key = 1; ioctl(device->fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)), key_bits); if (TEST_BIT(key_bits, BTN_TOOL_FINGER) && !TEST_BIT(key_bits, BTN_TOOL_PEN) && has_abs) device->dispatch = evdev_touchpad_create(device); for (i = KEY_ESC; i < KEY_MAX; i++) { if (i >= BTN_MISC && i < KEY_OK) continue; if (TEST_BIT(key_bits, i)) { device->caps |= EVDEV_KEYBOARD; break; } } for (i = BTN_MISC; i < KEY_OK; i++) { if (TEST_BIT(key_bits, i)) { device->caps |= EVDEV_BUTTON; break; } } } if (TEST_BIT(ev_bits, EV_LED)) { device->caps |= EVDEV_KEYBOARD; } /* This rule tries to catch accelerometer devices and opt out. We may * want to adjust the protocol later adding a proper event for dealing * with accelerometers and implement here accordingly */ if (has_abs && !has_key && !device->is_mt) { weston_log("input device %s, %s " "ignored: unsupported device type\n", device->devname, device->devnode); return 0; } return 1; }
static void ConfigJoystick(SDL_Joystick * joystick, int fd) { int i, t; unsigned long keybit[NBITS(KEY_MAX)] = { 0 }; unsigned long absbit[NBITS(ABS_MAX)] = { 0 }; unsigned long relbit[NBITS(REL_MAX)] = { 0 }; /* See if this device uses the new unified event API */ if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) && (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) && (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0)) { /* Get the number of buttons, axes, and other thingamajigs */ for (i = BTN_JOYSTICK; i < KEY_MAX; ++i) { if (test_bit(i, keybit)) { #ifdef DEBUG_INPUT_EVENTS printf("Joystick has button: 0x%x\n", i); #endif joystick->hwdata->key_map[i] = joystick->nbuttons; ++joystick->nbuttons; } } for (i = 0; i < BTN_JOYSTICK; ++i) { if (test_bit(i, keybit)) { #ifdef DEBUG_INPUT_EVENTS printf("Joystick has button: 0x%x\n", i); #endif joystick->hwdata->key_map[i] = joystick->nbuttons; ++joystick->nbuttons; } } for (i = 0; i < ABS_MAX; ++i) { /* Skip hats */ if (i == ABS_HAT0X) { i = ABS_HAT3Y; continue; } if (test_bit(i, absbit)) { struct input_absinfo absinfo; if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) { continue; } #ifdef DEBUG_INPUT_EVENTS printf("Joystick has absolute axis: 0x%.2x\n", i); printf("Values = { %d, %d, %d, %d, %d }\n", absinfo.value, absinfo.minimum, absinfo.maximum, absinfo.fuzz, absinfo.flat); #endif /* DEBUG_INPUT_EVENTS */ joystick->hwdata->abs_map[i] = joystick->naxes; if (absinfo.minimum == absinfo.maximum) { joystick->hwdata->abs_correct[i].used = 0; } else { joystick->hwdata->abs_correct[i].used = 1; joystick->hwdata->abs_correct[i].coef[0] = (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat; joystick->hwdata->abs_correct[i].coef[1] = (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat; t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat); if (t != 0) { joystick->hwdata->abs_correct[i].coef[2] = (1 << 28) / t; } else { joystick->hwdata->abs_correct[i].coef[2] = 0; } } ++joystick->naxes; } } for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) { if (test_bit(i, absbit) || test_bit(i + 1, absbit)) { struct input_absinfo absinfo; if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) { continue; } #ifdef DEBUG_INPUT_EVENTS printf("Joystick has hat %d\n", (i - ABS_HAT0X) / 2); printf("Values = { %d, %d, %d, %d, %d }\n", absinfo.value, absinfo.minimum, absinfo.maximum, absinfo.fuzz, absinfo.flat); #endif /* DEBUG_INPUT_EVENTS */ ++joystick->nhats; } } if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) { ++joystick->nballs; } /* Allocate data to keep track of these thingamajigs */ if (joystick->nhats > 0) { if (allocate_hatdata(joystick) < 0) { joystick->nhats = 0; } } if (joystick->nballs > 0) { if (allocate_balldata(joystick) < 0) { joystick->nballs = 0; } } } }
void joystick_linux::open_joystick(const char *p_path) { int joy_num = get_free_joy_slot(); int fd = open(p_path, O_RDONLY | O_NONBLOCK); if (fd != -1 && joy_num != -1) { unsigned long evbit[NBITS(EV_MAX)] = { 0 }; unsigned long keybit[NBITS(KEY_MAX)] = { 0 }; unsigned long absbit[NBITS(ABS_MAX)] = { 0 }; if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) || (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) || (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) { close(fd); return; } //check if the device supports basic gamepad events, prevents certain keyboards from //being detected as joysticks if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) && (test_bit(ABS_X, absbit) || test_bit(ABS_Y, absbit) || test_bit(ABS_HAT0X, absbit) || test_bit(ABS_GAS, absbit) || test_bit(ABS_RUDDER, absbit)) && (test_bit(BTN_A, keybit) || test_bit(BTN_THUMBL, keybit) || test_bit(BTN_TRIGGER, keybit) || test_bit(BTN_1, keybit)))) { close(fd); return; } char uid[128]; char namebuf[128]; String name = ""; input_id inpid; if (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) >= 0) { name = namebuf; } if (ioctl(fd, EVIOCGID, &inpid) < 0) { close(fd); return; } joysticks[joy_num].reset(); Joystick &joy = joysticks[joy_num]; joy.fd = fd; joy.devpath = String(p_path); setup_joystick_properties(joy_num); sprintf(uid, "%04x%04x", __bswap_16(inpid.bustype), 0); if (inpid.vendor && inpid.product && inpid.version) { uint16_t vendor = __bswap_16(inpid.vendor); uint16_t product = __bswap_16(inpid.product); uint16_t version = __bswap_16(inpid.version); sprintf(uid + String(uid).length(), "%04x%04x%04x%04x%04x%04x", vendor,0,product,0,version,0); input->joy_connection_changed(joy_num, true, name, uid); } else { String uidname = uid; int uidlen = MIN(name.length(), 11); for (int i=0; i<uidlen; i++) { uidname = uidname + _hex_str(name[i]); } uidname += "00"; input->joy_connection_changed(joy_num, true, name, uidname); } } }
int pa__init(pa_module*m) { pa_modargs *ma = NULL; struct userdata *u; int version; struct input_id input_id; char name[256]; uint8_t evtype_bitmask[EV_MAX/8 + 1]; pa_volume_t volume_limit = PA_VOLUME_NORM*3/2; pa_volume_t volume_step = PA_VOLUME_NORM/20; pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("Failed to parse module arguments"); goto fail; } if (pa_modargs_get_value_u32(ma, "volume_limit", &volume_limit) < 0) { pa_log("Failed to parse volume limit"); goto fail; } if (pa_modargs_get_value_u32(ma, "volume_step", &volume_step) < 0) { pa_log("Failed to parse volume step"); goto fail; } m->userdata = u = pa_xnew(struct userdata, 1); u->module = m; u->io = NULL; u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); u->fd = -1; u->fd_type = 0; u->volume_limit = PA_CLAMP_VOLUME(volume_limit); u->volume_step = PA_CLAMP_VOLUME(volume_step); if ((u->fd = pa_open_cloexec(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), O_RDONLY, 0)) < 0) { pa_log("Failed to open evdev device: %s", pa_cstrerror(errno)); goto fail; } if (ioctl(u->fd, EVIOCGVERSION, &version) < 0) { pa_log("EVIOCGVERSION failed: %s", pa_cstrerror(errno)); goto fail; } pa_log_info("evdev driver version %i.%i.%i", version >> 16, (version >> 8) & 0xff, version & 0xff); if (ioctl(u->fd, EVIOCGID, &input_id)) { pa_log("EVIOCGID failed: %s", pa_cstrerror(errno)); goto fail; } pa_log_info("evdev vendor 0x%04hx product 0x%04hx version 0x%04hx bustype %u", input_id.vendor, input_id.product, input_id.version, input_id.bustype); memset(name, 0, sizeof(name)); if (ioctl(u->fd, EVIOCGNAME(sizeof(name)), name) < 0) { pa_log("EVIOCGNAME failed: %s", pa_cstrerror(errno)); goto fail; } pa_log_info("evdev device name: %s", name); memset(evtype_bitmask, 0, sizeof(evtype_bitmask)); if (ioctl(u->fd, EVIOCGBIT(0, EV_MAX), evtype_bitmask) < 0) { pa_log("EVIOCGBIT failed: %s", pa_cstrerror(errno)); goto fail; } if (!test_bit(EV_KEY, evtype_bitmask)) { pa_log("Device has no keys."); goto fail; } u->io = m->core->mainloop->io_new(m->core->mainloop, u->fd, PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP, io_callback, u); pa_modargs_free(ma); return 0; fail: if (ma) pa_modargs_free(ma); pa__done(m); return -1; }
void evtest_test(const char* filename) { int fd, rd, i, j, k; struct input_event ev[64]; int version; unsigned short id[4]; unsigned long bit[EV_MAX][NBITS(KEY_MAX)]; char name[256] = "Unknown"; int abs[5]; if ((fd = open(filename, O_RDONLY)) < 0) { perror("evtest"); exit(1); } if (ioctl(fd, EVIOCGVERSION, &version)) { perror("evtest: can't get version"); exit(1); } printf("Input driver version is %d.%d.%d\n", version >> 16, (version >> 8) & 0xff, version & 0xff); ioctl(fd, EVIOCGID, id); printf("Input device ID: bus 0x%x vendor 0x%x product 0x%x version 0x%x\n", id[ID_BUS], id[ID_VENDOR], id[ID_PRODUCT], id[ID_VERSION]); ioctl(fd, EVIOCGNAME(sizeof(name)), name); printf("Input device name: \"%s\"\n", name); memset(bit, 0, sizeof(bit)); ioctl(fd, EVIOCGBIT(0, EV_MAX), bit[0]); printf("Supported events:\n"); for (i = 0; i < EV_MAX; i++) if (test_bit(i, bit[0])) { printf(" Event type %d (%s)\n", i, events[i] ? events[i] : "?"); ioctl(fd, EVIOCGBIT(i, KEY_MAX), bit[i]); for (j = 0; j < KEY_MAX; j++) if (test_bit(j, bit[i])) { printf(" Event code %d (%s)\n", j, names[i] ? (names[i][j] ? names[i][j] : "?") : "?"); if (i == EV_ABS) { ioctl(fd, EVIOCGABS(j), abs); for (k = 0; k < 5; k++) if ((k < 3) || abs[k]) printf(" %s %6d\n", absval[k], abs[k]); } } } printf("Testing ... (interrupt to exit)\n"); while (1) { rd = read(fd, ev, sizeof(struct input_event) * 64); if (rd < (int) sizeof(struct input_event)) { printf("yyy\n"); perror("\nevtest: error reading"); exit (1); } for (i = 0; i < rd / sizeof(struct input_event); i++) printf("Event: time %ld.%06ld, type %d (%s), code %d (%s), value %d\n", ev[i].time.tv_sec, ev[i].time.tv_usec, ev[i].type, events[ev[i].type] ? events[ev[i].type] : "?", ev[i].code, names[ev[i].type] ? (names[ev[i].type][ev[i].code] ? names[ev[i].type][ev[i].code] : "?") : "?", ev[i].value); } }
bool QDeviceDiscoveryStatic::checkDeviceType(const QString &device) { int fd = QT_OPEN(device.toLocal8Bit().constData(), O_RDONLY | O_NDELAY, 0); if (Q_UNLIKELY(fd == -1)) { qWarning() << "Device discovery cannot open device" << device; return false; } qCDebug(lcDD) << "doing static device discovery for " << device; if ((m_types & Device_DRM) && device.contains(QLatin1String(QT_DRM_DEVICE_PREFIX))) { QT_CLOSE(fd); return true; } long bitsAbs[LONG_FIELD_SIZE(ABS_CNT)]; long bitsKey[LONG_FIELD_SIZE(KEY_CNT)]; long bitsRel[LONG_FIELD_SIZE(REL_CNT)]; memset(bitsAbs, 0, sizeof(bitsAbs)); memset(bitsKey, 0, sizeof(bitsKey)); memset(bitsRel, 0, sizeof(bitsRel)); ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(bitsAbs)), bitsAbs); ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(bitsKey)), bitsKey); ioctl(fd, EVIOCGBIT(EV_REL, sizeof(bitsRel)), bitsRel); QT_CLOSE(fd); if ((m_types & Device_Keyboard)) { if (testBit(KEY_Q, bitsKey)) { qCDebug(lcDD) << "Found keyboard at" << device; return true; } } if ((m_types & Device_Mouse)) { if (testBit(REL_X, bitsRel) && testBit(REL_Y, bitsRel) && testBit(BTN_MOUSE, bitsKey)) { qCDebug(lcDD) << "Found mouse at" << device; return true; } } if ((m_types & (Device_Touchpad | Device_Touchscreen))) { if (testBit(ABS_X, bitsAbs) && testBit(ABS_Y, bitsAbs)) { if ((m_types & Device_Touchpad) && testBit(BTN_TOOL_FINGER, bitsKey)) { qCDebug(lcDD) << "Found touchpad at" << device; return true; } else if ((m_types & Device_Touchscreen) && testBit(BTN_TOUCH, bitsKey)) { qCDebug(lcDD) << "Found touchscreen at" << device; return true; } else if ((m_types & Device_Tablet) && (testBit(BTN_STYLUS, bitsKey) || testBit(BTN_TOOL_PEN, bitsKey))) { qCDebug(lcDD) << "Found tablet at" << device; return true; } } else if (testBit(ABS_MT_POSITION_X, bitsAbs) && testBit(ABS_MT_POSITION_Y, bitsAbs)) { qCDebug(lcDD) << "Found new-style touchscreen at" << device; return true; } } if ((m_types & Device_Joystick)) { if (testBit(BTN_A, bitsKey) || testBit(BTN_TRIGGER, bitsKey) || testBit(ABS_RX, bitsAbs)) { qCDebug(lcDD) << "Found joystick/gamepad at" << device; return true; } } return false; }
void evtest_info(const char* filename, int verbose) { int fd; unsigned short id[4]; char name[256] = "Unknown"; if ((fd = open(filename, O_RDONLY)) < 0) { perror(filename); } else { int i, j, k; int version; if (ioctl(fd, EVIOCGVERSION, &version)) { perror("evtest: can't get version"); exit(1); } unsigned long bit[EV_MAX][NBITS(KEY_MAX)]; ioctl(fd, EVIOCGID, id); ioctl(fd, EVIOCGNAME(sizeof(name)), name); memset(bit, 0, sizeof(bit)); ioctl(fd, EVIOCGBIT(0, EV_MAX), bit[0]); if (!verbose) { printf("%s\t\"%s\"\n", filename, name); } else { printf("Input device file: %s\n", filename); printf("Input device name: \"%s\"\n", name); printf("Input driver version is %d.%d.%d\n", version >> 16, (version >> 8) & 0xff, version & 0xff); printf("Input device ID: bus 0x%x vendor 0x%x product 0x%x version 0x%x\n", id[ID_BUS], id[ID_VENDOR], id[ID_PRODUCT], id[ID_VERSION]); printf("Supported events:\n"); for (i = 0; i < EV_MAX; i++) if (test_bit(i, bit[0])) { printf(" Event type %d (%s)\n", i, events[i] ? events[i] : "?"); ioctl(fd, EVIOCGBIT(i, KEY_MAX), bit[i]); for (j = 0; j < KEY_MAX; j++) if (test_bit(j, bit[i])) { printf(" Event code %d (%s)\n", j, names[i] ? (names[i][j] ? names[i][j] : "?") : "?"); if (i == EV_ABS) { int abs[5]; ioctl(fd, EVIOCGABS(j), abs); for (k = 0; k < 5; k++) if ((k < 3) || abs[k]) printf(" %s %6d\n", absval[k], abs[k]); } } } putchar('\n'); } } }
int PIGU_detect_device(const char *device, PIGU_device_info_t *info) { uint32_t types[EV_MAX]; uint32_t events[(KEY_MAX-1)/32+1]; int fd = open(device, O_RDONLY | O_NONBLOCK); if(fd<0) return -1; memset(info, 0, sizeof(PIGU_device_info_t)); info->fd = fd; // get device name ioctl(fd, EVIOCGNAME(sizeof(info->name)), info->name); // query supported event types memset(types, 0, sizeof(types)); ioctl(fd, EVIOCGBIT(0, EV_MAX), types); int key_count = 0; int mouse_button_count = 0; int joystick_button_count = 0; int gamepad_button_count = 0; PIGU_axis_data_t axes; PIGU_init_axis_data(&axes); PIGU_button_data_t buttons; PIGU_init_button_data(&buttons); if(PIGU_get_bit(types, EV_KEY)) { // count events memset(events, 0, sizeof(events)); ioctl(fd, EVIOCGBIT(EV_KEY, KEY_MAX), events); int j = 0; for(;j<BTN_MISC;++j) if(PIGU_get_bit(events, j)) key_count++; j = BTN_MOUSE; // skip misc buttons for(;j<BTN_JOYSTICK;++j) if(PIGU_get_bit(events, j)) { mouse_button_count++; if(j-BTN_MOUSE>=16) continue; buttons.map[buttons.count] = j-BTN_MOUSE; buttons.count++; } for(;j<BTN_GAMEPAD;++j) if(PIGU_get_bit(events, j)) { joystick_button_count++; if(j-BTN_JOYSTICK>=16) continue; buttons.map[buttons.count] = j-BTN_JOYSTICK; buttons.count++; } for(;j<BTN_DIGI;++j) if(PIGU_get_bit(events, j)) { gamepad_button_count++; if(j-BTN_GAMEPAD>=16) continue; buttons.map[buttons.count] = j-BTN_GAMEPAD; buttons.count++; } } if(PIGU_get_bit(types, EV_ABS)) { struct input_absinfo abs; memset(events, 0, sizeof(events)); ioctl(fd, EVIOCGBIT(EV_ABS, KEY_MAX), events); int j = 0; for(;j<32;++j) if(PIGU_get_bit(events, j)) { axes.map[axes.count] = j; ioctl(fd, EVIOCGABS(j), &abs); axes.position[j] = abs.value; axes.min[j] = abs.minimum; axes.max[j] = abs.maximum; axes.count++; } } // we simply assume that a device that reports gamepad events // is actually a gamepad... a device that reports different types // of events will simply detected according to the order of this // if chain here. info->type = PIGU_UNKNOWN; if(gamepad_button_count > 0) { info->type = PIGU_GAMEPAD; info->controller.buttons = buttons; info->controller.axes = axes; } else if(joystick_button_count > 0) { info->type = PIGU_JOYSTICK; info->controller.buttons = buttons; info->controller.axes = axes; } else if(mouse_button_count > 0) { info->type = PIGU_MOUSE; info->mouse.buttons = buttons; } else if(key_count > 0) { info->keyboard.keys = key_count; info->type = PIGU_KEYBOARD; } else { // no idea what it is so we ignore it // touch screen devices probably end up here atm close(info->fd); } return 0; }
static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], bool test) { struct udev_list_entry *entry; unsigned release[1024]; unsigned release_count = 0; _cleanup_close_ int fd = -1; const char *node; int has_abs = -1; node = udev_device_get_devnode(dev); if (!node) { log_error("No device node for \"%s\"", udev_device_get_syspath(dev)); return EXIT_FAILURE; } udev_list_entry_foreach(entry, udev_device_get_properties_list_entry(dev)) { const char *key; char *endptr; key = udev_list_entry_get_name(entry); if (startswith(key, "KEYBOARD_KEY_")) { const char *keycode; unsigned scancode; /* KEYBOARD_KEY_<hex scan code>=<key identifier string> */ scancode = strtoul(key + 13, &endptr, 16); if (endptr[0] != '\0') { log_warning("Unable to parse scan code from \"%s\"", key); continue; } keycode = udev_list_entry_get_value(entry); /* a leading '!' needs a force-release entry */ if (keycode[0] == '!') { keycode++; release[release_count] = scancode; if (release_count < ELEMENTSOF(release)-1) release_count++; if (keycode[0] == '\0') continue; } if (fd == -1) { fd = open_device(node); if (fd < 0) return EXIT_FAILURE; } map_keycode(fd, node, scancode, keycode); } else if (startswith(key, "EVDEV_ABS_")) { unsigned evcode; /* EVDEV_ABS_<EV_ABS code>=<min>:<max>:<res>:<fuzz>:<flat> */ evcode = strtoul(key + 10, &endptr, 16); if (endptr[0] != '\0') { log_warning("Unable to parse EV_ABS code from \"%s\"", key); continue; } if (fd == -1) { fd = open_device(node); if (fd < 0) return EXIT_FAILURE; } if (has_abs == -1) { unsigned long bits; int rc; rc = ioctl(fd, EVIOCGBIT(0, sizeof(bits)), &bits); if (rc < 0) { log_error_errno(errno, "Unable to EVIOCGBIT device \"%s\"", node); return EXIT_FAILURE; } has_abs = !!(bits & (1 << EV_ABS)); if (!has_abs) log_warning("EVDEV_ABS override set but no EV_ABS present on device \"%s\"", node); } if (!has_abs) continue; override_abs(fd, node, evcode, udev_list_entry_get_value(entry)); } else if (streq(key, "POINTINGSTICK_SENSITIVITY")) set_trackpoint_sensitivity(dev, udev_list_entry_get_value(entry)); } /* install list of force-release codes */ if (release_count > 0) install_force_release(dev, release, release_count); return EXIT_SUCCESS; }
int open_dev_usb(struct device *dev) { int i; struct input_absinfo absinfo; unsigned char evtype_mask[(EV_MAX + 7) / 8]; if((dev->fd = open(dev->path, O_RDWR)) == -1) { if((dev->fd = open(dev->path, O_RDONLY)) == -1) { perror("failed to open device"); return -1; } fprintf(stderr, "opened device read-only, LEDs won't work\n"); } if(ioctl(dev->fd, EVIOCGNAME(sizeof dev->name), dev->name) == -1) { perror("EVIOCGNAME ioctl failed"); strcpy(dev->name, "unknown"); } printf("device name: %s\n", dev->name); /* get number of axes */ dev->num_axes = 6; /* default to regular 6dof controller axis count */ if(ioctl(dev->fd, EVIOCGBIT(EV_ABS, sizeof evtype_mask), evtype_mask) == 0) { dev->num_axes = 0; for(i=0; i<ABS_CNT; i++) { int idx = i / 8; int bit = i % 8; if(evtype_mask[idx] & (1 << bit)) { dev->num_axes++; } else { break; } } } if(verbose) { printf(" Number of axes: %d\n", dev->num_axes); } dev->minval = malloc(dev->num_axes * sizeof *dev->minval); dev->maxval = malloc(dev->num_axes * sizeof *dev->maxval); dev->fuzz = malloc(dev->num_axes * sizeof *dev->fuzz); if(!dev->minval || !dev->maxval || !dev->fuzz) { perror("failed to allocate memory"); return -1; } /* if the device is an absolute device, find the minimum and maximum axis values */ for(i=0; i<dev->num_axes; i++) { dev->minval[i] = DEF_MINVAL; dev->maxval[i] = DEF_MAXVAL; dev->fuzz[i] = 0; if(ioctl(dev->fd, EVIOCGABS(i), &absinfo) == 0) { dev->minval[i] = absinfo.minimum; dev->maxval[i] = absinfo.maximum; dev->fuzz[i] = absinfo.fuzz; if(verbose) { printf(" Axis %d value range: %d - %d (fuzz: %d)\n", i, dev->minval[i], dev->maxval[i], dev->fuzz[i]); } } } /*if(ioctl(dev->fd, EVIOCGBIT(0, sizeof(evtype_mask)), evtype_mask) == -1) { perror("EVIOCGBIT ioctl failed\n"); close(dev->fd); return -1; }*/ if(cfg.grab_device) { int grab = 1; /* try to grab the device */ if(ioctl(dev->fd, EVIOCGRAB, &grab) == -1) { perror("failed to grab the device"); } } /* set non-blocking */ fcntl(dev->fd, F_SETFL, fcntl(dev->fd, F_GETFL) | O_NONBLOCK); if(cfg.led) { set_led_evdev(dev, 1); } /* fill the device function pointers */ dev->close = close_evdev; dev->read = read_evdev; dev->set_led = set_led_evdev; return 0; }
I_NOSTATE(USBDEVFS_RESETEP, success), I_NOSTATE(USBDEVFS_GETDRIVER, enodata), I_NOSTATE(USBDEVFS_IOCTL, enotty), 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 */
int main (int argc, char **argv) { int fd, rd, i, j, k; struct input_event ev[64]; int version; unsigned short id[4]; unsigned long bit[EV_MAX][NBITS(KEY_MAX)]; char name[256] = "Unknown"; int abs[5]; if (argc < 2) { printf("Usage: evtest /dev/input/eventX\n"); printf("Where X = input device number\n"); return 1; } if ((fd = open(argv[argc - 1], O_RDONLY)) < 0) { perror("evtest"); return 1; } if (ioctl(fd, EVIOCGVERSION, &version)) { perror("evtest: can't get version"); return 1; } printf("Input driver version is %d.%d.%d\n", version >> 16, (version >> 8) & 0xff, version & 0xff); ioctl(fd, EVIOCGID, id); printf("Input device ID: bus 0x%x vendor 0x%x product 0x%x version 0x%x\n", id[ID_BUS], id[ID_VENDOR], id[ID_PRODUCT], id[ID_VERSION]); ioctl(fd, EVIOCGNAME(sizeof(name)), name); printf("Input device name: \"%s\"\n", name); memset(bit, 0, sizeof(bit)); ioctl(fd, EVIOCGBIT(0, EV_MAX), bit[0]); printf("Supported events:\n"); for (i = 0; i < EV_MAX; i++) if (test_bit(i, bit[0])) { printf(" Event type %d (%s)\n", i, events[i] ? events[i] : "?"); if (!i) continue; ioctl(fd, EVIOCGBIT(i, KEY_MAX), bit[i]); for (j = 0; j < KEY_MAX; j++) if (test_bit(j, bit[i])) { printf(" Event code %d (%s)\n", j, names[i] ? (names[i][j] ? names[i][j] : "?") : "?"); if (i == EV_ABS) { ioctl(fd, EVIOCGABS(j), abs); for (k = 0; k < 5; k++) if ((k < 3) || abs[k]) printf(" %s %6d\n", absval[k], abs[k]); } } } printf("Testing ... (interrupt to exit)\n"); while (1) { rd = read(fd, ev, sizeof(struct input_event) * 64); if (rd < (int) sizeof(struct input_event)) { printf("yyy\n"); perror("\nevtest: error reading"); return 1; } for (i = 0; i < rd / sizeof(struct input_event); i++) if (ev[i].type == EV_SYN) { printf("Event: time %ld.%06ld, -------------- %s ------------\n", ev[i].time.tv_sec, ev[i].time.tv_usec, ev[i].code ? "Config Sync" : "Report Sync" ); } else if (ev[i].type == EV_MSC && (ev[i].code == MSC_RAW || ev[i].code == MSC_SCAN)) { printf("Event: time %ld.%06ld, type %d (%s), code %d (%s), value %02x\n", ev[i].time.tv_sec, ev[i].time.tv_usec, ev[i].type, events[ev[i].type] ? events[ev[i].type] : "?", ev[i].code, names[ev[i].type] ? (names[ev[i].type][ev[i].code] ? names[ev[i].type][ev[i].code] : "?") : "?", ev[i].value); } else { printf("Event: time %ld.%06ld, type %d (%s), code %d (%s), value %d\n", ev[i].time.tv_sec, ev[i].time.tv_usec, ev[i].type, events[ev[i].type] ? events[ev[i].type] : "?", ev[i].code, names[ev[i].type] ? (names[ev[i].type][ev[i].code] ? names[ev[i].type][ev[i].code] : "?") : "?", ev[i].value); } } }
void Gamepad_detectDevices() { struct input_id id; DIR * dev_input; struct dirent * entity; unsigned int charsConsumed; int num; int fd; int evCapBits[(EV_CNT - 1) / sizeof(int) * 8 + 1]; int evKeyBits[(KEY_CNT - 1) / sizeof(int) * 8 + 1]; int evAbsBits[(ABS_CNT - 1) / sizeof(int) * 8 + 1]; char fileName[PATH_MAX]; bool duplicate; unsigned int gamepadIndex; struct stat statBuf; struct Gamepad_device * deviceRecord; struct Gamepad_devicePrivate * deviceRecordPrivate; char name[128]; char * description; int bit; time_t currentTime; static time_t lastInputStatTime; if (!inited) { return; } pthread_mutex_lock(&devicesMutex); dev_input = opendir("/dev/input"); currentTime = time(NULL); if (dev_input != NULL) { while ((entity = readdir(dev_input)) != NULL) { charsConsumed = 0; if (sscanf(entity->d_name, "event%d%n", &num, &charsConsumed) && charsConsumed == strlen(entity->d_name)) { snprintf(fileName, PATH_MAX, "/dev/input/%s", entity->d_name); if (stat(fileName, &statBuf) || statBuf.st_mtime < lastInputStatTime) { continue; } duplicate = false; for (gamepadIndex = 0; gamepadIndex < numDevices; gamepadIndex++) { if (!strcmp(((struct Gamepad_devicePrivate *) devices[gamepadIndex]->privateData)->path, fileName)) { duplicate = true; break; } } if (duplicate) { continue; } fd = open(fileName, O_RDONLY, 0); memset(evCapBits, 0, sizeof(evCapBits)); memset(evKeyBits, 0, sizeof(evKeyBits)); memset(evAbsBits, 0, sizeof(evAbsBits)); if (ioctl(fd, EVIOCGBIT(0, sizeof(evCapBits)), evCapBits) < 0 || ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(evKeyBits)), evKeyBits) < 0 || ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(evAbsBits)), evAbsBits) < 0) { close(fd); continue; } if (!test_bit(EV_KEY, evCapBits) || !test_bit(EV_ABS, evCapBits) || !test_bit(ABS_X, evAbsBits) || !test_bit(ABS_Y, evAbsBits) || (!test_bit(BTN_TRIGGER, evKeyBits) && !test_bit(BTN_A, evKeyBits) && !test_bit(BTN_1, evKeyBits))) { close(fd); continue; } deviceRecord = (Gamepad_device *)malloc(sizeof(struct Gamepad_device)); deviceRecord->deviceID = nextDeviceID++; devices = (Gamepad_device **)realloc(devices, sizeof(struct Gamepad_device *) * (numDevices + 1)); devices[numDevices++] = deviceRecord; deviceRecordPrivate = (Gamepad_devicePrivate *)malloc(sizeof(struct Gamepad_devicePrivate)); deviceRecordPrivate->fd = fd; deviceRecordPrivate->path = (char *)malloc(strlen(fileName) + 1); strcpy(deviceRecordPrivate->path, fileName); memset(deviceRecordPrivate->buttonMap, 0xFF, sizeof(deviceRecordPrivate->buttonMap)); memset(deviceRecordPrivate->axisMap, 0xFF, sizeof(deviceRecordPrivate->axisMap)); deviceRecord->privateData = deviceRecordPrivate; if (ioctl(fd, EVIOCGNAME(sizeof(name)), name) > 0) { description = (char *)malloc(strlen(name) + 1); strcpy(description, name); } else { description = (char *)malloc(strlen(fileName) + 1); strcpy(description, fileName); } deviceRecord->description = description; if (!ioctl(fd, EVIOCGID, &id)) { deviceRecord->vendorID = id.vendor; deviceRecord->productID = id.product; } else { deviceRecord->vendorID = deviceRecord->productID = 0; } memset(evKeyBits, 0, sizeof(evKeyBits)); memset(evAbsBits, 0, sizeof(evAbsBits)); ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(evKeyBits)), evKeyBits); ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(evAbsBits)), evAbsBits); deviceRecord->numAxes = 0; for (bit = 0; bit < ABS_CNT; bit++) { if (test_bit(bit, evAbsBits)) { if (ioctl(fd, EVIOCGABS(bit), &deviceRecordPrivate->axisInfo[bit]) < 0 || deviceRecordPrivate->axisInfo[bit].minimum == deviceRecordPrivate->axisInfo[bit].maximum) { continue; } deviceRecordPrivate->axisMap[bit] = deviceRecord->numAxes; deviceRecord->numAxes++; } } deviceRecord->numButtons = 0; for (bit = BTN_MISC; bit < KEY_CNT; bit++) { if (test_bit(bit, evKeyBits)) { deviceRecordPrivate->buttonMap[bit - BTN_MISC] = deviceRecord->numButtons; deviceRecord->numButtons++; } } deviceRecord->axisStates = (float *)calloc(sizeof(float), deviceRecord->numAxes); deviceRecord->buttonStates = (bool *)calloc(sizeof(bool), deviceRecord->numButtons); if (Gamepad_deviceAttachCallback != NULL) { Gamepad_deviceAttachCallback(deviceRecord, Gamepad_deviceAttachContext); } pthread_create(&deviceRecordPrivate->thread, NULL, deviceThread, deviceRecord); } } closedir(dev_input); } lastInputStatTime = currentTime; pthread_mutex_unlock(&devicesMutex); }
static int evdev_try_add(int fd) { unsigned short id[4]; unsigned long bit[EV_MAX][NBITS(KEY_MAX)]; char devname[256]; int ret; devname[0] = '\0'; ioctl(fd, EVIOCGNAME(sizeof(devname)), devname); logdebug("\nInvestigating evdev [%s]\n", devname); ioctl(fd, EVIOCGID, id); if ((!evdev_is_internal(id)) #ifndef __powerpc__ && !(appleir_cfg.enabled && evdev_is_appleir(id)) #endif && !(has_kbd_backlight() && evdev_is_lidswitch(id)) && !(evdev_is_mouseemu(id)) && !(evdev_is_extkbd(id))) { logdebug("Discarding evdev: bus 0x%04x, vid 0x%04x, pid 0x%04x\n", id[ID_BUS], id[ID_VENDOR], id[ID_PRODUCT]); close(fd); return -1; } memset(bit, 0, sizeof(bit)); ioctl(fd, EVIOCGBIT(0, EV_MAX), bit[0]); if (!test_bit(EV_KEY, bit[0])) { logdebug("evdev: no EV_KEY event type (not a keyboard)\n"); if (!test_bit(EV_SW, bit[0])) { logdebug("Discarding evdev: no EV_SW event type (not a switch)\n"); close(fd); return -1; } } /* Wireless keyboards advertise EV_ABS events, single them out */ else if (test_bit(EV_ABS, bit[0]) && !(evdev_is_extkbd_alu_wl(id))) { logdebug("Discarding evdev with EV_ABS event type (mouse/trackpad)\n"); close(fd); return -1; } /* There are 2 keyboards, but one of them only has the eject key; the real keyboard has all the keys and the LEDs. Checking for the LEDs is a quick way of identifying the keyboard we want. */ if (test_bit(EV_LED, bit[0]) && evdev_is_internal(id)) { logdebug(" -> Internal keyboard\n"); internal_kbd_fd = fd; } ret = evloop_add(fd, EPOLLIN, evdev_process_events); if (ret < 0) { logmsg(LOG_ERR, "Could not add device to event loop"); if (fd == internal_kbd_fd) internal_kbd_fd = -1; close(fd); return -1; } return 0; }
static int prepareUinputInstance (UinputObject *uinput, int keyboard) { { int type = EV_KEY; BITMASK(mask, KEY_MAX+1, char); int size = ioctl(keyboard, EVIOCGBIT(type, sizeof(mask)), mask); if (size == -1) { logSystemError("ioctl[EVIOCGBIT]"); return 0; } { int count = size * 8; { int key = KEY_ENTER; if (key >= count) return 0; if (!BITMASK_TEST(mask, key)) return 0; } if (!enableUinputEventType(uinput, type)) return 0; for (int key=0; key<count; key+=1) { if (BITMASK_TEST(mask, key)) { if (!enableUinputKey(uinput, key)) { return 0; } } } } } if (!enableUinputEventType(uinput, EV_REP)) return 0; if (!createUinputDevice(uinput)) return 0; { int properties[2]; if (ioctl(keyboard, EVIOCGREP, properties) != -1) { if (!writeRepeatDelay(uinput, properties[0])) return 0; if (!writeRepeatPeriod(uinput, properties[1])) return 0; } } { BITMASK(mask, KEY_MAX+1, char); int size = ioctl(keyboard, EVIOCGKEY(sizeof(mask)), mask); if (size != -1) { int count = size * 8; for (int key=0; key<count; key+=1) { if (BITMASK_TEST(mask, key)) { logMessage(LOG_WARNING, "key already pressed: %d", key); } } } } return 1; }
/* * Open the device, fill out information about it, * allocate and fill private data, start input thread. */ bool CLinuxInputDevice::Open() { int fd, ret; unsigned long ledbit[NBITS(LED_CNT)]; /* open device */ fd = open(m_fileName.c_str(), O_RDWR | O_NONBLOCK); if (fd < 0) { CLog::Log(LOGERROR, "CLinuxInputDevice: could not open device: %s\n", m_fileName.c_str()); return false; } /* grab device */ ret = ioctl(fd, EVIOCGRAB, 1); if (ret && errno != EINVAL) { CLog::Log(LOGERROR, "CLinuxInputDevice: could not grab device: %s\n", m_fileName.c_str()); close(fd); return false; } // Set the socket to non-blocking int opts = 0; if ((opts = fcntl(fd, F_GETFL)) < 0) { CLog::Log(LOGERROR, "CLinuxInputDevice %s: fcntl(F_GETFL) failed: %s", __FUNCTION__ , strerror(errno)); close(fd); return false; } opts = (opts | O_NONBLOCK); if (fcntl(fd, F_SETFL, opts) < 0) { CLog::Log(LOGERROR, "CLinuxInputDevice %s: fcntl(F_SETFL) failed: %s", __FUNCTION__, strerror(errno)); close(fd); return false; } /* fill device info structure */ GetInfo(fd); if (m_deviceType & LI_DEVICE_KEYBOARD) SetupKeyboardAutoRepeat(fd); m_fd = fd; m_vt_fd = -1; if (m_deviceMinKeyCode >= 0 && m_deviceMaxKeyCode >= m_deviceMinKeyCode) { if (m_vt_fd < 0) m_vt_fd = open("/dev/tty0", O_RDWR | O_NOCTTY); if (m_vt_fd < 0) CLog::Log(LOGWARNING, "no keymap support (requires /dev/tty0 - CONFIG_VT)"); } /* check if the device has LEDs */ ret = ioctl(fd, EVIOCGBIT(EV_LED, sizeof(ledbit)), ledbit); if (ret < 0) CLog::Log(LOGWARNING, "DirectFB/linux_input: could not get LED bits" ); else m_hasLeds = test_bit( LED_SCROLLL, ledbit ) || test_bit( LED_NUML, ledbit ) || test_bit( LED_CAPSL, ledbit ); if (m_hasLeds) { /* get LED state */ ret = ioctl(fd, EVIOCGLED(sizeof(m_ledState)), m_ledState); if (ret < 0) { CLog::Log(LOGERROR, "DirectFB/linux_input: could not get LED state"); goto driver_open_device_error; } /* turn off LEDs */ SetLed(LED_SCROLLL, 0); SetLed(LED_NUML, 0); SetLed(LED_CAPSL, 0); } return true; driver_open_device_error: ioctl(fd, EVIOCGRAB, 0); if (m_vt_fd >= 0) { close(m_vt_fd); m_vt_fd = -1; } close(fd); m_fd = -1; return false; }
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); fd = -1; 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; } } for (int i=0; i<((BTN_GAMEPAD+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 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); } // See if this device has a gamepad. for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) { if (hasKeycode(device, GAMEPAD_KEYCODES[i])) { device->classes |= CLASS_GAMEPAD; break; } } 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 int print_possible_events(int fd, int print_flags) { uint8_t *bits = NULL; ssize_t bits_size = 0; const char* label; int i, j, k; int res, res2; struct label* bit_labels; const char *bit_label; printf(" events:\n"); for(i = EV_KEY; i <= EV_MAX; i++) { // skip EV_SYN since we cannot query its available codes int count = 0; while(1) { res = ioctl(fd, EVIOCGBIT(i, bits_size), bits); if(res < bits_size) break; bits_size = res + 16; bits = realloc(bits, bits_size * 2); if(bits == NULL) { fprintf(stderr, "failed to allocate buffer of size %d\n", (int)bits_size); return 1; } } res2 = 0; switch(i) { case EV_KEY: res2 = ioctl(fd, EVIOCGKEY(res), bits + bits_size); label = "KEY"; bit_labels = key_labels; break; case EV_REL: label = "REL"; bit_labels = rel_labels; break; case EV_ABS: label = "ABS"; bit_labels = abs_labels; break; case EV_MSC: label = "MSC"; bit_labels = msc_labels; break; case EV_LED: res2 = ioctl(fd, EVIOCGLED(res), bits + bits_size); label = "LED"; bit_labels = led_labels; break; case EV_SND: res2 = ioctl(fd, EVIOCGSND(res), bits + bits_size); label = "SND"; bit_labels = snd_labels; break; case EV_SW: res2 = ioctl(fd, EVIOCGSW(bits_size), bits + bits_size); label = "SW "; bit_labels = sw_labels; break; case EV_REP: label = "REP"; bit_labels = rep_labels; break; case EV_FF: label = "FF "; bit_labels = ff_labels; break; case EV_PWR: label = "PWR"; bit_labels = NULL; break; case EV_FF_STATUS: label = "FFS"; bit_labels = ff_status_labels; break; default: res2 = 0; label = "???"; bit_labels = NULL; } for(j = 0; j < res; j++) { for(k = 0; k < 8; k++) if(bits[j] & 1 << k) { char down; if(j < res2 && (bits[j + bits_size] & 1 << k)) down = '*'; else down = ' '; if(count == 0) printf(" %s (%04x):", label, i); else if((count & (print_flags & PRINT_LABELS ? 0x3 : 0x7)) == 0 || i == EV_ABS) printf("\n "); if(bit_labels && (print_flags & PRINT_LABELS)) { bit_label = get_label(bit_labels, j * 8 + k); if(bit_label) printf(" %.20s%c%*s", bit_label, down, 20 - strlen(bit_label), ""); else printf(" %04x%c ", j * 8 + k, down); } else { printf(" %04x%c", j * 8 + k, down); } if(i == EV_ABS) { struct input_absinfo abs; if(ioctl(fd, EVIOCGABS(j * 8 + k), &abs) == 0) { printf(" : value %d, min %d, max %d, fuzz %d, flat %d, resolution %d", abs.value, abs.minimum, abs.maximum, abs.fuzz, abs.flat, abs.resolution); } } count++; } } if(count) printf("\n"); } free(bits); return 0; }
/* * 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; }
/* Initialization. This should run automatically. */ void __attribute__ ((constructor)) joyrumble_init(void) { #ifdef DEBUG printf("INIT\n"); #endif /* event_fd is the handle of the event file */ int event_fd; int count=0, j=0; /* this will hold the path of files while we do some checks */ char tmp[128]; for (count = 0; count < MAXJOY; count++) { sprintf(tmp,"/dev/input/js%d",count); /* Check if joystick device exists */ if (file_exists(tmp)==1){ lastjoy=count; for (j = 0; j <= 99; j++) { /* Try to discover the corresponding event number */ sprintf(tmp,"/sys/class/input/js%d/device/event%d",count,j); if (dir_exists(tmp)==1){ /* Store the full path of the event file in the eventfile[] array */ sprintf(tmp,"/dev/input/event%d",j); eventfile[count]=(char *)calloc(sizeof(tmp),sizeof(char)); sprintf(eventfile[count], "%s", tmp); #ifdef DEBUG printf("%s", eventfile[count]); printf("\n"); #endif } } } // else printf("Joystick does not exist!"); } #ifdef DEBUG printf("lastjoy=%d\n",lastjoy); #endif for (count = 0; count <= lastjoy ; count++) { hasrumble[count]=0; /* Prepare the effects */ effects[count].type = FF_RUMBLE; effects[count].u.rumble.strong_magnitude = 65535; effects[count].u.rumble.weak_magnitude = 65535; effects[count].replay.length = 1000; effects[count].replay.delay = 0; effects[count].id = -1; /* Prepare the stop event */ stop[count].type = EV_FF; stop[count].code = effects[count].id; stop[count].value = 0; /* Prepare the play event */ play[count].type = EV_FF; play[count].code = effects[count].id; play[count].value = 1; /* Open event file to verify if the device and the drivers support rumble */ event_fd = open(eventfile[count], O_RDWR); if (event_fd < 0) /* Can't acess the event file */ hasrumble[count]=0; else{ if (ioctl(event_fd, EVIOCGBIT(EV_FF, sizeof(unsigned long) * 4), features) == -1) /* This device can't rumble, or the drivers don't support it */ hasrumble[count]=0; else{ if (test_bit(FF_RUMBLE, features)) /* Success! This device can rumble! */ hasrumble[count]=1; } /* Close the event file */ if (event_fd>0) close(event_fd); } #ifdef DEBUG printf("%s", eventfile[count]); if (hasrumble[count]){ printf(" can rumble.\n"); } else{ printf(" can't rumble.\n"); } #endif } /* Initialization is complete */ initialized=1; }
static adv_error joystickb_setup(struct joystick_item_context* item, int f) { unsigned char key_bitmask[KEY_MAX/8 + 1]; unsigned char abs_bitmask[ABS_MAX/8 + 1]; unsigned char rel_bitmask[REL_MAX/8 + 1]; unsigned i; unsigned short device_info[4]; struct button_entry { int code; const char* name; } button_map[] = { #ifdef BTN_TRIGGER { BTN_TRIGGER, "trigger" }, /* joystick */ #endif #ifdef BTN_THUMB { BTN_THUMB, "thumb" }, /* joystick */ #endif #ifdef BTN_THUMB2 { BTN_THUMB2, "thumb2" }, /* joystick */ #endif #ifdef BTN_TOP { BTN_TOP, "top" }, /* joystick */ #endif #ifdef BTN_TOP2 { BTN_TOP2, "top2" }, /* joystick */ #endif #ifdef BTN_PINKIE { BTN_PINKIE, "pinkie" }, /* joystick */ #endif #ifdef BTN_BASE { BTN_BASE, "base" }, /* joystick */ #endif #ifdef BTN_BASE2 { BTN_BASE2, "base2" }, /* joystick */ #endif #ifdef BTN_BASE3 { BTN_BASE3, "base3" }, /* joystick */ #endif #ifdef BTN_BASE4 { BTN_BASE4, "base4" }, /* joystick */ #endif #ifdef BTN_BASE5 { BTN_BASE5, "base5" }, /* joystick */ #endif #ifdef BTN_BASE6 { BTN_BASE6, "base6" }, /* joystick */ #endif #ifdef BTN_DEAD { BTN_DEAD, "dead" }, /* joystick */ #endif #ifdef BTN_A { BTN_A, "a" }, /* gamepad */ #endif #ifdef BTN_B { BTN_B, "b" }, /* gamepad */ #endif #ifdef BTN_C { BTN_C, "c" }, /* gamepad */ #endif #ifdef BTN_X { BTN_X, "x" }, /* gamepad */ #endif #ifdef BTN_Y { BTN_Y, "y" }, /* gamepad */ #endif #ifdef BTN_Z { BTN_Z, "z" }, /* gamepad */ #endif #ifdef BTN_TL { BTN_TL, "tl" }, /* gamepad (top left) */ #endif #ifdef BTN_TR { BTN_TR, "tr" }, /* gamepad (top right) */ #endif #ifdef BTN_TL2 { BTN_TL2, "tl2" }, /* gamepad (top left 2) */ #endif #ifdef BTN_TR2 { BTN_TR2, "tr2" }, /* gamepad (top right 2) */ #endif #ifdef BTN_SELECT { BTN_SELECT, "select" }, /* gamepad */ #endif #ifdef BTN_START { BTN_START, "start" }, /* gamepad */ #endif #ifdef BTN_MODE { BTN_MODE, "mode" }, /* gamepad */ #endif #ifdef BTN_THUMBL { BTN_THUMBL, "thumbl" }, /* gamepad (thumb left) */ #endif #ifdef BTN_THUMBR { BTN_THUMBR, "thumbr" }, /* gamepad (thumb right) */ #endif #ifdef BTN_GEAR_DOWN { BTN_GEAR_DOWN, "gear_down" }, /* wheel */ #endif #ifdef BTN_GEAR_UP { BTN_GEAR_UP, "gear_up" }, /* wheel */ #endif #ifdef BTN_0 { BTN_0, "0" }, /* misc */ #endif #ifdef BTN_1 { BTN_1, "1" }, /* misc */ #endif #ifdef BTN_2 { BTN_2, "2" }, /* misc */ #endif #ifdef BTN_3 { BTN_3, "3" }, /* misc */ #endif #ifdef BTN_4 { BTN_4, "4" }, /* misc */ #endif #ifdef BTN_5 { BTN_5, "5" }, /* misc */ #endif #ifdef BTN_6 { BTN_6, "6" }, /* misc */ #endif #ifdef BTN_7 { BTN_7, "7" }, /* misc */ #endif #ifdef BTN_8 { BTN_8, "8" }, /* misc */ #endif #ifdef BTN_9 { BTN_9, "9" }, /* misc */ #endif #ifdef BTN_LEFT { BTN_LEFT, "left" }, /* ball */ #endif #ifdef BTN_RIGHT { BTN_RIGHT, "right" }, /* ball */ #endif #ifdef BTN_MIDDLE { BTN_MIDDLE, "middle" }, /* ball/lightgun first button */ #endif #ifdef BTN_SIDE { BTN_SIDE, "side" }, /* ball/lightgun second button */ #endif #ifdef BTN_EXTRA { BTN_EXTRA, "extra" }, /* ball */ #endif #ifdef BTN_FORWARD { BTN_FORWARD, "forward" }, /* ball */ #endif #ifdef BTN_BACK { BTN_BACK, "back" } /* ball */ #endif }; /* WARNING: It must be syncronized with the list in event.c */ struct stick_entry { struct axe_entry { int code; const char* name; } axe_map[7]; const char* name; } stick_map[] = { { { { ABS_X, "x" }, { ABS_Y, "y" }, { ABS_Z, "z" }, { ABS_RX, "rx" }, { ABS_RY, "ry" }, { ABS_RZ, "rz" }, { ABS_UNASSIGNED, 0 } }, "stick" }, #ifdef ABS_GAS { { { ABS_GAS, "mono" }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 } }, "gas" }, /* IT:acceleratore */ #endif #ifdef ABS_BRAKE { { { ABS_BRAKE, "mono" }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 } }, "brake" }, /* IT:freno */ #endif #ifdef ABS_WHEEL { { { ABS_WHEEL, "mono" }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 } }, "wheel" }, /* IT:volante */ #endif #ifdef ABS_HAT0X { { { ABS_HAT0X, "x" }, { ABS_HAT0Y, "y" }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 } }, "hat" }, /* IT:mini joystick digitale */ #endif #ifdef ABS_HAT1X { { { ABS_HAT1X, "x" }, { ABS_HAT1Y, "y" }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 } }, "hat2" }, #endif #ifdef ABS_HAT2X { { { ABS_HAT2X, "x" }, { ABS_HAT2Y, "y" }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 } }, "hat3" }, #endif #ifdef ABS_HAT3X { { { ABS_HAT3X, "x" }, { ABS_HAT3Y, "y" }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 } }, "hat4" }, #endif #ifdef ABS_THROTTLE { { { ABS_THROTTLE, "mono" }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 } }, "throttle" }, #endif #ifdef ABS_RUDDER { { { ABS_RUDDER, "mono" }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 } }, "rudder" }, /* IT:timone */ #endif /* { { { ABS_PRESSURE, "mono" }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 } }, "pressure" }, */ /* tablet */ /* { { { ABS_DISTANCE, "mono" }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 } }, "distance" }, */ /* tablet */ /* { { { ABS_TILT_X, "x" }, { ABS_TILT_Y, "y" }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 } }, "tilt" }, */ /* tablet */ /* { { { ABS_VOLUME, "mono" }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 } }, "volume" }, */ /* not an action control */ #ifdef ABS_MISC { { { ABS_MISC, "mono" }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 }, { ABS_UNASSIGNED, 0 } }, "misc" } #endif }; struct rel_entry { int code; const char* name; } rel_map[] = { #ifdef REL_X { REL_X, "x" }, #endif #ifdef REL_Y { REL_Y, "y" }, #endif #ifdef REL_Z { REL_Z, "z" }, #endif #ifdef REL_WHEEL { REL_WHEEL, "wheel" }, /* (IT: rotella del mouse verticale) */ #endif #ifdef REL_HWHEEL { REL_HWHEEL, "hwheel" }, /* (IT: rotella del mouse orizzontale) */ #endif #ifdef REL_DIAL { REL_DIAL, "dial" }, /* (IT: manopola che gira) */ #endif #ifdef REL_MISC { REL_MISC, "misc" } #endif }; item->f = f; #ifdef USE_ACTLABS_HACK item->actlabs_hack_enable = 0; #endif if (ioctl(f, EVIOCGID, &device_info)) { log_std(("event: error in ioctl(EVIOCGID)\n")); item->vendor_id = 0; item->device_id = 0; item->version_id = 0; item->bus_id = 0; } else { item->vendor_id = device_info[ID_VENDOR]; item->device_id = device_info[ID_PRODUCT]; item->version_id = device_info[ID_VERSION]; item->bus_id = device_info[ID_BUS]; } memset(key_bitmask, 0, sizeof(key_bitmask)); if (event_test_bit(EV_KEY, item->evtype_bitmask)) { if (ioctl(f, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) < 0) { log_std(("event: error in ioctl(EVIOCGBIT(EV_KEY,%d))\n", (int)KEY_MAX)); return -1; } } item->button_mac = 0; for(i=0;i<sizeof(button_map)/sizeof(button_map[0]);++i) { if (event_test_bit(button_map[i].code, key_bitmask)) { if (item->button_mac < EVENT_JOYSTICK_BUTTON_MAX) { item->button_map[item->button_mac].code = button_map[i].code; item->button_map[item->button_mac].state = 0; sncpy(item->button_map[item->button_mac].name, sizeof(item->button_map[item->button_mac].name), button_map[i].name); ++item->button_mac; } } } memset(abs_bitmask, 0, sizeof(abs_bitmask)); if (event_test_bit(EV_ABS, item->evtype_bitmask)) { if (ioctl(f, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) < 0) { log_std(("event: error in ioctl(EVIOCGBIT(EV_ABS,%d))\n", (int)ABS_MAX)); return -1; } } item->stick_mac = 0; for(i=0;i<sizeof(stick_map)/sizeof(stick_map[0]);++i) { if (item->stick_mac < EVENT_JOYSTICK_STICK_MAX) { unsigned j; struct joystick_stick_context* stick = item->stick_map + item->stick_mac; stick->axe_mac = 0; sncpy(stick->name, sizeof(stick->name), stick_map[i].name); for(j=0;stick_map[i].axe_map[j].code != ABS_UNASSIGNED;++j) { int code = stick_map[i].axe_map[j].code; if (event_test_bit(code, abs_bitmask)) { if (stick->axe_mac < EVENT_JOYSTICK_AXE_MAX) { struct joystick_axe_context* axe = stick->axe_map + stick->axe_mac; int features[5]; axe->code = code; sncpy(axe->name, sizeof(axe->name), stick_map[i].axe_map[j].name); memset(features, 0, sizeof(features)); if (ioctl(f, EVIOCGABS(code), features) < 0) { axe->min = 0; axe->max = 0; axe->fuzz = 0; axe->flat = 0; axe->digit_low = -32; axe->digit_high = 32; axe->value = 0; axe->value_adj = 0; } else { int middle = (features[1] + features[2]) / 2; int size = features[2] - features[1]; int flat = features[4]; axe->min = features[1]; axe->max = features[2]; axe->fuzz = features[3]; axe->flat = features[4]; axe->digit_low = middle - flat - (size - flat) / 8; axe->digit_high = middle + flat + (size - flat) / 8; axe->value = middle; axe->value_adj = 0; } ++stick->axe_mac; } } } /* save the stick only if it hash some axes */ if (stick->axe_mac) ++item->stick_mac; } } memset(rel_bitmask, 0, sizeof(rel_bitmask)); if (event_test_bit(EV_REL, item->evtype_bitmask)) { if (ioctl(f, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) < 0) { log_std(("event: error in ioctl(EVIOCGBIT(EV_REL,%d))\n", (int)REL_MAX)); return -1; } } item->rel_mac = 0; for(i=0;i<sizeof(rel_map)/sizeof(rel_map[0]);++i) { if (event_test_bit(rel_map[i].code, rel_bitmask)) { if (item->rel_mac < EVENT_JOYSTICK_REL_MAX) { item->rel_map[item->rel_mac].code = rel_map[i].code; item->rel_map[item->rel_mac].value = 0; sncpy(item->rel_map[item->rel_mac].name, sizeof(item->rel_map[item->rel_mac].name), rel_map[i].name); ++item->rel_mac; } } } return 0; }
Joystick_Linux::Joystick_Linux(const char *jsdev_path, const char *evdev_path) : jsdev_fd(-1), evdev_fd(-1) { unsigned char tmp; //printf("%s %s\n", jsdev_path, evdev_path); jsdev_fd = open(jsdev_path, O_RDONLY); if(jsdev_fd == -1) { ErrnoHolder ene(errno); throw MDFN_Error(ene.Errno(), _("Error opening joystick device \"%s\": %s"), jsdev_path, ene.StrError()); } fcntl(jsdev_fd, F_SETFL, fcntl(jsdev_fd, F_GETFL) | O_NONBLOCK); if(evdev_path != NULL) { evdev_fd = open(evdev_path, O_RDWR); if(evdev_fd == -1) { ErrnoHolder ene(errno); if(ene.Errno() == EACCES) { evdev_fd = open(evdev_path, O_RDONLY); if(evdev_fd == -1) { ErrnoHolder ene2(errno); fprintf(stderr, _("WARNING: Failed to open event device \"%s\": %s --- !!!!! BASE JOYSTICK FUNCTIONALITY WILL BE AVAILABLE, BUT FORCE-FEEDBACK(E.G. RUMBLE) WILL BE UNAVAILABLE, AND THE CALCULATED JOYSTICK ID WILL BE DIFFERENT. !!!!!\n"), evdev_path, ene2.StrError()); } else { fprintf(stderr, _("WARNING: Could only open event device \"%s\" for reading, and not reading+writing: %s --- !!!!! FORCE-FEEDBACK(E.G. RUMBLE) WILL BE UNAVAILABLE. !!!!!\n"), evdev_path, ene.StrError()); } } else fprintf(stderr, _("WARNING: Failed to open event device \"%s\": %s --- !!!!! BASE JOYSTICK FUNCTIONALITY WILL BE AVAILABLE, BUT FORCE-FEEDBACK(E.G. RUMBLE) WILL BE UNAVAILABLE, AND THE CALCULATED JOYSTICK ID WILL BE DIFFERENT. !!!!!\n"), evdev_path, ene.StrError()); } } else fprintf(stderr, _("WARNING: Failed to find a valid corresponding event device to joystick device \"%s\" --- !!!!! BASE JOYSTICK FUNCTIONALITY WILL BE AVAILABLE, BUT FORCE-FEEDBACK(E.G. RUMBLE) WILL BE UNAVAILABLE, AND THE CALCULATED JOYSTICK ID WILL BE DIFFERENT. !!!!!\n"), jsdev_path); if(evdev_fd != -1) fcntl(evdev_fd, F_SETFL, fcntl(evdev_fd, F_GETFL) | O_NONBLOCK); num_rel_axes = 0; if(ioctl(jsdev_fd, JSIOCGAXES, &tmp) == -1) { ErrnoHolder ene(errno); throw MDFN_Error(ene.Errno(), _("Failed to get number of axes: %s"), ene.StrError()); } else num_axes = tmp; if(ioctl(jsdev_fd, JSIOCGBUTTONS, &tmp) == -1) { ErrnoHolder ene(errno); throw MDFN_Error(ene.Errno(), _("Failed to get number of buttons: %s"), ene.StrError()); } else num_buttons = tmp; axis_state.resize(num_axes); button_state.resize(num_buttons); memset(name, 0, sizeof(name)); ioctl(jsdev_fd, JSIOCGNAME(sizeof(name) - 1), name); if(name[0] == 0) snprintf(name, sizeof(name), _("%u-button, %u-axis controller"), num_buttons, num_axes); compat_hat_offs = ~0U; CalcOldStyleID(num_axes, 0, 0, num_buttons); if(evdev_fd != -1) { #if 0 uint8 keybits[(KEY_CNT + 7) / 8]; unsigned ev_button_count = 0; memset(keybits, 0, sizeof(keybits)); ioctl(evdev_fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits); for(unsigned kbt = 0; kbt < KEY_CNT; kbt++) { if(keybits[kbt >> 3] & (1 << (kbt & 0x7))) { ev_button_count++; } } printf("moo: %u\n", ev_button_count); #endif uint8 absaxbits[(ABS_CNT + 7) / 8]; unsigned ev_abs_count = 0; unsigned ev_hat_count = 0; memset(absaxbits, 0, sizeof(absaxbits)); ioctl(evdev_fd, EVIOCGBIT(EV_ABS, sizeof(absaxbits)), absaxbits); for(unsigned aat = 0; aat < ABS_CNT; aat++) { if(TestEVBit(absaxbits, aat)) { if(aat >= ABS_HAT0X && aat <= ABS_HAT3Y) { if(compat_hat_offs == ~0U) compat_hat_offs = ev_abs_count; ev_hat_count++; } ev_abs_count++; } } //printf("%u\n", compat_hat_offs); CalcOldStyleID(ev_abs_count - ev_hat_count, 0, ev_hat_count / 2, num_buttons); }
EvdevDevice::EvdevDevice(const std::string& filename) : fd(), version(), relatives(), absolutes(), keys(), name(), device(filename) { fd = open(device.c_str(), O_RDONLY | O_NONBLOCK); if (fd == -1) { throw std::runtime_error(filename + ": " + std::string(strerror(errno))); } if (ioctl(fd, EVIOCGVERSION, &version)) { throw std::runtime_error("Error: EvdevDevice: Couldn't get version for " + filename); } if (1) { // FIXME: Some versions of linux don't have these structs, use arrays there struct input_id id; ioctl(fd, EVIOCGID, &id); printf("Input device ID: bus 0x%x vendor 0x%x product 0x%x version 0x%x\n", id.bustype, id.vendor, id.product, id.vendor); } { // Get the human readable name char c_name[256] = "unknown"; ioctl(fd, EVIOCGNAME(sizeof(c_name)), c_name); name = c_name; log_info("Name: " << name); } { // Read in how many buttons the device has unsigned long bit[EV_MAX][NBITS(KEY_MAX)]; memset(bit, 0, sizeof(bit)); ioctl(fd, EVIOCGBIT(0, EV_MAX), bit[0]); for (int i = 0; i < EV_MAX; i++) { if (test_bit(i, bit[0])) { //printf(" Event type %d (%s)\n", i, events[i] ? events[i] : "?"); if (!i) continue; ioctl(fd, EVIOCGBIT(i, KEY_MAX), bit[i]); for (int j = 0; j < KEY_MAX; j++) { if (test_bit(j, bit[i])) { if (i == EV_KEY) { keys.push_back(Key(j)); } else if (i == EV_ABS) { // FIXME: Some Linuxes don't have these struct struct input_absinfo absinfo; ioctl(fd, EVIOCGABS(j), &absinfo); // FIXME: we are ignoring absinfo.fuzz and // absinfo.flat = deadzone // absinfo.fuzz = values in which range can be considered the same (jitter) absolutes.push_back(Absolute(j, absinfo.minimum, absinfo.maximum, absinfo.value)); } else if (i == EV_REL) { relatives.push_back(Relative(j)); } } } } } } }
status_t EventHub::openDeviceLocked(const char *devicePath) { char buffer[80]; ALOGV("Opening device: %s", devicePath); int fd = open(devicePath, O_RDWR); if(fd < 0) { ALOGE("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) { ALOGI("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)) { ALOGE("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)) { ALOGE("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)) { 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); #if 0 ALOGI("add device %d: %s\n", deviceId, devicePath); ALOGI(" bus: %04x\n" " vendor %04x\n" " product %04x\n" " version %04x\n", identifier.bus, identifier.vendor, identifier.product, identifier.version); ALOGI(" name: \"%s\"\n", identifier.name.string()); ALOGI(" location: \"%s\"\n", identifier.location.string()); ALOGI(" unique id: \"%s\"\n", identifier.uniqueId.string()); ALOGI(" 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. // Mozilla Bug 741038 - support GB touchscreen drivers //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)) { ALOGE("Could not add device fd to epoll instance. errno=%d", errno); delete device; return -1; } 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)); mDevices.add(deviceId, device); device->next = mOpeningDevices; mOpeningDevices = device; return 0; }
// Get the event types and event codes that the input device supports static PyObject * ioctl_capabilities(PyObject *self, PyObject *args) { int fd, ev_type, ev_code; char ev_bits[EV_MAX/8 + 1], code_bits[KEY_MAX/8 + 1]; struct input_absinfo absinfo; int ret = PyArg_ParseTuple(args, "i", &fd); if (!ret) return NULL; // @todo: figure out why fd gets zeroed on an ioctl after the // refactoring and get rid of this workaround const int _fd = fd; // Capabilities is a mapping of supported event types to lists of handled // events e.g: {1: [272, 273, 274, 275], 2: [0, 1, 6, 8]} PyObject* capabilities = PyDict_New(); PyObject* eventcodes = NULL; PyObject* evlong = NULL; PyObject* capability = NULL; PyObject* py_absinfo = NULL; PyObject* absitem = NULL; memset(&ev_bits, 0, sizeof(ev_bits)); if (ioctl(_fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) < 0) goto on_err; // Build a dictionary of the device's capabilities for (ev_type=0 ; ev_type<EV_MAX ; ev_type++) { if (test_bit(ev_bits, ev_type)) { capability = PyLong_FromLong(ev_type); eventcodes = PyList_New(0); memset(&code_bits, 0, sizeof(code_bits)); ioctl(_fd, EVIOCGBIT(ev_type, sizeof(code_bits)), code_bits); for (ev_code = 0; ev_code < KEY_MAX; ev_code++) { if (test_bit(code_bits, ev_code)) { // Get abs{min,max,fuzz,flat} values for ABS_* event codes if (ev_type == EV_ABS) { memset(&absinfo, 0, sizeof(absinfo)); ioctl(_fd, EVIOCGABS(ev_code), &absinfo); py_absinfo = Py_BuildValue("(iiiiii)", absinfo.value, absinfo.minimum, absinfo.maximum, absinfo.fuzz, absinfo.flat, absinfo.resolution); evlong = PyLong_FromLong(ev_code); absitem = Py_BuildValue("(OO)", evlong, py_absinfo); // absitem -> tuple(ABS_X, (0, 255, 0, 0)) PyList_Append(eventcodes, absitem); Py_DECREF(absitem); Py_DECREF(py_absinfo); } else { evlong = PyLong_FromLong(ev_code); PyList_Append(eventcodes, evlong); } Py_DECREF(evlong); } } // capabilities[EV_KEY] = [KEY_A, KEY_B, KEY_C, ...] // capabilities[EV_ABS] = [(ABS_X, (0, 255, 0, 0)), ...] PyDict_SetItem(capabilities, capability, eventcodes); Py_DECREF(capability); Py_DECREF(eventcodes); } } return capabilities; on_err: PyErr_SetFromErrno(PyExc_IOError); return NULL; }