Commit d31b2865 authored by Daniel Mack's avatar Daniel Mack Committed by Dmitry Torokhov

Input: dynamically allocate ABS information

As all callers are now changed to only use the input_abs_*() access
helpers, switching over to dynamically allocated ABS information is
easy. This reduces size of struct input_dev from 3152 to 1640 on
64 bit architectures.
Signed-off-by: default avatarDaniel Mack <daniel@caiaq.de>
Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
parent 987a6c02
...@@ -649,13 +649,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, ...@@ -649,13 +649,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
t = _IOC_NR(cmd) & ABS_MAX; t = _IOC_NR(cmd) & ABS_MAX;
abs = dev->absinfo[t];
abs.value = input_abs_get_val(dev, t);
abs.minimum = input_abs_get_min(dev, t);
abs.maximum = input_abs_get_max(dev, t);
abs.fuzz = input_abs_get_fuzz(dev, t);
abs.flat = input_abs_get_flat(dev, t);
abs.resolution = input_abs_get_res(dev, t);
if (copy_to_user(p, &abs, min_t(size_t, if (copy_to_user(p, &abs, min_t(size_t,
_IOC_SIZE(cmd), _IOC_SIZE(cmd),
...@@ -691,6 +685,9 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, ...@@ -691,6 +685,9 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
sizeof(struct input_absinfo)))) sizeof(struct input_absinfo))))
return -EFAULT; return -EFAULT;
if (_IOC_SIZE(cmd) < sizeof(struct input_absinfo))
abs.resolution = 0;
/* We can't change number of reserved MT slots */ /* We can't change number of reserved MT slots */
if (t == ABS_MT_SLOT) if (t == ABS_MT_SLOT)
return -EINVAL; return -EINVAL;
...@@ -701,15 +698,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, ...@@ -701,15 +698,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
* of event. * of event.
*/ */
spin_lock_irq(&dev->event_lock); spin_lock_irq(&dev->event_lock);
dev->absinfo[t] = abs;
input_abs_set_val(dev, t, abs.value);
input_abs_set_min(dev, t, abs.minimum);
input_abs_set_max(dev, t, abs.maximum);
input_abs_set_fuzz(dev, t, abs.fuzz);
input_abs_set_flat(dev, t, abs.flat);
input_abs_set_res(dev, t, _IOC_SIZE(cmd) < sizeof(struct input_absinfo) ?
0 : abs.resolution);
spin_unlock_irq(&dev->event_lock); spin_unlock_irq(&dev->event_lock);
return 0; return 0;
......
...@@ -182,7 +182,7 @@ static int input_handle_abs_event(struct input_dev *dev, ...@@ -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; is_mt_event = code >= ABS_MT_FIRST && code <= ABS_MT_LAST;
if (!is_mt_event) { if (!is_mt_event) {
pold = &dev->abs[code]; pold = &dev->absinfo[code].value;
} else if (dev->mt) { } else if (dev->mt) {
struct input_mt_slot *mtslot = &dev->mt[dev->slot]; struct input_mt_slot *mtslot = &dev->mt[dev->slot];
pold = &mtslot->abs[code - ABS_MT_FIRST]; pold = &mtslot->abs[code - ABS_MT_FIRST];
...@@ -196,7 +196,7 @@ static int input_handle_abs_event(struct input_dev *dev, ...@@ -196,7 +196,7 @@ static int input_handle_abs_event(struct input_dev *dev,
if (pold) { if (pold) {
*pval = input_defuzz_abs_event(*pval, *pold, *pval = input_defuzz_abs_event(*pval, *pold,
dev->absfuzz[code]); dev->absinfo[code].fuzz);
if (*pold == *pval) if (*pold == *pval)
return INPUT_IGNORE_EVENT; return INPUT_IGNORE_EVENT;
...@@ -390,6 +390,43 @@ void input_inject_event(struct input_handle *handle, ...@@ -390,6 +390,43 @@ void input_inject_event(struct input_handle *handle,
} }
EXPORT_SYMBOL(input_inject_event); 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 * input_grab_device - grabs device for exclusive use
* @handle: input handle that wants to own the device * @handle: input handle that wants to own the device
...@@ -1308,6 +1345,7 @@ static void input_dev_release(struct device *device) ...@@ -1308,6 +1345,7 @@ static void input_dev_release(struct device *device)
input_ff_destroy(dev); input_ff_destroy(dev);
input_mt_destroy_slots(dev); input_mt_destroy_slots(dev);
kfree(dev->absinfo);
kfree(dev); kfree(dev);
module_put(THIS_MODULE); module_put(THIS_MODULE);
......
...@@ -776,6 +776,7 @@ struct input_absinfo { ...@@ -776,6 +776,7 @@ struct input_absinfo {
#define REP_DELAY 0x00 #define REP_DELAY 0x00
#define REP_PERIOD 0x01 #define REP_PERIOD 0x01
#define REP_MAX 0x01 #define REP_MAX 0x01
#define REP_CNT (REP_MAX+1)
/* /*
* Sounds * Sounds
...@@ -1099,21 +1100,18 @@ struct input_mt_slot { ...@@ -1099,21 +1100,18 @@ struct input_mt_slot {
* @repeat_key: stores key code of the last key pressed; used to implement * @repeat_key: stores key code of the last key pressed; used to implement
* software autorepeat * software autorepeat
* @timer: timer for software autorepeat * @timer: timer for software autorepeat
* @abs: current values for reports from absolute axes
* @rep: current values for autorepeat parameters (delay, rate) * @rep: current values for autorepeat parameters (delay, rate)
* @mt: pointer to array of struct input_mt_slot holding current values * @mt: pointer to array of struct input_mt_slot holding current values
* of tracked contacts * of tracked contacts
* @mtsize: number of MT slots the device uses * @mtsize: number of MT slots the device uses
* @slot: MT slot currently being transmitted * @slot: MT slot currently being transmitted
* @absinfo: array of &struct absinfo elements holding information
* about absolute axes (current value, min, max, flat, fuzz,
* resolution)
* @key: reflects current state of device's keys/buttons * @key: reflects current state of device's keys/buttons
* @led: reflects current state of device's LEDs * @led: reflects current state of device's LEDs
* @snd: reflects current state of sound effects * @snd: reflects current state of sound effects
* @sw: reflects current state of device's switches * @sw: reflects current state of device's switches
* @absmax: maximum values for events coming from absolute axes
* @absmin: minimum values for events coming from absolute axes
* @absfuzz: describes noisiness for axes
* @absflat: size of the center flat position (used by joydev)
* @absres: resolution used for events coming form absolute axes
* @open: this method is called when the very first user calls * @open: this method is called when the very first user calls
* input_open_device(). The driver must prepare the device * input_open_device(). The driver must prepare the device
* to start generating events (start polling thread, * to start generating events (start polling thread,
...@@ -1180,24 +1178,19 @@ struct input_dev { ...@@ -1180,24 +1178,19 @@ struct input_dev {
unsigned int repeat_key; unsigned int repeat_key;
struct timer_list timer; struct timer_list timer;
int abs[ABS_CNT]; int rep[REP_CNT];
int rep[REP_MAX + 1];
struct input_mt_slot *mt; struct input_mt_slot *mt;
int mtsize; int mtsize;
int slot; int slot;
struct input_absinfo *absinfo;
unsigned long key[BITS_TO_LONGS(KEY_CNT)]; unsigned long key[BITS_TO_LONGS(KEY_CNT)];
unsigned long led[BITS_TO_LONGS(LED_CNT)]; unsigned long led[BITS_TO_LONGS(LED_CNT)];
unsigned long snd[BITS_TO_LONGS(SND_CNT)]; unsigned long snd[BITS_TO_LONGS(SND_CNT)];
unsigned long sw[BITS_TO_LONGS(SW_CNT)]; unsigned long sw[BITS_TO_LONGS(SW_CNT)];
int absmax[ABS_CNT];
int absmin[ABS_CNT];
int absfuzz[ABS_CNT];
int absflat[ABS_CNT];
int absres[ABS_CNT];
int (*open)(struct input_dev *dev); int (*open)(struct input_dev *dev);
void (*close)(struct input_dev *dev); void (*close)(struct input_dev *dev);
int (*flush)(struct input_dev *dev, struct file *file); int (*flush)(struct input_dev *dev, struct file *file);
...@@ -1459,45 +1452,31 @@ static inline void input_set_events_per_packet(struct input_dev *dev, int n_even ...@@ -1459,45 +1452,31 @@ static inline void input_set_events_per_packet(struct input_dev *dev, int n_even
dev->hint_events_per_packet = n_events; dev->hint_events_per_packet = n_events;
} }
static inline void input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat) void input_alloc_absinfo(struct input_dev *dev);
{ void input_set_abs_params(struct input_dev *dev, unsigned int axis,
dev->absmin[axis] = min; int min, int max, int fuzz, int flat);
dev->absmax[axis] = max;
dev->absfuzz[axis] = fuzz;
dev->absflat[axis] = flat;
dev->absbit[BIT_WORD(axis)] |= BIT_MASK(axis);
}
#define INPUT_GENERATE_ABS_ACCESSORS(_suffix, _item) \ #define INPUT_GENERATE_ABS_ACCESSORS(_suffix, _item) \
static inline int input_abs_get_##_suffix(struct input_dev *dev, \ static inline int input_abs_get_##_suffix(struct input_dev *dev, \
unsigned int axis) \ unsigned int axis) \
{ \ { \
return dev->abs##_item[axis]; \ return dev->absinfo ? dev->absinfo[axis]._item : 0; \
} \ } \
\ \
static inline void input_abs_set_##_suffix(struct input_dev *dev, \ static inline void input_abs_set_##_suffix(struct input_dev *dev, \
unsigned int axis, int val) \ unsigned int axis, int val) \
{ \ { \
dev->abs##_item[axis] = val; \ input_alloc_absinfo(dev); \
if (dev->absinfo) \
dev->absinfo[axis]._item = val; \
} }
INPUT_GENERATE_ABS_ACCESSORS(min, min) INPUT_GENERATE_ABS_ACCESSORS(val, value)
INPUT_GENERATE_ABS_ACCESSORS(max, max) INPUT_GENERATE_ABS_ACCESSORS(min, minimum)
INPUT_GENERATE_ABS_ACCESSORS(max, maximum)
INPUT_GENERATE_ABS_ACCESSORS(fuzz, fuzz) INPUT_GENERATE_ABS_ACCESSORS(fuzz, fuzz)
INPUT_GENERATE_ABS_ACCESSORS(flat, flat) INPUT_GENERATE_ABS_ACCESSORS(flat, flat)
INPUT_GENERATE_ABS_ACCESSORS(res, res) INPUT_GENERATE_ABS_ACCESSORS(res, resolution)
static inline int input_abs_get_val(struct input_dev *dev, unsigned int axis)
{
return dev->abs[axis];
}
static inline void input_abs_set_val(struct input_dev *dev,
unsigned int axis, int val)
{
dev->abs[axis] = val;
}
int input_get_keycode(struct input_dev *dev, int input_get_keycode(struct input_dev *dev,
unsigned int scancode, unsigned int *keycode); unsigned int scancode, unsigned int *keycode);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment