static int uinput_validate_absbits(struct input_dev *dev) { unsigned int cnt; int retval = 0; for (cnt = 0; cnt < ABS_CNT; cnt++) { if (!test_bit(cnt, dev->absbit)) continue; if (input_abs_get_max(dev, cnt) <= input_abs_get_min(dev, cnt)) { printk(KERN_DEBUG "%s: invalid abs[%02x] min:%d max:%d\n", UINPUT_NAME, cnt, input_abs_get_min(dev, cnt), input_abs_get_max(dev, cnt)); retval = -EINVAL; break; } if (input_abs_get_flat(dev, cnt) > input_abs_get_max(dev, cnt) - input_abs_get_min(dev, cnt)) { printk(KERN_DEBUG "%s: abs_flat #%02x out of range: %d " "(min:%d/max:%d)\n", UINPUT_NAME, cnt, input_abs_get_flat(dev, cnt), input_abs_get_min(dev, cnt), input_abs_get_max(dev, cnt)); retval = -EINVAL; break; } } return retval; }
static int uinput_setup_device(struct uinput_device *udev, const char __user *buffer, size_t count) { struct uinput_user_dev *user_dev; struct input_dev *dev; int i; int retval; if (count != sizeof(struct uinput_user_dev)) return -EINVAL; if (!udev->dev) { retval = uinput_allocate_device(udev); if (retval) return retval; } dev = udev->dev; user_dev = memdup_user(buffer, sizeof(struct uinput_user_dev)); if (IS_ERR(user_dev)) return PTR_ERR(user_dev); udev->ff_effects_max = user_dev->ff_effects_max; /* Ensure name is filled in */ if (!user_dev->name[0]) { retval = -EINVAL; goto exit; } kfree(dev->name); dev->name = kstrndup(user_dev->name, UINPUT_MAX_NAME_SIZE, GFP_KERNEL); if (!dev->name) { retval = -ENOMEM; goto exit; } dev->id.bustype = user_dev->id.bustype; dev->id.vendor = user_dev->id.vendor; dev->id.product = user_dev->id.product; dev->id.version = user_dev->id.version; for (i = 0; i < ABS_CNT; i++) { input_abs_set_max(dev, i, user_dev->absmax[i]); input_abs_set_min(dev, i, user_dev->absmin[i]); input_abs_set_fuzz(dev, i, user_dev->absfuzz[i]); input_abs_set_flat(dev, i, user_dev->absflat[i]); } /* check if absmin/absmax/absfuzz/absflat are filled as * told in Documentation/input/input-programming.txt */ if (test_bit(EV_ABS, dev->evbit)) { retval = uinput_validate_absbits(dev); if (retval < 0) goto exit; if (test_bit(ABS_MT_SLOT, dev->absbit)) { int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1; input_mt_init_slots(dev, nslot, 0); } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) { input_set_events_per_packet(dev, 60); } } udev->state = UIST_SETUP_COMPLETE; retval = count; exit: kfree(user_dev); return retval; }
/** * touchscreen_parse_properties - parse common touchscreen DT properties * @input: input device that should be parsed * @multitouch: specifies whether parsed properties should be applied to * single-touch or multi-touch axes * @prop: pointer to a struct touchscreen_properties into which to store * axis swap and invert info for use with touchscreen_report_x_y(); * or %NULL * * This function parses common DT properties for touchscreens and setups the * input device accordingly. The function keeps previously set up default * values if no value is specified via DT. */ void touchscreen_parse_properties(struct input_dev *input, bool multitouch, struct touchscreen_properties *prop) { struct device *dev = input->dev.parent; unsigned int axis; unsigned int maximum, fuzz; bool data_present; input_alloc_absinfo(input); if (!input->absinfo) return; axis = multitouch ? ABS_MT_POSITION_X : ABS_X; data_present = touchscreen_get_prop_u32(dev, "touchscreen-size-x", input_abs_get_max(input, axis) + 1, &maximum) | touchscreen_get_prop_u32(dev, "touchscreen-fuzz-x", input_abs_get_fuzz(input, axis), &fuzz); if (data_present) touchscreen_set_params(input, axis, maximum - 1, fuzz); axis = multitouch ? ABS_MT_POSITION_Y : ABS_Y; data_present = touchscreen_get_prop_u32(dev, "touchscreen-size-y", input_abs_get_max(input, axis) + 1, &maximum) | touchscreen_get_prop_u32(dev, "touchscreen-fuzz-y", input_abs_get_fuzz(input, axis), &fuzz); if (data_present) touchscreen_set_params(input, axis, maximum - 1, fuzz); axis = multitouch ? ABS_MT_PRESSURE : ABS_PRESSURE; data_present = touchscreen_get_prop_u32(dev, "touchscreen-max-pressure", input_abs_get_max(input, axis), &maximum) | touchscreen_get_prop_u32(dev, "touchscreen-fuzz-pressure", input_abs_get_fuzz(input, axis), &fuzz); if (data_present) touchscreen_set_params(input, axis, maximum, fuzz); if (!prop) return; axis = multitouch ? ABS_MT_POSITION_X : ABS_X; prop->max_x = input_abs_get_max(input, axis); prop->max_y = input_abs_get_max(input, axis + 1); prop->invert_x = device_property_read_bool(dev, "touchscreen-inverted-x"); prop->invert_y = device_property_read_bool(dev, "touchscreen-inverted-y"); prop->swap_x_y = device_property_read_bool(dev, "touchscreen-swapped-x-y"); if (prop->swap_x_y) swap(input->absinfo[axis], input->absinfo[axis + 1]); }
static void hil_dev_handle_ptr_events(struct hil_dev *ptr) { struct input_dev *dev = ptr->dev; int idx = ptr->idx4 / 4; hil_packet p = ptr->data[idx - 1]; int i, cnt, laxis; bool absdev, ax16; if ((p & HIL_CMDCT_POL) != idx - 1) { printk(KERN_WARNING PREFIX "Malformed poll packet %x (idx = %i)\n", p, idx); return; } i = (p & HIL_POL_AXIS_ALT) ? 3 : 0; laxis = (p & HIL_POL_NUM_AXES_MASK) + i; ax16 = ptr->idd[1] & HIL_IDD_HEADER_16BIT; /* 8 or 16bit resolution */ absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS; for (cnt = 1; i < laxis; i++) { unsigned int lo, hi, val; lo = ptr->data[cnt++] & HIL_PKT_DATA_MASK; hi = ax16 ? (ptr->data[cnt++] & HIL_PKT_DATA_MASK) : 0; if (absdev) { val = lo + (hi << 8); #ifdef TABLET_AUTOADJUST if (val < input_abs_get_min(dev, ABS_X + i)) input_abs_set_min(dev, ABS_X + i, val); if (val > input_abs_get_max(dev, ABS_X + i)) input_abs_set_max(dev, ABS_X + i, val); #endif if (i % 3) val = input_abs_get_max(dev, ABS_X + i) - val; input_report_abs(dev, ABS_X + i, val); } else { val = (int) (((int8_t) lo) | ((int8_t) hi << 8)); if (i % 3) val *= -1; input_report_rel(dev, REL_X + i, val); } } while (cnt < idx - 1) { unsigned int btn = ptr->data[cnt++]; int up = btn & 1; btn &= 0xfe; if (btn == 0x8e) continue; /* TODO: proximity == touch? */ if (btn > 0x8c || btn < 0x80) continue; btn = (btn - 0x80) >> 1; btn = ptr->btnmap[btn]; input_report_key(dev, btn, !up); } input_sync(dev); }
static void hil_dev_pointer_setup(struct hil_dev *ptr) { struct input_dev *input_dev = ptr->dev; uint8_t did = ptr->idd[0]; uint8_t *idd = ptr->idd + 1; unsigned int naxsets = HIL_IDD_NUM_AXSETS(*idd); unsigned int i, btntype; const char *txt; ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd); switch (did & HIL_IDD_DID_TYPE_MASK) { case HIL_IDD_DID_TYPE_REL: input_dev->evbit[0] = BIT_MASK(EV_REL); for (i = 0; i < ptr->naxes; i++) __set_bit(REL_X + i, input_dev->relbit); for (i = 3; naxsets > 1 && i < ptr->naxes + 3; i++) __set_bit(REL_X + i, input_dev->relbit); txt = "relative"; break; case HIL_IDD_DID_TYPE_ABS: input_dev->evbit[0] = BIT_MASK(EV_ABS); for (i = 0; i < ptr->naxes; i++) input_set_abs_params(input_dev, ABS_X + i, 0, HIL_IDD_AXIS_MAX(idd, i), 0, 0); for (i = 3; naxsets > 1 && i < ptr->naxes + 3; i++) input_set_abs_params(input_dev, ABS_X + i, 0, HIL_IDD_AXIS_MAX(idd, i - 3), 0, 0); #ifdef TABLET_AUTOADJUST for (i = 0; i < ABS_MAX; i++) { int diff = input_abs_get_max(input_dev, ABS_X + i) / 10; input_abs_set_min(input_dev, ABS_X + i, input_abs_get_min(input_dev, ABS_X + i) + diff); input_abs_set_max(input_dev, ABS_X + i, input_abs_get_max(input_dev, ABS_X + i) - diff); } #endif txt = "absolute"; break; default: BUG(); } ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd); if (ptr->nbtn) input_dev->evbit[0] |= BIT_MASK(EV_KEY); btntype = BTN_MISC; if ((did & HIL_IDD_DID_ABS_TABLET_MASK) == HIL_IDD_DID_ABS_TABLET) #ifdef TABLET_SIMULATES_MOUSE btntype = BTN_TOUCH; #else btntype = BTN_DIGI; #endif if ((did & HIL_IDD_DID_ABS_TSCREEN_MASK) == HIL_IDD_DID_ABS_TSCREEN) btntype = BTN_TOUCH; if ((did & HIL_IDD_DID_REL_MOUSE_MASK) == HIL_IDD_DID_REL_MOUSE) btntype = BTN_MOUSE; for (i = 0; i < ptr->nbtn; i++) { __set_bit(btntype | i, input_dev->keybit); ptr->btnmap[i] = btntype | i; } if (btntype == BTN_MOUSE) { /* Swap buttons 2 and 3 */ ptr->btnmap[1] = BTN_MIDDLE; ptr->btnmap[2] = BTN_RIGHT; } input_dev->name = strlen(ptr->rnm) ? ptr->rnm : "HIL pointer device"; printk(KERN_INFO PREFIX "HIL pointer device found (did: 0x%02x, axis: %s)\n", did, txt); printk(KERN_INFO PREFIX "HIL pointer has %i buttons and %i sets of %i axes\n", ptr->nbtn, naxsets, ptr->naxes); }
/* * 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; }
static int uinput_setup_device(struct uinput_device *udev, const char __user *buffer, size_t count) { struct uinput_user_dev *user_dev; struct input_dev *dev; int i; int retval; size_t size; size = min_t(size_t, count, sizeof(struct uinput_user_dev)); if (!udev->dev) { retval = uinput_allocate_device(udev); if (retval) return retval; } dev = udev->dev; user_dev = kzalloc(sizeof(struct uinput_user_dev), GFP_KERNEL); if (!user_dev) return -ENOMEM; if (copy_from_user(user_dev, buffer, size)) { retval = -EFAULT; goto exit; } udev->ff_effects_max = user_dev->ff_effects_max; /* Ensure name is filled in */ if (!user_dev->name[0]) { retval = -EINVAL; goto exit; } kfree(dev->name); dev->name = kstrndup(user_dev->name, UINPUT_MAX_NAME_SIZE, GFP_KERNEL); if (!dev->name) { retval = -ENOMEM; goto exit; } dev->id.bustype = user_dev->id.bustype; dev->id.vendor = user_dev->id.vendor; dev->id.product = user_dev->id.product; dev->id.version = user_dev->id.version; for (i = 0; i < ABS_CNT; i++) { input_abs_set_max(dev, i, user_dev->absmax[i]); input_abs_set_min(dev, i, user_dev->absmin[i]); input_abs_set_fuzz(dev, i, user_dev->absfuzz[i]); input_abs_set_flat(dev, i, user_dev->absflat[i]); input_abs_set_res(dev, i, user_dev->absres[i]); } /* check if absmin/absmax/absfuzz/absflat are filled as * told in Documentation/input/input-programming.txt */ if (test_bit(EV_ABS, dev->evbit)) { retval = uinput_validate_absbits(dev); if (retval < 0) goto exit; if (test_bit(ABS_MT_SLOT, dev->absbit)) { int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1; #ifdef INPUT_MT_POINTER input_mt_init_slots(dev, nslot, 0); #else /* INPUT_MT_POINTER */ input_mt_init_slots(dev, nslot); #endif /* INPUT_MT_POINTER */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) { input_set_events_per_packet(dev, 60); #endif /* LINUX_VERSION_CODE >= 2.6.36 */ } } udev->state = UIST_SETUP_COMPLETE; retval = count; exit: kfree(user_dev); return retval; }
static int pixcir_i2c_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { const struct pixcir_ts_platform_data *pdata = dev_get_platdata(&client->dev); struct device *dev = &client->dev; struct pixcir_i2c_ts_data *tsdata; struct input_dev *input; int error; tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL); if (!tsdata) return -ENOMEM; if (pdata) { tsdata->chip = &pdata->chip; } else if (dev->of_node) { error = pixcir_parse_dt(dev, tsdata); if (error) return error; } else { dev_err(&client->dev, "platform data not defined\n"); return -EINVAL; } if (!tsdata->chip->max_fingers) { dev_err(dev, "Invalid max_fingers in chip data\n"); return -EINVAL; } input = devm_input_allocate_device(dev); if (!input) { dev_err(dev, "Failed to allocate input device\n"); return -ENOMEM; } tsdata->client = client; tsdata->input = input; input->name = client->name; input->id.bustype = BUS_I2C; input->open = pixcir_input_open; input->close = pixcir_input_close; input->dev.parent = &client->dev; if (pdata) { input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0); } else { input_set_capability(input, EV_ABS, ABS_MT_POSITION_X); input_set_capability(input, EV_ABS, ABS_MT_POSITION_Y); touchscreen_parse_properties(input, true, &tsdata->prop); if (!input_abs_get_max(input, ABS_MT_POSITION_X) || !input_abs_get_max(input, ABS_MT_POSITION_Y)) { dev_err(dev, "Touchscreen size is not specified\n"); return -EINVAL; } } tsdata->max_fingers = tsdata->chip->max_fingers; if (tsdata->max_fingers > PIXCIR_MAX_SLOTS) { tsdata->max_fingers = PIXCIR_MAX_SLOTS; dev_info(dev, "Limiting maximum fingers to %d\n", tsdata->max_fingers); } error = input_mt_init_slots(input, tsdata->max_fingers, INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); if (error) { dev_err(dev, "Error initializing Multi-Touch slots\n"); return error; } input_set_drvdata(input, tsdata); tsdata->gpio_attb = devm_gpiod_get(dev, "attb", GPIOD_IN); if (IS_ERR(tsdata->gpio_attb)) { error = PTR_ERR(tsdata->gpio_attb); dev_err(dev, "Failed to request ATTB gpio: %d\n", error); return error; } tsdata->gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(tsdata->gpio_reset)) { error = PTR_ERR(tsdata->gpio_reset); dev_err(dev, "Failed to request RESET gpio: %d\n", error); return error; } tsdata->gpio_wake = devm_gpiod_get_optional(dev, "wake", GPIOD_OUT_HIGH); if (IS_ERR(tsdata->gpio_wake)) { error = PTR_ERR(tsdata->gpio_wake); if (error != -EPROBE_DEFER) dev_err(dev, "Failed to get wake gpio: %d\n", error); return error; } tsdata->gpio_enable = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); if (IS_ERR(tsdata->gpio_enable)) { error = PTR_ERR(tsdata->gpio_enable); if (error != -EPROBE_DEFER) dev_err(dev, "Failed to get enable gpio: %d\n", error); return error; } if (tsdata->gpio_enable) msleep(100); error = devm_request_threaded_irq(dev, client->irq, NULL, pixcir_ts_isr, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, tsdata); if (error) { dev_err(dev, "failed to request irq %d\n", client->irq); return error; } pixcir_reset(tsdata); /* Always be in IDLE mode to save power, device supports auto wake */ error = pixcir_set_power_mode(tsdata, PIXCIR_POWER_IDLE); if (error) { dev_err(dev, "Failed to set IDLE mode\n"); return error; } /* Stop device till opened */ error = pixcir_stop(tsdata); if (error) return error; error = input_register_device(input); if (error) return error; i2c_set_clientdata(client, tsdata); return 0; }
void genode_evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { #if DEBUG_EVDEV static unsigned long count = 0; #endif static int last_ax = -1; /* store the last absolute x value */ /* filter sound events */ if (test_bit(EV_SND, handle->dev->evbit)) return; /* filter input_repeat_key() */ if ((type == EV_KEY) && (value == 2)) return; /* filter EV_SYN */ if (type == EV_SYN) return; /* generate arguments and call back */ enum input_event_type arg_type; unsigned arg_keycode = KEY_UNKNOWN; int arg_ax = 0, arg_ay = 0, arg_rx = 0, arg_ry = 0; switch (type) { case EV_KEY: arg_keycode = code; /* map BTN_TOUCH events to BTN_LEFT */ if (code == BTN_TOUCH) arg_keycode = BTN_LEFT; switch (value) { case 0: arg_type = EVENT_TYPE_RELEASE; break; case 1: arg_type = EVENT_TYPE_PRESS; break; default: printk("Unknown key event value %d - not handled\n", value); return; } break; case EV_ABS: switch (code) { case ABS_X: case ABS_MT_POSITION_X: /* * Don't create an input event yet. Store the value and wait for the * subsequent Y event. */ last_ax = value; return; case ABS_Y: case ABS_MT_POSITION_Y: /* * Create a unified input event with absolute positions on x and y * axis. */ arg_type = EVENT_TYPE_MOTION; arg_ax = last_ax; arg_ay = value; /* transform if requested */ if (screen_x && screen_y) { int const min_x_dev = input_abs_get_min(handle->dev, ABS_X); int const min_y_dev = input_abs_get_min(handle->dev, ABS_Y); int const max_x_dev = input_abs_get_max(handle->dev, ABS_X); int const max_y_dev = input_abs_get_max(handle->dev, ABS_Y); int const max_y_norm = max_y_dev - min_y_dev; int const max_x_norm = max_x_dev - min_x_dev; if ((max_x_norm == 0) || (max_y_norm == 0) || (last_ax < min_x_dev) || (value < min_y_dev) || (last_ax > max_x_dev) || (value > max_y_dev)) { printk("Ignore input source with coordinates out of range\n"); return; } arg_ax = screen_x * (last_ax - min_x_dev) / (max_x_norm); arg_ay = screen_y * (value - min_y_dev) / (max_y_norm); } last_ax = -1; if (arg_ax == -1) { printk("Ignore absolute Y event without a preceeding X event\n"); return; } break; case ABS_WHEEL: /* * XXX I do not know, how to handle this correctly. At least, this * scheme works on Qemu. */ arg_type = EVENT_TYPE_WHEEL; arg_ry = value; break; default: printk("Unknown absolute event code %d - not handled\n", code); return; } break; case EV_REL: switch (code) { case REL_X: arg_type = EVENT_TYPE_MOTION; arg_rx = value; break; case REL_Y: arg_type = EVENT_TYPE_MOTION; arg_ry = value; break; case REL_HWHEEL: arg_type = EVENT_TYPE_WHEEL; arg_rx = value; break; case REL_WHEEL: arg_type = EVENT_TYPE_WHEEL; arg_ry = value; break; default: printk("Unknown relative event code %d - not handled\n", code); return; } break; default: printk("Unknown event type %d - not handled\n", type); return; } if (handler) handler(arg_type, arg_keycode, arg_ax, arg_ay, arg_rx, arg_ry); #if DEBUG_EVDEV printk("event[%ld]. dev: %s, type: %d, code: %d, value: %d a=%d,%d " "r=%d,%d\n", count++, handle->dev->name, type, code, value, arg_ax, arg_ay, arg_rx, arg_ry); #endif }
static int uinput_setup_device(struct uinput_device *udev, const char __user *buffer, size_t count) { struct uinput_user_dev *user_dev; struct input_dev *dev; char *name; int size; int retval; if (count != sizeof(struct uinput_user_dev)) return -EINVAL; if (!udev->dev) { retval = uinput_allocate_device(udev); if (retval) return retval; } dev = udev->dev; user_dev = kmalloc(sizeof(struct uinput_user_dev), GFP_KERNEL); if (!user_dev) return -ENOMEM; if (copy_from_user(user_dev, buffer, sizeof(struct uinput_user_dev))) { retval = -EFAULT; goto exit; } udev->ff_effects_max = user_dev->ff_effects_max; size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1; if (!size) { retval = -EINVAL; goto exit; } kfree(dev->name); dev->name = name = kmalloc(size, GFP_KERNEL); if (!name) { retval = -ENOMEM; goto exit; } strlcpy(name, user_dev->name, size); dev->id.bustype = user_dev->id.bustype; dev->id.vendor = user_dev->id.vendor; dev->id.product = user_dev->id.product; dev->id.version = user_dev->id.version; size = sizeof(int) * (ABS_MAX + 1); memcpy(dev->absmax, user_dev->absmax, size); memcpy(dev->absmin, user_dev->absmin, size); memcpy(dev->absfuzz, user_dev->absfuzz, size); memcpy(dev->absflat, user_dev->absflat, size); /* check if absmin/absmax/absfuzz/absflat are filled as * told in Documentation/input/input-programming.txt */ if (test_bit(EV_ABS, dev->evbit)) { retval = uinput_validate_absbits(dev); if (retval < 0) goto exit; if (test_bit(ABS_MT_SLOT, dev->absbit)) { int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1; input_mt_init_slots(dev, nslot, 0); } } udev->state = UIST_SETUP_COMPLETE; retval = count; exit: kfree(user_dev); return retval; }