Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/dtor/input

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: xpad - add USB-ID for PL-3601 Xbox 360 pad
  Input: cy8ctmg100_ts - signedness bug
  Input: elantech - report position also with 3 fingers
  Input: elantech - discard the first 2 positions on some firmwares
  Input: adxl34x - do not mark device as disabled on startup
  Input: gpio_keys - add hooks to enable/disable device
  Input: evdev - rearrange ioctl handling
  Input: dynamically allocate ABS information
  Input: switch to input_abs_*() access functions
  Input: add static inline accessors for ABS properties
  • Loading branch information
torvalds committed Aug 10, 2010
2 parents 9895850 + 5fc0d36 commit 04f2b97
Show file tree
Hide file tree
Showing 25 changed files with 336 additions and 247 deletions.
49 changes: 24 additions & 25 deletions drivers/hid/hid-wacom.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
input_report_key(input, BTN_RIGHT, 0);
input_report_key(input, BTN_MIDDLE, 0);
input_report_abs(input, ABS_DISTANCE,
input->absmax[ABS_DISTANCE]);
input_abs_get_max(input, ABS_DISTANCE));
} else {
input_report_key(input, BTN_TOUCH, 0);
input_report_key(input, BTN_STYLUS, 0);
Expand Down Expand Up @@ -383,38 +383,37 @@ static int wacom_probe(struct hid_device *hdev,

/* Basics */
input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL);
input->absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) |
BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE);
input->relbit[0] |= BIT(REL_WHEEL);
set_bit(BTN_TOOL_PEN, input->keybit);
set_bit(BTN_TOUCH, input->keybit);
set_bit(BTN_STYLUS, input->keybit);
set_bit(BTN_STYLUS2, input->keybit);
set_bit(BTN_LEFT, input->keybit);
set_bit(BTN_RIGHT, input->keybit);
set_bit(BTN_MIDDLE, input->keybit);

__set_bit(REL_WHEEL, input->relbit);

__set_bit(BTN_TOOL_PEN, input->keybit);
__set_bit(BTN_TOUCH, input->keybit);
__set_bit(BTN_STYLUS, input->keybit);
__set_bit(BTN_STYLUS2, input->keybit);
__set_bit(BTN_LEFT, input->keybit);
__set_bit(BTN_RIGHT, input->keybit);
__set_bit(BTN_MIDDLE, input->keybit);

/* Pad */
input->evbit[0] |= BIT(EV_MSC);
input->mscbit[0] |= BIT(MSC_SERIAL);
set_bit(BTN_0, input->keybit);
set_bit(BTN_1, input->keybit);
set_bit(BTN_TOOL_FINGER, input->keybit);

/* Distance, rubber and mouse */
input->absbit[0] |= BIT(ABS_DISTANCE);
set_bit(BTN_TOOL_RUBBER, input->keybit);
set_bit(BTN_TOOL_MOUSE, input->keybit);
__set_bit(MSC_SERIAL, input->mscbit);

input->absmax[ABS_PRESSURE] = 511;
input->absmax[ABS_DISTANCE] = 32;
__set_bit(BTN_0, input->keybit);
__set_bit(BTN_1, input->keybit);
__set_bit(BTN_TOOL_FINGER, input->keybit);

input->absmax[ABS_X] = 16704;
input->absmax[ABS_Y] = 12064;
input->absfuzz[ABS_X] = 4;
input->absfuzz[ABS_Y] = 4;
/* Distance, rubber and mouse */
__set_bit(BTN_TOOL_RUBBER, input->keybit);
__set_bit(BTN_TOOL_MOUSE, input->keybit);

input_set_abs_params(input, ABS_X, 0, 16704, 4, 0);
input_set_abs_params(input, ABS_Y, 0, 12064, 4, 0);
input_set_abs_params(input, ABS_PRESSURE, 0, 511, 0, 0);
input_set_abs_params(input, ABS_DISTANCE, 0, 32, 0, 0);

return 0;

err_free:
kfree(wdata);
return ret;
Expand Down
152 changes: 73 additions & 79 deletions drivers/input/evdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -492,13 +492,15 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p)
}

#define OLD_KEY_MAX 0x1ff
static int handle_eviocgbit(struct input_dev *dev, unsigned int cmd, void __user *p, int compat_mode)
static int handle_eviocgbit(struct input_dev *dev,
unsigned int type, unsigned int size,
void __user *p, int compat_mode)
{
static unsigned long keymax_warn_time;
unsigned long *bits;
int len;

switch (_IOC_NR(cmd) & EV_MAX) {
switch (type) {

case 0: bits = dev->evbit; len = EV_MAX; break;
case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
Expand All @@ -517,7 +519,7 @@ static int handle_eviocgbit(struct input_dev *dev, unsigned int cmd, void __user
* EVIOCGBIT(EV_KEY, KEY_MAX) and not realize that 'len'
* should be in bytes, not in bits.
*/
if ((_IOC_NR(cmd) & EV_MAX) == EV_KEY && _IOC_SIZE(cmd) == OLD_KEY_MAX) {
if (type == EV_KEY && size == OLD_KEY_MAX) {
len = OLD_KEY_MAX;
if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000))
printk(KERN_WARNING
Expand All @@ -528,7 +530,7 @@ static int handle_eviocgbit(struct input_dev *dev, unsigned int cmd, void __user
BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long));
}

return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode);
return bits_to_user(bits, len, size, p, compat_mode);
}
#undef OLD_KEY_MAX

Expand All @@ -542,8 +544,10 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
struct ff_effect effect;
int __user *ip = (int __user *)p;
unsigned int i, t, u, v;
unsigned int size;
int error;

/* First we check for fixed-length commands */
switch (cmd) {

case EVIOCGVERSION:
Expand Down Expand Up @@ -610,112 +614,102 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
return evdev_grab(evdev, client);
else
return evdev_ungrab(evdev, client);
}

default:

if (_IOC_TYPE(cmd) != 'E')
return -EINVAL;

if (_IOC_DIR(cmd) == _IOC_READ) {
size = _IOC_SIZE(cmd);

if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0)))
return handle_eviocgbit(dev, cmd, p, compat_mode);
/* Now check variable-length commands */
#define EVIOC_MASK_SIZE(nr) ((nr) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT))

if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))
return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd),
p, compat_mode);
switch (EVIOC_MASK_SIZE(cmd)) {

if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0)))
return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd),
p, compat_mode);
case EVIOCGKEY(0):
return bits_to_user(dev->key, KEY_MAX, size, p, compat_mode);

if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0)))
return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd),
p, compat_mode);
case EVIOCGLED(0):
return bits_to_user(dev->led, LED_MAX, size, p, compat_mode);

if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0)))
return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd),
p, compat_mode);
case EVIOCGSND(0):
return bits_to_user(dev->snd, SND_MAX, size, p, compat_mode);

if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0)))
return str_to_user(dev->name, _IOC_SIZE(cmd), p);
case EVIOCGSW(0):
return bits_to_user(dev->sw, SW_MAX, size, p, compat_mode);

if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0)))
return str_to_user(dev->phys, _IOC_SIZE(cmd), p);
case EVIOCGNAME(0):
return str_to_user(dev->name, size, p);

if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0)))
return str_to_user(dev->uniq, _IOC_SIZE(cmd), p);
case EVIOCGPHYS(0):
return str_to_user(dev->phys, size, p);

if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
case EVIOCGUNIQ(0):
return str_to_user(dev->uniq, size, p);

t = _IOC_NR(cmd) & ABS_MAX;
case EVIOC_MASK_SIZE(EVIOCSFF):
if (input_ff_effect_from_user(p, size, &effect))
return -EFAULT;

abs.value = dev->abs[t];
abs.minimum = dev->absmin[t];
abs.maximum = dev->absmax[t];
abs.fuzz = dev->absfuzz[t];
abs.flat = dev->absflat[t];
abs.resolution = dev->absres[t];
error = input_ff_upload(dev, &effect, file);

if (copy_to_user(p, &abs, min_t(size_t,
_IOC_SIZE(cmd),
sizeof(struct input_absinfo))))
return -EFAULT;
if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
return -EFAULT;

return 0;
}
return error;
}

}
/* Multi-number variable-length handlers */
if (_IOC_TYPE(cmd) != 'E')
return -EINVAL;

if (_IOC_DIR(cmd) == _IOC_WRITE) {
if (_IOC_DIR(cmd) == _IOC_READ) {

if (_IOC_NR(cmd) == _IOC_NR(EVIOCSFF)) {
if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0)))
return handle_eviocgbit(dev,
_IOC_NR(cmd) & EV_MAX, size,
p, compat_mode);

if (input_ff_effect_from_user(p, _IOC_SIZE(cmd), &effect))
return -EFAULT;
if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {

error = input_ff_upload(dev, &effect, file);
t = _IOC_NR(cmd) & ABS_MAX;
abs = dev->absinfo[t];

if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
return -EFAULT;
if (copy_to_user(p, &abs, min_t(size_t,
size, sizeof(struct input_absinfo))))
return -EFAULT;

return error;
}
return 0;
}
}

if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
if (_IOC_DIR(cmd) == _IOC_READ) {

t = _IOC_NR(cmd) & ABS_MAX;
if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {

if (copy_from_user(&abs, p, min_t(size_t,
_IOC_SIZE(cmd),
sizeof(struct input_absinfo))))
return -EFAULT;
t = _IOC_NR(cmd) & ABS_MAX;

/* We can't change number of reserved MT slots */
if (t == ABS_MT_SLOT)
return -EINVAL;
if (copy_from_user(&abs, p, min_t(size_t,
size, sizeof(struct input_absinfo))))
return -EFAULT;

/*
* Take event lock to ensure that we are not
* changing device parameters in the middle
* of event.
*/
spin_lock_irq(&dev->event_lock);
if (size < sizeof(struct input_absinfo))
abs.resolution = 0;

dev->abs[t] = abs.value;
dev->absmin[t] = abs.minimum;
dev->absmax[t] = abs.maximum;
dev->absfuzz[t] = abs.fuzz;
dev->absflat[t] = abs.flat;
dev->absres[t] = _IOC_SIZE(cmd) < sizeof(struct input_absinfo) ?
0 : abs.resolution;
/* We can't change number of reserved MT slots */
if (t == ABS_MT_SLOT)
return -EINVAL;

spin_unlock_irq(&dev->event_lock);
/*
* Take event lock to ensure that we are not
* changing device parameters in the middle
* of event.
*/
spin_lock_irq(&dev->event_lock);
dev->absinfo[t] = abs;
spin_unlock_irq(&dev->event_lock);

return 0;
}
return 0;
}
}

return -EINVAL;
}

Expand Down
46 changes: 42 additions & 4 deletions drivers/input/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ static int input_handle_abs_event(struct input_dev *dev,
is_mt_event = code >= ABS_MT_FIRST && code <= ABS_MT_LAST;

if (!is_mt_event) {
pold = &dev->abs[code];
pold = &dev->absinfo[code].value;
} else if (dev->mt) {
struct input_mt_slot *mtslot = &dev->mt[dev->slot];
pold = &mtslot->abs[code - ABS_MT_FIRST];
Expand All @@ -196,16 +196,16 @@ static int input_handle_abs_event(struct input_dev *dev,

if (pold) {
*pval = input_defuzz_abs_event(*pval, *pold,
dev->absfuzz[code]);
dev->absinfo[code].fuzz);
if (*pold == *pval)
return INPUT_IGNORE_EVENT;

*pold = *pval;
}

/* Flush pending "slot" event */
if (is_mt_event && dev->slot != dev->abs[ABS_MT_SLOT]) {
dev->abs[ABS_MT_SLOT] = dev->slot;
if (is_mt_event && dev->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
input_abs_set_val(dev, ABS_MT_SLOT, dev->slot);
input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot);
}

Expand Down Expand Up @@ -390,6 +390,43 @@ void input_inject_event(struct input_handle *handle,
}
EXPORT_SYMBOL(input_inject_event);

/**
* input_alloc_absinfo - allocates array of input_absinfo structs
* @dev: the input device emitting absolute events
*
* If the absinfo struct the caller asked for is already allocated, this
* functions will not do anything.
*/
void input_alloc_absinfo(struct input_dev *dev)
{
if (!dev->absinfo)
dev->absinfo = kcalloc(ABS_CNT, sizeof(struct input_absinfo),
GFP_KERNEL);

WARN(!dev->absinfo, "%s(): kcalloc() failed?\n", __func__);
}
EXPORT_SYMBOL(input_alloc_absinfo);

void input_set_abs_params(struct input_dev *dev, unsigned int axis,
int min, int max, int fuzz, int flat)
{
struct input_absinfo *absinfo;

input_alloc_absinfo(dev);
if (!dev->absinfo)
return;

absinfo = &dev->absinfo[axis];
absinfo->minimum = min;
absinfo->maximum = max;
absinfo->fuzz = fuzz;
absinfo->flat = flat;

dev->absbit[BIT_WORD(axis)] |= BIT_MASK(axis);
}
EXPORT_SYMBOL(input_set_abs_params);


/**
* input_grab_device - grabs device for exclusive use
* @handle: input handle that wants to own the device
Expand Down Expand Up @@ -1308,6 +1345,7 @@ static void input_dev_release(struct device *device)

input_ff_destroy(dev);
input_mt_destroy_slots(dev);
kfree(dev->absinfo);
kfree(dev);

module_put(THIS_MODULE);
Expand Down
Loading

0 comments on commit 04f2b97

Please sign in to comment.