From 509ca1a9383601fdc5612d3d3ba5b981f6eb6c8b Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Wed, 19 Jul 2006 01:40:22 -0400 Subject: Input: implement new force feedback interface Implement a new force feedback interface, in which all non-driver-specific operations are separated to a common module. This includes handling effect type validations, locking, etc. The effects are now file descriptor specific instead of the previous strange half-process half-fd specific behaviour. The effect memory of devices is not emptied if the root user opens and closes the device while another user is using effects. This is a minor change and most likely no force feedback aware programs are affected by this negatively. Otherwise the userspace interface is left unaltered. Signed-off-by: Anssi Hannula Signed-off-by: Dmitry Torokhov --- include/linux/input.h | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'include') diff --git a/include/linux/input.h b/include/linux/input.h index b3253ab72ff..81c6ea5afed 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -784,6 +784,9 @@ struct ff_effect { #define FF_INERTIA 0x56 #define FF_RAMP 0x57 +#define FF_EFFECT_MIN FF_RUMBLE +#define FF_EFFECT_MAX FF_RAMP + /* * Force feedback periodic effect types */ @@ -795,6 +798,9 @@ struct ff_effect { #define FF_SAW_DOWN 0x5c #define FF_CUSTOM 0x5d +#define FF_WAVEFORM_MIN FF_SQUARE +#define FF_WAVEFORM_MAX FF_CUSTOM + /* * Set ff device properties */ @@ -870,6 +876,8 @@ struct input_dev { unsigned int keycodesize; void *keycode; + struct ff_device *ff; + unsigned int repeat_key; struct timer_list timer; @@ -1108,5 +1116,58 @@ static inline void input_set_abs_params(struct input_dev *dev, int axis, int min extern struct class input_class; +/** + * struct ff_device - force-feedback part of an input device + * @upload: Called to upload an new effect into device + * @erase: Called to erase an effect from device + * @playback: Called to request device to start playing specified effect + * @set_gain: Called to set specified gain + * @set_autocenter: Called to auto-center device + * @destroy: called by input core when parent input device is being + * destroyed + * @private: driver-specific data, will be freed automatically + * @ffbit: bitmap of force feedback capabilities truly supported by + * device (not emulated like ones in input_dev->ffbit) + * @mutex: mutex for serializing access to the device + * @max_effects: maximum number of effects supported by device + * @effects: pointer to an array of effects currently loaded into device + * @effect_owners: array of effect owners; when file handle owning + * an effect gets closed the effcet is automatically erased + * + * Every force-feedback device must implement upload() and playback() + * methods; erase() is optional. set_gain() and set_autocenter() need + * only be implemented if driver sets up FF_GAIN and FF_AUTOCENTER + * bits. + */ +struct ff_device { + int (*upload)(struct input_dev *dev, struct ff_effect *effect, + struct ff_effect *old); + int (*erase)(struct input_dev *dev, int effect_id); + + int (*playback)(struct input_dev *dev, int effect_id, int value); + void (*set_gain)(struct input_dev *dev, u16 gain); + void (*set_autocenter)(struct input_dev *dev, u16 magnitude); + + void (*destroy)(struct ff_device *); + + void *private; + + unsigned long ffbit[NBITS(FF_MAX)]; + + struct mutex mutex; + + int max_effects; + struct ff_effect *effects; + struct file *effect_owners[]; +}; + +int input_ff_create(struct input_dev *dev, int max_effects); +void input_ff_destroy(struct input_dev *dev); + +int input_ff_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); + +int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, struct file *file); +int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file); + #endif #endif -- cgit v1.2.3-70-g09d2 From 7d928a2b14eede1f333db7b7b684c57f7fa7f456 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Wed, 19 Jul 2006 01:40:30 -0400 Subject: Input: unified force feedback support for memoryless devices Consolidate core implementing memoryless devices in one module; added support for gain and envelopes and periodic => rumble conversion. Signed-off-by: Anssi Hannula Signed-off-by: Dmitry Torokhov --- drivers/input/Kconfig | 14 ++ drivers/input/Makefile | 2 + drivers/input/ff-memless.c | 515 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/input.h | 3 + 4 files changed, 534 insertions(+) create mode 100644 drivers/input/ff-memless.c (limited to 'include') diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 58223b5d842..96232313b1b 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -24,6 +24,20 @@ config INPUT if INPUT +config INPUT_FF_MEMLESS + tristate "Support for memoryless force-feedback devices" + default n + ---help--- + Say Y here if you have memoryless force-feedback input device + such as Logitech WingMan Force 3D, ThrustMaster FireStorm Dual + Power 2, or similar. You will also need to enable hardware-specific + driver. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called ff-memless. + comment "Userland interfaces" config INPUT_MOUSEDEV diff --git a/drivers/input/Makefile b/drivers/input/Makefile index abdc9d43570..a005b1df5f1 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -7,6 +7,8 @@ obj-$(CONFIG_INPUT) += input-core.o input-core-objs := input.o ff-core.o +obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o + obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o obj-$(CONFIG_INPUT_JOYDEV) += joydev.o obj-$(CONFIG_INPUT_EVDEV) += evdev.o diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c new file mode 100644 index 00000000000..cd8b7297e6d --- /dev/null +++ b/drivers/input/ff-memless.c @@ -0,0 +1,515 @@ +/* + * Force feedback support for memoryless devices + * + * Copyright (c) 2006 Anssi Hannula + * Copyright (c) 2006 Dmitry Torokhov + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* #define DEBUG */ + +#define debug(format, arg...) pr_debug("ff-memless: " format "\n", ## arg) + +#include +#include +#include +#include +#include + +#include "fixp-arith.h" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Anssi Hannula "); +MODULE_DESCRIPTION("Force feedback support for memoryless devices"); + +/* Number of effects handled with memoryless devices */ +#define FF_MEMLESS_EFFECTS 16 + +/* Envelope update interval in ms */ +#define FF_ENVELOPE_INTERVAL 50 + +#define FF_EFFECT_STARTED 0 +#define FF_EFFECT_PLAYING 1 +#define FF_EFFECT_ABORTING 2 + +struct ml_effect_state { + struct ff_effect *effect; + unsigned long flags; /* effect state (STARTED, PLAYING, etc) */ + int count; /* loop count of the effect */ + unsigned long play_at; /* start time */ + unsigned long stop_at; /* stop time */ + unsigned long adj_at; /* last time the effect was sent */ +}; + +struct ml_device { + void *private; + struct ml_effect_state states[FF_MEMLESS_EFFECTS]; + int gain; + struct timer_list timer; + spinlock_t timer_lock; + struct input_dev *dev; + + int (*play_effect)(struct input_dev *dev, void *data, + struct ff_effect *effect); +}; + +static const struct ff_envelope *get_envelope(const struct ff_effect *effect) +{ + static const struct ff_envelope empty_envelope; + + switch (effect->type) { + case FF_PERIODIC: + return &effect->u.periodic.envelope; + case FF_CONSTANT: + return &effect->u.constant.envelope; + default: + return &empty_envelope; + } +} + +/* + * Check for the next time envelope requires an update on memoryless devices + */ +static unsigned long calculate_next_time(struct ml_effect_state *state) +{ + const struct ff_envelope *envelope = get_envelope(state->effect); + unsigned long attack_stop, fade_start, next_fade; + + if (envelope->attack_length) { + attack_stop = state->play_at + + msecs_to_jiffies(envelope->attack_length); + if (time_before(state->adj_at, attack_stop)) + return state->adj_at + + msecs_to_jiffies(FF_ENVELOPE_INTERVAL); + } + + if (state->effect->replay.length) { + if (envelope->fade_length) { + /* check when fading should start */ + fade_start = state->stop_at - + msecs_to_jiffies(envelope->fade_length); + + if (time_before(state->adj_at, fade_start)) + return fade_start; + + /* already fading, advance to next checkpoint */ + next_fade = state->adj_at + + msecs_to_jiffies(FF_ENVELOPE_INTERVAL); + if (time_before(next_fade, state->stop_at)) + return next_fade; + } + + return state->stop_at; + } + + return state->play_at; +} + +static void ml_schedule_timer(struct ml_device *ml) +{ + struct ml_effect_state *state; + unsigned long now = jiffies; + unsigned long earliest = 0; + unsigned long next_at; + int events = 0; + int i; + + debug("calculating next timer"); + + for (i = 0; i < FF_MEMLESS_EFFECTS; i++) { + + state = &ml->states[i]; + + if (!test_bit(FF_EFFECT_STARTED, &state->flags)) + continue; + + if (test_bit(FF_EFFECT_PLAYING, &state->flags)) + next_at = calculate_next_time(state); + else + next_at = state->play_at; + + if (time_before_eq(now, next_at) && + (++events == 1 || time_before(next_at, earliest))) + earliest = next_at; + } + + if (!events) { + debug("no actions"); + del_timer(&ml->timer); + } else { + debug("timer set"); + mod_timer(&ml->timer, earliest); + } +} + +/* + * Apply an envelope to a value + */ +static int apply_envelope(struct ml_effect_state *state, int value, + struct ff_envelope *envelope) +{ + struct ff_effect *effect = state->effect; + unsigned long now = jiffies; + int time_from_level; + int time_of_envelope; + int envelope_level; + int difference; + + if (envelope->attack_length && + time_before(now, + state->play_at + msecs_to_jiffies(envelope->attack_length))) { + debug("value = 0x%x, attack_level = 0x%x", value, + envelope->attack_level); + time_from_level = jiffies_to_msecs(now - state->play_at); + time_of_envelope = envelope->attack_length; + envelope_level = min_t(__s16, envelope->attack_level, 0x7fff); + + } else if (envelope->fade_length && effect->replay.length && + time_after(now, + state->stop_at - msecs_to_jiffies(envelope->fade_length)) && + time_before(now, state->stop_at)) { + time_from_level = jiffies_to_msecs(state->stop_at - now); + time_of_envelope = envelope->fade_length; + envelope_level = min_t(__s16, envelope->fade_level, 0x7fff); + } else + return value; + + difference = abs(value) - envelope_level; + + debug("difference = %d", difference); + debug("time_from_level = 0x%x", time_from_level); + debug("time_of_envelope = 0x%x", time_of_envelope); + + difference = difference * time_from_level / time_of_envelope; + + debug("difference = %d", difference); + + return value < 0 ? + -(difference + envelope_level) : (difference + envelope_level); +} + +/* + * Return the type the effect has to be converted into (memless devices) + */ +static int get_compatible_type(struct ff_device *ff, int effect_type) +{ + + if (test_bit(effect_type, ff->ffbit)) + return effect_type; + + if (effect_type == FF_PERIODIC && test_bit(FF_RUMBLE, ff->ffbit)) + return FF_RUMBLE; + + printk(KERN_ERR + "ff-memless: invalid type in get_compatible_type()\n"); + + return 0; +} + +/* + * Combine two effects and apply gain. + */ +static void ml_combine_effects(struct ff_effect *effect, + struct ml_effect_state *state, + int gain) +{ + struct ff_effect *new = state->effect; + unsigned int strong, weak, i; + int x, y; + fixp_t level; + + switch (new->type) { + case FF_CONSTANT: + i = new->direction * 360 / 0xffff; + level = fixp_new16(apply_envelope(state, + new->u.constant.level, + &new->u.constant.envelope)); + x = fixp_mult(fixp_sin(i), level) * gain / 0xffff; + y = fixp_mult(-fixp_cos(i), level) * gain / 0xffff; + /* + * here we abuse ff_ramp to hold x and y of constant force + * If in future any driver wants something else than x and y + * in s8, this should be changed to something more generic + */ + effect->u.ramp.start_level = + max(min(effect->u.ramp.start_level + x, 0x7f), -0x80); + effect->u.ramp.end_level = + max(min(effect->u.ramp.end_level + y, 0x7f), -0x80); + break; + + case FF_RUMBLE: + strong = new->u.rumble.strong_magnitude * gain / 0xffff; + weak = new->u.rumble.weak_magnitude * gain / 0xffff; + effect->u.rumble.strong_magnitude = + min(strong + effect->u.rumble.strong_magnitude, + 0xffffU); + effect->u.rumble.weak_magnitude = + min(weak + effect->u.rumble.weak_magnitude, 0xffffU); + break; + + case FF_PERIODIC: + i = apply_envelope(state, abs(new->u.periodic.magnitude), + &new->u.periodic.envelope); + + /* here we also scale it 0x7fff => 0xffff */ + i = i * gain / 0x7fff; + + effect->u.rumble.strong_magnitude = + min(i + effect->u.rumble.strong_magnitude, 0xffffU); + effect->u.rumble.weak_magnitude = + min(i + effect->u.rumble.weak_magnitude, 0xffffU); + break; + + default: + printk(KERN_ERR "ff-memless: invalid type in ml_combine_effects()\n"); + break; + } + +} + + +/* + * Because memoryless devices have only one effect per effect type active + * at one time we have to combine multiple effects into one + */ +static int ml_get_combo_effect(struct ml_device *ml, + unsigned long *effect_handled, + struct ff_effect *combo_effect) +{ + struct ff_effect *effect; + struct ml_effect_state *state; + int effect_type; + int i; + + memset(combo_effect, 0, sizeof(struct ff_effect)); + + for (i = 0; i < FF_MEMLESS_EFFECTS; i++) { + if (__test_and_set_bit(i, effect_handled)) + continue; + + state = &ml->states[i]; + effect = state->effect; + + if (!test_bit(FF_EFFECT_STARTED, &state->flags)) + continue; + + if (time_before(jiffies, state->play_at)) + continue; + + /* + * here we have started effects that are either + * currently playing (and may need be aborted) + * or need to start playing. + */ + effect_type = get_compatible_type(ml->dev->ff, effect->type); + if (combo_effect->type != effect_type) { + if (combo_effect->type != 0) { + __clear_bit(i, effect_handled); + continue; + } + combo_effect->type = effect_type; + } + + if (__test_and_clear_bit(FF_EFFECT_ABORTING, &state->flags)) { + __clear_bit(FF_EFFECT_PLAYING, &state->flags); + __clear_bit(FF_EFFECT_STARTED, &state->flags); + } else if (effect->replay.length && + time_after_eq(jiffies, state->stop_at)) { + + __clear_bit(FF_EFFECT_PLAYING, &state->flags); + + if (--state->count <= 0) { + __clear_bit(FF_EFFECT_STARTED, &state->flags); + } else { + state->play_at = jiffies + + msecs_to_jiffies(effect->replay.delay); + state->stop_at = state->play_at + + msecs_to_jiffies(effect->replay.length); + } + } else { + __set_bit(FF_EFFECT_PLAYING, &state->flags); + state->adj_at = jiffies; + ml_combine_effects(combo_effect, state, ml->gain); + } + } + + return combo_effect->type != 0; +} + +static void ml_play_effects(struct ml_device *ml) +{ + struct ff_effect effect; + DECLARE_BITMAP(handled_bm, FF_MEMLESS_EFFECTS); + + memset(handled_bm, 0, sizeof(handled_bm)); + + while (ml_get_combo_effect(ml, handled_bm, &effect)) + ml->play_effect(ml->dev, ml->private, &effect); + + ml_schedule_timer(ml); +} + +static void ml_effect_timer(unsigned long timer_data) +{ + struct input_dev *dev = (struct input_dev *)timer_data; + struct ml_device *ml = dev->ff->private; + + debug("timer: updating effects"); + + spin_lock(&ml->timer_lock); + ml_play_effects(ml); + spin_unlock(&ml->timer_lock); +} + +static void ml_ff_set_gain(struct input_dev *dev, u16 gain) +{ + struct ml_device *ml = dev->ff->private; + int i; + + spin_lock_bh(&ml->timer_lock); + + ml->gain = gain; + + for (i = 0; i < FF_MEMLESS_EFFECTS; i++) + __clear_bit(FF_EFFECT_PLAYING, &ml->states[i].flags); + + ml_play_effects(ml); + + spin_unlock_bh(&ml->timer_lock); +} + +static int ml_ff_playback(struct input_dev *dev, int effect_id, int value) +{ + struct ml_device *ml = dev->ff->private; + struct ml_effect_state *state = &ml->states[effect_id]; + + spin_lock_bh(&ml->timer_lock); + + if (value > 0) { + debug("initiated play"); + + __set_bit(FF_EFFECT_STARTED, &state->flags); + state->count = value; + state->play_at = jiffies + + msecs_to_jiffies(state->effect->replay.delay); + state->stop_at = state->play_at + + msecs_to_jiffies(state->effect->replay.length); + state->adj_at = state->play_at; + + ml_schedule_timer(ml); + + } else { + debug("initiated stop"); + + if (test_bit(FF_EFFECT_PLAYING, &state->flags)) + __set_bit(FF_EFFECT_ABORTING, &state->flags); + else + __clear_bit(FF_EFFECT_STARTED, &state->flags); + + ml_play_effects(ml); + } + + spin_unlock_bh(&ml->timer_lock); + + return 0; +} + +static int ml_ff_upload(struct input_dev *dev, + struct ff_effect *effect, struct ff_effect *old) +{ + struct ml_device *ml = dev->ff->private; + struct ml_effect_state *state = &ml->states[effect->id]; + + spin_lock_bh(&ml->timer_lock); + + if (test_bit(FF_EFFECT_STARTED, &state->flags)) { + __clear_bit(FF_EFFECT_PLAYING, &state->flags); + state->play_at = jiffies + + msecs_to_jiffies(state->effect->replay.delay); + state->stop_at = state->play_at + + msecs_to_jiffies(state->effect->replay.length); + state->adj_at = state->play_at; + ml_schedule_timer(ml); + } + + spin_unlock_bh(&ml->timer_lock); + + return 0; +} + +static void ml_ff_destroy(struct ff_device *ff) +{ + struct ml_device *ml = ff->private; + + kfree(ml->private); +} + +/** + * input_ff_create_memless() - create memoryless FF device + * @dev: input device supporting force-feedback + * @data: driver-specific data to be passed into @play_effect + * @play_effect: driver-specific method for playing FF effect + */ +int input_ff_create_memless(struct input_dev *dev, void *data, + int (*play_effect)(struct input_dev *, void *, struct ff_effect *)) +{ + struct ml_device *ml; + struct ff_device *ff; + int error; + int i; + + ml = kzalloc(sizeof(struct ml_device), GFP_KERNEL); + if (!ml) + return -ENOMEM; + + ml->dev = dev; + ml->private = data; + ml->play_effect = play_effect; + ml->gain = 0xffff; + spin_lock_init(&ml->timer_lock); + setup_timer(&ml->timer, ml_effect_timer, (unsigned long)dev); + + set_bit(FF_GAIN, dev->ffbit); + + error = input_ff_create(dev, FF_MEMLESS_EFFECTS); + if (error) { + kfree(ml); + return error; + } + + ff = dev->ff; + ff->private = ml; + ff->upload = ml_ff_upload; + ff->playback = ml_ff_playback; + ff->set_gain = ml_ff_set_gain; + ff->destroy = ml_ff_destroy; + + /* we can emulate periodic effects with RUMBLE */ + if (test_bit(FF_RUMBLE, ff->ffbit)) { + set_bit(FF_PERIODIC, dev->ffbit); + set_bit(FF_SINE, dev->ffbit); + set_bit(FF_TRIANGLE, dev->ffbit); + set_bit(FF_SQUARE, dev->ffbit); + } + + for (i = 0; i < FF_MEMLESS_EFFECTS; i++) + ml->states[i].effect = &ff->effects[i]; + + return 0; +} +EXPORT_SYMBOL_GPL(input_ff_create_memless); diff --git a/include/linux/input.h b/include/linux/input.h index 81c6ea5afed..d8b0c5610c0 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1169,5 +1169,8 @@ int input_ff_event(struct input_dev *dev, unsigned int type, unsigned int code, int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, struct file *file); int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file); +int input_ff_create_memless(struct input_dev *dev, void *data, + int (*play_effect)(struct input_dev *, void *, struct ff_effect *)); + #endif #endif -- cgit v1.2.3-70-g09d2 From ff462551235d8d7d843a005950bc90924fcedede Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Wed, 19 Jul 2006 01:41:09 -0400 Subject: Input: uinput - switch to the new FF interface The userspace interface of the force feedback part is changed and documentation in uinput.h is updated accordingly. MODULE_VERSION is also incremented to reflect the revision. Signed-off-by: Anssi Hannula Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 67 ++++++++++++++++++++++++++++++++++----------- include/linux/uinput.h | 35 +++++++++++++++-------- 2 files changed, 74 insertions(+), 28 deletions(-) (limited to 'include') diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index d723e9ad7c4..9516439b7c7 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -20,6 +20,9 @@ * Author: Aristeu Sergio Rozanski Filho * * Changes/Revisions: + * 0.3 09/04/2006 (Anssi Hannula ) + * - updated ff support for the changes in kernel interface + * - added MODULE_VERSION * 0.2 16/10/2004 (Micah Dowty ) * - added force feedback support * - added UI_SET_PHYS @@ -107,18 +110,31 @@ static int uinput_request_submit(struct input_dev *dev, struct uinput_request *r return request->retval; } -static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect) +static void uinput_dev_set_gain(struct input_dev *dev, u16 gain) +{ + uinput_dev_event(dev, EV_FF, FF_GAIN, gain); +} + +static void uinput_dev_set_autocenter(struct input_dev *dev, u16 magnitude) +{ + uinput_dev_event(dev, EV_FF, FF_AUTOCENTER, magnitude); +} + +static int uinput_dev_playback(struct input_dev *dev, int effect_id, int value) +{ + return uinput_dev_event(dev, EV_FF, effect_id, value); +} + +static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old) { struct uinput_request request; int retval; - if (!test_bit(EV_FF, dev->evbit)) - return -ENOSYS; - request.id = -1; init_completion(&request.done); request.code = UI_FF_UPLOAD; - request.u.effect = effect; + request.u.upload.effect = effect; + request.u.upload.old = old; retval = uinput_request_reserve_slot(dev->private, &request); if (!retval) @@ -168,6 +184,7 @@ static void uinput_destroy_device(struct uinput_device *udev) static int uinput_create_device(struct uinput_device *udev) { + struct input_dev *dev = udev->dev; int error; if (udev->state != UIST_SETUP_COMPLETE) { @@ -175,15 +192,29 @@ static int uinput_create_device(struct uinput_device *udev) return -EINVAL; } - error = input_register_device(udev->dev); - if (error) { - uinput_destroy_device(udev); - return error; + if (udev->ff_effects_max) { + error = input_ff_create(dev, udev->ff_effects_max); + if (error) + goto fail1; + + dev->ff->upload = uinput_dev_upload_effect; + dev->ff->erase = uinput_dev_erase_effect; + dev->ff->playback = uinput_dev_playback; + dev->ff->set_gain = uinput_dev_set_gain; + dev->ff->set_autocenter = uinput_dev_set_autocenter; } + error = input_register_device(udev->dev); + if (error) + goto fail2; + udev->state = UIST_CREATED; return 0; + + fail2: input_ff_destroy(dev); + fail1: uinput_destroy_device(udev); + return error; } static int uinput_open(struct inode *inode, struct file *file) @@ -243,8 +274,6 @@ static int uinput_allocate_device(struct uinput_device *udev) return -ENOMEM; udev->dev->event = uinput_dev_event; - udev->dev->upload_effect = uinput_dev_upload_effect; - udev->dev->erase_effect = uinput_dev_erase_effect; udev->dev->private = udev; return 0; @@ -278,6 +307,8 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu 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; @@ -296,7 +327,6 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu dev->id.vendor = user_dev->id.vendor; dev->id.product = user_dev->id.product; dev->id.version = user_dev->id.version; - dev->ff_effects_max = user_dev->ff_effects_max; size = sizeof(int) * (ABS_MAX + 1); memcpy(dev->absmax, user_dev->absmax, size); @@ -525,12 +555,17 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; } req = uinput_request_find(udev, ff_up.request_id); - if (!(req && req->code == UI_FF_UPLOAD && req->u.effect)) { + if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) { retval = -EINVAL; break; } ff_up.retval = 0; - memcpy(&ff_up.effect, req->u.effect, sizeof(struct ff_effect)); + memcpy(&ff_up.effect, req->u.upload.effect, sizeof(struct ff_effect)); + if (req->u.upload.old) + memcpy(&ff_up.old, req->u.upload.old, sizeof(struct ff_effect)); + else + memset(&ff_up.old, 0, sizeof(struct ff_effect)); + if (copy_to_user(p, &ff_up, sizeof(ff_up))) { retval = -EFAULT; break; @@ -561,12 +596,11 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; } req = uinput_request_find(udev, ff_up.request_id); - if (!(req && req->code == UI_FF_UPLOAD && req->u.effect)) { + if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) { retval = -EINVAL; break; } req->retval = ff_up.retval; - memcpy(req->u.effect, &ff_up.effect, sizeof(struct ff_effect)); uinput_request_done(udev, req); break; @@ -622,6 +656,7 @@ static void __exit uinput_exit(void) MODULE_AUTHOR("Aristeu Sergio Rozanski Filho"); MODULE_DESCRIPTION("User level driver support for input subsystem"); MODULE_LICENSE("GPL"); +MODULE_VERSION("0.3"); module_init(uinput_init); module_exit(uinput_exit); diff --git a/include/linux/uinput.h b/include/linux/uinput.h index 7168302f984..1fd61eeed66 100644 --- a/include/linux/uinput.h +++ b/include/linux/uinput.h @@ -22,12 +22,18 @@ * Author: Aristeu Sergio Rozanski Filho * * Changes/Revisions: + * 0.3 24/05/2006 (Anssi Hannula ) + * - update ff support for the changes in kernel interface + * - add UINPUT_VERSION * 0.2 16/10/2004 (Micah Dowty ) * - added force feedback support * - added UI_SET_PHYS * 0.1 20/06/2002 * - first public version */ + +#define UINPUT_VERSION 3 + #ifdef __KERNEL__ #define UINPUT_MINOR 223 #define UINPUT_NAME "uinput" @@ -45,7 +51,10 @@ struct uinput_request { union { int effect_id; - struct ff_effect* effect; + struct { + struct ff_effect *effect; + struct ff_effect *old; + } upload; } u; }; @@ -58,6 +67,7 @@ struct uinput_device { unsigned char head; unsigned char tail; struct input_event buff[UINPUT_BUFFER_SIZE]; + int ff_effects_max; struct uinput_request *requests[UINPUT_NUM_REQUESTS]; wait_queue_head_t requests_waitq; @@ -69,6 +79,7 @@ struct uinput_ff_upload { int request_id; int retval; struct ff_effect effect; + struct ff_effect old; }; struct uinput_ff_erase { @@ -98,33 +109,33 @@ struct uinput_ff_erase { #define UI_BEGIN_FF_ERASE _IOWR(UINPUT_IOCTL_BASE, 202, struct uinput_ff_erase) #define UI_END_FF_ERASE _IOW(UINPUT_IOCTL_BASE, 203, struct uinput_ff_erase) -/* To write a force-feedback-capable driver, the upload_effect +/* + * To write a force-feedback-capable driver, the upload_effect * and erase_effect callbacks in input_dev must be implemented. * The uinput driver will generate a fake input event when one of * these callbacks are invoked. The userspace code then uses * ioctls to retrieve additional parameters and send the return code. * The callback blocks until this return code is sent. * - * The described callback mechanism is only used if EV_FF is set. - * Otherwise, default implementations of upload_effect and erase_effect - * are used. + * The described callback mechanism is only used if ff_effects_max + * is set. * * To implement upload_effect(): - * 1. Wait for an event with type==EV_UINPUT and code==UI_FF_UPLOAD. + * 1. Wait for an event with type == EV_UINPUT and code == UI_FF_UPLOAD. * A request ID will be given in 'value'. * 2. Allocate a uinput_ff_upload struct, fill in request_id with * the 'value' from the EV_UINPUT event. * 3. Issue a UI_BEGIN_FF_UPLOAD ioctl, giving it the * uinput_ff_upload struct. It will be filled in with the - * ff_effect passed to upload_effect(). - * 4. Perform the effect upload, and place the modified ff_effect - * and a return code back into the uinput_ff_upload struct. + * ff_effects passed to upload_effect(). + * 4. Perform the effect upload, and place a return code back into + the uinput_ff_upload struct. * 5. Issue a UI_END_FF_UPLOAD ioctl, also giving it the * uinput_ff_upload_effect struct. This will complete execution * of our upload_effect() handler. * * To implement erase_effect(): - * 1. Wait for an event with type==EV_UINPUT and code==UI_FF_ERASE. + * 1. Wait for an event with type == EV_UINPUT and code == UI_FF_ERASE. * A request ID will be given in 'value'. * 2. Allocate a uinput_ff_erase struct, fill in request_id with * the 'value' from the EV_UINPUT event. @@ -133,13 +144,13 @@ struct uinput_ff_erase { * effect ID passed to erase_effect(). * 4. Perform the effect erasure, and place a return code back * into the uinput_ff_erase struct. - * and a return code back into the uinput_ff_erase struct. * 5. Issue a UI_END_FF_ERASE ioctl, also giving it the * uinput_ff_erase_effect struct. This will complete execution * of our erase_effect() handler. */ -/* This is the new event type, used only by uinput. +/* + * This is the new event type, used only by uinput. * 'code' is UI_FF_UPLOAD or UI_FF_ERASE, and 'value' * is the unique request ID. This number was picked * arbitrarily, above EV_MAX (since the input system -- cgit v1.2.3-70-g09d2 From 1f734cb461e1f029d751deb15c8d9f8137fb2ca7 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Wed, 19 Jul 2006 01:44:08 -0400 Subject: Input: drop remnants of the old force-feedback interface Signed-off-by: Anssi Hannula Signed-off-by: Dmitry Torokhov --- include/linux/input.h | 8 -------- 1 file changed, 8 deletions(-) (limited to 'include') diff --git a/include/linux/input.h b/include/linux/input.h index d8b0c5610c0..4405d028354 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -870,7 +870,6 @@ struct input_dev { unsigned long sndbit[NBITS(SND_MAX)]; unsigned long ffbit[NBITS(FF_MAX)]; unsigned long swbit[NBITS(SW_MAX)]; - int ff_effects_max; unsigned int keycodemax; unsigned int keycodesize; @@ -903,8 +902,6 @@ struct input_dev { void (*close)(struct input_dev *dev); int (*flush)(struct input_dev *dev, struct file *file); int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); - int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect); - int (*erase_effect)(struct input_dev *dev, int effect_id); struct input_handle *grab; @@ -1078,11 +1075,6 @@ static inline void input_report_abs(struct input_dev *dev, unsigned int code, in input_event(dev, EV_ABS, code, value); } -static inline void input_report_ff(struct input_dev *dev, unsigned int code, int value) -{ - input_event(dev, EV_FF, code, value); -} - static inline void input_report_ff_status(struct input_dev *dev, unsigned int code, int value) { input_event(dev, EV_FF_STATUS, code, value); -- cgit v1.2.3-70-g09d2 From 8b8277a17477de38d8df6783e8221aed55bab300 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Wed, 19 Jul 2006 01:44:22 -0400 Subject: Input: update the force feedback documentation Signed-off-by: Anssi Hannula Signed-off-by: Dmitry Torokhov --- Documentation/input/ff.txt | 112 ++++++++++++++--------------- include/linux/input.h | 175 +++++++++++++++++++++++++++++++-------------- 2 files changed, 174 insertions(+), 113 deletions(-) (limited to 'include') diff --git a/Documentation/input/ff.txt b/Documentation/input/ff.txt index c7e10eaff20..c53b1c11aa4 100644 --- a/Documentation/input/ff.txt +++ b/Documentation/input/ff.txt @@ -1,67 +1,37 @@ Force feedback for Linux. By Johann Deneux on 2001/04/22. +Updated by Anssi Hannula on 2006/04/09. You may redistribute this file. Please remember to include shape.fig and interactive.fig as well. ---------------------------------------------------------------------------- -0. Introduction +1. Introduction ~~~~~~~~~~~~~~~ This document describes how to use force feedback devices under Linux. The goal is not to support these devices as if they were simple input-only devices (as it is already the case), but to really enable the rendering of force effects. -At the moment, only I-Force devices are supported, and not officially. That -means I had to find out how the protocol works on my own. Of course, the -information I managed to grasp is far from being complete, and I can not -guarranty that this driver will work for you. -This document only describes the force feedback part of the driver for I-Force -devices. Please read joystick.txt before reading further this document. +This document only describes the force feedback part of the Linux input +interface. Please read joystick.txt and input.txt before reading further this +document. 2. Instructions to the user ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Here are instructions on how to compile and use the driver. In fact, this -driver is the normal iforce, input and evdev drivers written by Vojtech -Pavlik, plus additions to support force feedback. +To enable force feedback, you have to: + +1. have your kernel configured with evdev and a driver that supports your + device. +2. make sure evdev module is loaded and /dev/input/event* device files are + created. Before you start, let me WARN you that some devices shake violently during the initialisation phase. This happens for example with my "AVB Top Shot Pegasus". To stop this annoying behaviour, move you joystick to its limits. Anyway, you -should keep a hand on your device, in order to avoid it to brake down if +should keep a hand on your device, in order to avoid it to break down if something goes wrong. -At the kernel's compilation: - - Enable IForce/Serial - - Enable Event interface - -Compile the modules, install them. - -You also need inputattach. - -You then need to insert the modules into the following order: -% modprobe joydev -% modprobe serport # Only for serial -% modprobe iforce -% modprobe evdev -% ./inputattach -ifor $2 & # Only for serial -If you are using USB, you don't need the inputattach step. - -Please check that you have all the /dev/input entries needed: -cd /dev -rm js* -mkdir input -mknod input/js0 c 13 0 -mknod input/js1 c 13 1 -mknod input/js2 c 13 2 -mknod input/js3 c 13 3 -ln -s input/js0 js0 -ln -s input/js1 js1 -ln -s input/js2 js2 -ln -s input/js3 js3 - -mknod input/event0 c 13 64 -mknod input/event1 c 13 65 -mknod input/event2 c 13 66 -mknod input/event3 c 13 67 +If you have a serial iforce device, you need to start inputattach. See +joystick.txt for details. 2.1 Does it work ? ~~~~~~~~~~~~~~~~~~ @@ -70,9 +40,9 @@ There is an utility called fftest that will allow you to test the driver. 3. Instructions to the developper ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - All interactions are done using the event API. That is, you can use ioctl() +All interactions are done using the event API. That is, you can use ioctl() and write() on /dev/input/eventXX. - This information is subject to change. +This information is subject to change. 3.1 Querying device capabilities ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -86,18 +56,29 @@ int ioctl(int file_descriptor, int request, unsigned long *features); Returns the features supported by the device. features is a bitfield with the following bits: -- FF_X has an X axis (usually joysticks) -- FF_Y has an Y axis (usually joysticks) -- FF_WHEEL has a wheel (usually sterring wheels) - FF_CONSTANT can render constant force effects -- FF_PERIODIC can render periodic effects (sine, triangle, square...) +- FF_PERIODIC can render periodic effects with the following waveforms: + - FF_SQUARE square waveform + - FF_TRIANGLE triangle waveform + - FF_SINE sine waveform + - FF_SAW_UP sawtooth up waveform + - FF_SAW_DOWN sawtooth down waveform + - FF_CUSTOM custom waveform - FF_RAMP can render ramp effects - FF_SPRING can simulate the presence of a spring -- FF_FRICTION can simulate friction +- FF_FRICTION can simulate friction - FF_DAMPER can simulate damper effects -- FF_RUMBLE rumble effects (normally the only effect supported by rumble - pads) +- FF_RUMBLE rumble effects - FF_INERTIA can simulate inertia +- FF_GAIN gain is adjustable +- FF_AUTOCENTER autocenter is adjustable + +Note: In most cases you should use FF_PERIODIC instead of FF_RUMBLE. All + devices that support FF_RUMBLE support FF_PERIODIC (square, triangle, + sine) and the other way around. + +Note: The exact syntax FF_CUSTOM is undefined for the time being as no driver + supports it yet. int ioctl(int fd, EVIOCGEFFECTS, int *n); @@ -108,7 +89,7 @@ Returns the number of effects the device can keep in its memory. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #include #include - + int ioctl(int file_descriptor, int request, struct ff_effect *effect); "request" must be EVIOCSFF. @@ -120,6 +101,9 @@ to the unique id assigned by the driver. This data is required for performing some operations (removing an effect, controlling the playback). This if field must be set to -1 by the user in order to tell the driver to allocate a new effect. + +Effects are file descriptor specific. + See for a description of the ff_effect struct. You should also find help in a few sketches, contained in files shape.fig and interactive.fig. You need xfig to visualize these files. @@ -128,8 +112,8 @@ You need xfig to visualize these files. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ int ioctl(int fd, EVIOCRMFF, effect.id); -This makes room for new effects in the device's memory. Please note this won't -stop the effect if it was playing. +This makes room for new effects in the device's memory. Note that this also +stops the effect if it was playing. 3.4 Controlling the playback of effects ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -149,22 +133,21 @@ Control of playing is done with write(). Below is an example: play.type = EV_FF; play.code = effect.id; play.value = 3; - + write(fd, (const void*) &play, sizeof(play)); ... /* Stop an effect */ stop.type = EV_FF; stop.code = effect.id; stop.value = 0; - + write(fd, (const void*) &play, sizeof(stop)); 3.5 Setting the gain ~~~~~~~~~~~~~~~~~~~~ Not all devices have the same strength. Therefore, users should set a gain factor depending on how strong they want effects to be. This setting is -persistent across access to the driver, so you should not care about it if -you are writing games, as another utility probably already set this for you. +persistent across access to the driver. /* Set the gain of the device int gain; /* between 0 and 100 */ @@ -204,11 +187,14 @@ type of device, not all parameters can be dynamically updated. For example, the direction of an effect cannot be updated with iforce devices. In this case, the driver stops the effect, up-load it, and restart it. +Therefore it is recommended to dynamically change direction while the effect +is playing only when it is ok to restart the effect with a replay count of 1. 3.8 Information about the status of effects ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Every time the status of an effect is changed, an event is sent. The values and meanings of the fields of the event are as follows: + struct input_event { /* When the status of the effect changed */ struct timeval time; @@ -225,3 +211,9 @@ struct input_event { FF_STATUS_STOPPED The effect stopped playing FF_STATUS_PLAYING The effect started to play + +NOTE: Status feedback is only supported by iforce driver. If you have + a really good reason to use this, please contact + linux-joystick@atrey.karlin.mff.cuni.cz or anssi.hannula@gmail.com + so that support for it can be added to the rest of the drivers. + diff --git a/include/linux/input.h b/include/linux/input.h index 4405d028354..a7a1f55a5ee 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -667,98 +667,167 @@ struct input_absinfo { /* * Structures used in ioctls to upload effects to a device - * The first structures are not passed directly by using ioctls. - * They are sub-structures of the actually sent structure (called ff_effect) + * They are pieces of a bigger structure (called ff_effect) */ +/* + * All duration values are expressed in ms. Values above 32767 ms (0x7fff) + * should not be used and have unspecified results. + */ + +/** + * struct ff_replay - defines scheduling of the effect + * @length: duration of the effect + * @delay: delay before effect should start playing + */ struct ff_replay { - __u16 length; /* Duration of an effect in ms. All other times are also expressed in ms */ - __u16 delay; /* Time to wait before to start playing an effect */ + __u16 length; + __u16 delay; }; +/** + * struct ff_trigger - defines what triggers the effect + * @button: number of the button triggering the effect + * @interval: controls how soon the effect can be re-triggered + */ struct ff_trigger { - __u16 button; /* Number of button triggering an effect */ - __u16 interval; /* Time to wait before an effect can be re-triggered (ms) */ + __u16 button; + __u16 interval; }; +/** + * struct ff_envelope - generic effect envelope + * @attack_length: duration of the attack (ms) + * @attack_level: level at the beginning of the attack + * @fade_length: duration of fade (ms) + * @fade_level: level at the end of fade + * + * The @attack_level and @fade_level are absolute values; when applying + * envelope force-feedback core will convert to positive/negative + * value based on polarity of the default level of the effect. + * Valid range for the attack and fade levels is 0x0000 - 0x7fff + */ struct ff_envelope { - __u16 attack_length; /* Duration of attack (ms) */ - __u16 attack_level; /* Level at beginning of attack */ - __u16 fade_length; /* Duration of fade (ms) */ - __u16 fade_level; /* Level at end of fade */ + __u16 attack_length; + __u16 attack_level; + __u16 fade_length; + __u16 fade_level; }; -/* FF_CONSTANT */ +/** + * struct ff_constant_effect - defines parameters of a constant effect + * @level: strength of the effect; may be negative + * @envelope: envelope data + */ struct ff_constant_effect { - __s16 level; /* Strength of effect. Negative values are OK */ + __s16 level; struct ff_envelope envelope; }; -/* FF_RAMP */ +/** + * struct ff_ramp_effect - defines parameters of a ramp effect + * @start_level: beginning strength of the effect; may be negative + * @end_level: final strength of the effect; may be negative + * @envelope: envelope data + */ struct ff_ramp_effect { __s16 start_level; __s16 end_level; struct ff_envelope envelope; }; -/* FF_SPRING of FF_FRICTION */ +/** + * struct ff_condition_effect - defines a spring or friction effect + * @right_saturation: maximum level when joystick moved all way to the right + * @left_saturation: same for the left side + * @right_coeff: controls how fast the force grows when the joystick moves + * to the right + * @left_coeff: same for the left side + * @deadband: size of the dead zone, where no force is produced + * @center: position of the dead zone + */ struct ff_condition_effect { - __u16 right_saturation; /* Max level when joystick is on the right */ - __u16 left_saturation; /* Max level when joystick in on the left */ + __u16 right_saturation; + __u16 left_saturation; - __s16 right_coeff; /* Indicates how fast the force grows when the - joystick moves to the right */ - __s16 left_coeff; /* Same for left side */ - - __u16 deadband; /* Size of area where no force is produced */ - __s16 center; /* Position of dead zone */ + __s16 right_coeff; + __s16 left_coeff; + __u16 deadband; + __s16 center; }; -/* FF_PERIODIC */ +/** + * struct ff_periodic_effect - defines parameters of a periodic effect + * @waveform: kind of the effect (wave) + * @period: period of the wave (ms) + * @magnitude: peak value + * @offset: mean value of the wave (roughly) + * @phase: 'horizontal' shift + * @envelope: envelope data + * @custom_len: number of samples (FF_CUSTOM only) + * @custom_data: buffer of samples (FF_CUSTOM only) + * + * Known waveforms - FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, + * FF_SAW_DOWN, FF_CUSTOM. The exact syntax FF_CUSTOM is undefined + * for the time being as no driver supports it yet. + * + * Note: the data pointed by custom_data is copied by the driver. + * You can therefore dispose of the memory after the upload/update. + */ struct ff_periodic_effect { - __u16 waveform; /* Kind of wave (sine, square...) */ - __u16 period; /* in ms */ - __s16 magnitude; /* Peak value */ - __s16 offset; /* Mean value of wave (roughly) */ - __u16 phase; /* 'Horizontal' shift */ + __u16 waveform; + __u16 period; + __s16 magnitude; + __s16 offset; + __u16 phase; struct ff_envelope envelope; -/* Only used if waveform == FF_CUSTOM */ - __u32 custom_len; /* Number of samples */ - __s16 *custom_data; /* Buffer of samples */ -/* Note: the data pointed by custom_data is copied by the driver. You can - * therefore dispose of the memory after the upload/update */ + __u32 custom_len; + __s16 *custom_data; }; -/* FF_RUMBLE */ -/* Some rumble pads have two motors of different weight. - strong_magnitude represents the magnitude of the vibration generated - by the heavy motor. -*/ +/** + * struct ff_rumble_effect - defines parameters of a periodic effect + * @strong_magnitude: magnitude of the heavy motor + * @weak_magnitude: magnitude of the light one + * + * Some rumble pads have two motors of different weight. Strong_magnitude + * represents the magnitude of the vibration generated by the heavy one. + */ struct ff_rumble_effect { - __u16 strong_magnitude; /* Magnitude of the heavy motor */ - __u16 weak_magnitude; /* Magnitude of the light one */ + __u16 strong_magnitude; + __u16 weak_magnitude; }; -/* - * Structure sent through ioctl from the application to the driver +/** + * struct ff_effect - defines force feedback effect + * @type: type of the effect (FF_CONSTANT, FF_PERIODIC, FF_RAMP, FF_SPRING, + * FF_FRICTION, FF_DAMPER, FF_RUMBLE, FF_INERTIA, or FF_CUSTOM) + * @id: an unique id assigned to an effect + * @direction: direction of the effect + * @trigger: trigger conditions (struct ff_trigger) + * @replay: scheduling of the effect (struct ff_replay) + * @u: effect-specific structure (one of ff_constant_effect, ff_ramp_effect, + * ff_periodic_effect, ff_condition_effect, ff_rumble_effect) further + * defining effect parameters + * + * This structure is sent through ioctl from the application to the driver. + * To create a new effect aplication should set its @id to -1; the kernel + * will return assigned @id which can later be used to update or delete + * this effect. + * + * Direction of the effect is encoded as follows: + * 0 deg -> 0x0000 (down) + * 90 deg -> 0x4000 (left) + * 180 deg -> 0x8000 (up) + * 270 deg -> 0xC000 (right) */ struct ff_effect { __u16 type; -/* Following field denotes the unique id assigned to an effect. - * If user sets if to -1, a new effect is created, and its id is returned in the same field - * Else, the user sets it to the effect id it wants to update. - */ __s16 id; - - __u16 direction; /* Direction. 0 deg -> 0x0000 (down) - 90 deg -> 0x4000 (left) - 180 deg -> 0x8000 (up) - 270 deg -> 0xC000 (right) - */ - + __u16 direction; struct ff_trigger trigger; struct ff_replay replay; -- cgit v1.2.3-70-g09d2 From ee4799997950e81437ef9055a4b104099e3272c4 Mon Sep 17 00:00:00 2001 From: Rick Koch Date: Sat, 5 Aug 2006 00:32:18 -0400 Subject: Input: add driver for Penmount serial touchscreens Signed-off-by: Rick Koch Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 12 +++ drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/penmount.c | 185 +++++++++++++++++++++++++++++++++++ include/linux/serio.h | 1 + 4 files changed, 199 insertions(+) create mode 100644 drivers/input/touchscreen/penmount.c (limited to 'include') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index b1b14f8d4dd..fa038126d50 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -108,4 +108,16 @@ config TOUCHSCREEN_HP600 To compile this driver as a module, choose M here: the module will be called hp680_ts_input. +config TOUCHSCREEN_PENMOUNT + tristate "Penmount serial touchscreen" + select SERIO + help + Say Y here if you have a Penmount serial touchscreen connected to + your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called penmount. + endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 5e5557c4312..72e7be8097a 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -12,3 +12,4 @@ obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o +obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c new file mode 100644 index 00000000000..f7370109d43 --- /dev/null +++ b/drivers/input/touchscreen/penmount.c @@ -0,0 +1,185 @@ +/* + * Penmount serial touchscreen driver + * + * Copyright (c) 2006 Rick Koch + * + * Based on ELO driver (drivers/input/touchscreen/elo.c) + * Copyright (c) 2004 Vojtech Pavlik + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_DESC "Penmount serial touchscreen driver" + +MODULE_AUTHOR("Rick Koch "); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +/* + * Definitions & global arrays. + */ + +#define PM_MAX_LENGTH 5 + +/* + * Per-touchscreen data. + */ + +struct pm { + struct input_dev *dev; + struct serio *serio; + int idx; + unsigned char data[PM_MAX_LENGTH]; + char phys[32]; +}; + +static irqreturn_t pm_interrupt(struct serio *serio, + unsigned char data, unsigned int flags, struct pt_regs *regs) +{ + struct pm *pm = serio_get_drvdata(serio); + struct input_dev *dev = pm->dev; + + pm->data[pm->idx] = data; + + if (pm->data[0] & 0x80) { + if (PM_MAX_LENGTH == ++pm->idx) { + input_regs(dev, regs); + input_report_abs(dev, ABS_X, pm->data[2] * 128 + pm->data[1]); + input_report_abs(dev, ABS_Y, pm->data[4] * 128 + pm->data[3]); + input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40)); + input_sync(dev); + pm->idx = 0; + } + } + + return IRQ_HANDLED; +} + +/* + * pm_disconnect() is the opposite of pm_connect() + */ + +static void pm_disconnect(struct serio *serio) +{ + struct pm *pm = serio_get_drvdata(serio); + + input_get_device(pm->dev); + input_unregister_device(pm->dev); + serio_close(serio); + serio_set_drvdata(serio, NULL); + input_put_device(pm->dev); + kfree(pm); +} + +/* + * pm_connect() is the routine that is called when someone adds a + * new serio device that supports Gunze protocol and registers it as + * an input device. + */ + +static int pm_connect(struct serio *serio, struct serio_driver *drv) +{ + struct pm *pm; + struct input_dev *input_dev; + int err; + + pm = kzalloc(sizeof(struct pm), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!pm || !input_dev) { + err = -ENOMEM; + goto fail1; + } + + pm->serio = serio; + pm->dev = input_dev; + snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys); + + input_dev->private = pm; + input_dev->name = "Penmount Serial TouchScreen"; + input_dev->phys = pm->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_PENMOUNT; + input_dev->id.product = 0; + input_dev->id.version = 0x0100; + input_dev->cdev.dev = &serio->dev; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_set_abs_params(pm->dev, ABS_X, 0, 0x3ff, 0, 0); + input_set_abs_params(pm->dev, ABS_Y, 0, 0x3ff, 0, 0); + + serio_set_drvdata(serio, pm); + + err = serio_open(serio, drv); + if (err) + goto fail2; + + err = input_register_device(pm->dev); + if (err) + goto fail3; + + return 0; + + fail3: serio_close(serio); + fail2: serio_set_drvdata(serio, NULL); + fail1: input_free_device(input_dev); + kfree(pm); + return err; +} + +/* + * The serio driver structure. + */ + +static struct serio_device_id pm_serio_ids[] = { + { + .type = SERIO_RS232, + .proto = SERIO_PENMOUNT, + .id = SERIO_ANY, + .extra = SERIO_ANY, + }, + { 0 } +}; + +MODULE_DEVICE_TABLE(serio, pm_serio_ids); + +static struct serio_driver pm_drv = { + .driver = { + .name = "penmountlpc", + }, + .description = DRIVER_DESC, + .id_table = pm_serio_ids, + .interrupt = pm_interrupt, + .connect = pm_connect, + .disconnect = pm_disconnect, +}; + +/* + * The functions for inserting/removing us as a module. + */ + +static int __init pm_init(void) +{ + serio_register_driver(&pm_drv); + return 0; +} + +static void __exit pm_exit(void) +{ + serio_unregister_driver(&pm_drv); +} + +module_init(pm_init); +module_exit(pm_exit); diff --git a/include/linux/serio.h b/include/linux/serio.h index 6348e833089..ad546a0205c 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -217,5 +217,6 @@ static inline void serio_unpin_driver(struct serio *serio) #define SERIO_LKKBD 0x28 #define SERIO_ELO 0x29 #define SERIO_MICROTOUCH 0x30 +#define SERIO_PENMOUNT 0x31 #endif -- cgit v1.2.3-70-g09d2 From 4003dff41e65ad338a60dde90019bffcb5531fb6 Mon Sep 17 00:00:00 2001 From: Rick Koch Date: Sat, 5 Aug 2006 00:32:24 -0400 Subject: Input: add driver for Touchright serial touchscreens Signed-off-by: Rick Koch Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 12 ++ drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/touchright.c | 196 +++++++++++++++++++++++++++++++++ include/linux/serio.h | 1 + 4 files changed, 210 insertions(+) create mode 100644 drivers/input/touchscreen/touchright.c (limited to 'include') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index fa038126d50..216db122937 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -120,4 +120,16 @@ config TOUCHSCREEN_PENMOUNT To compile this driver as a module, choose M here: the module will be called penmount. +config TOUCHSCREEN_TOUCHRIGHT + tristate "Touchright serial touchscreen" + select SERIO + help + Say Y here if you have a Touchright serial touchscreen connected to + your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called touchright. + endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 72e7be8097a..deda25e3680 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o +obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o diff --git a/drivers/input/touchscreen/touchright.c b/drivers/input/touchscreen/touchright.c new file mode 100644 index 00000000000..1c89fa53865 --- /dev/null +++ b/drivers/input/touchscreen/touchright.c @@ -0,0 +1,196 @@ +/* + * Touchright serial touchscreen driver + * + * Copyright (c) 2006 Rick Koch + * + * Based on MicroTouch driver (drivers/input/touchscreen/mtouch.c) + * Copyright (c) 2004 Vojtech Pavlik + * and Dan Streetman + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_DESC "Touchright serial touchscreen driver" + +MODULE_AUTHOR("Rick Koch "); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +/* + * Definitions & global arrays. + */ + +#define TR_FORMAT_TOUCH_BIT 0x01 +#define TR_FORMAT_STATUS_BYTE 0x40 +#define TR_FORMAT_STATUS_MASK ~TR_FORMAT_TOUCH_BIT + +#define TR_LENGTH 5 + +#define TR_MIN_XC 0 +#define TR_MAX_XC 0x1ff +#define TR_MIN_YC 0 +#define TR_MAX_YC 0x1ff + +/* + * Per-touchscreen data. + */ + +struct tr { + struct input_dev *dev; + struct serio *serio; + int idx; + unsigned char data[TR_LENGTH]; + char phys[32]; +}; + +static irqreturn_t tr_interrupt(struct serio *serio, + unsigned char data, unsigned int flags, struct pt_regs *regs) +{ + struct tr *tr = serio_get_drvdata(serio); + struct input_dev *dev = tr->dev; + + tr->data[tr->idx] = data; + + if ((tr->data[0] & TR_FORMAT_STATUS_MASK) == TR_FORMAT_STATUS_BYTE) { + if (++tr->idx == TR_LENGTH) { + input_regs(dev, regs); + input_report_abs(dev, ABS_X, + (tr->data[1] << 5) | (tr->data[2] >> 1)); + input_report_abs(dev, ABS_Y, + (tr->data[3] << 5) | (tr->data[4] >> 1)); + input_report_key(dev, BTN_TOUCH, + tr->data[0] & TR_FORMAT_TOUCH_BIT); + input_sync(dev); + tr->idx = 0; + } + } + + return IRQ_HANDLED; +} + +/* + * tr_disconnect() is the opposite of tr_connect() + */ + +static void tr_disconnect(struct serio *serio) +{ + struct tr *tr = serio_get_drvdata(serio); + + input_get_device(tr->dev); + input_unregister_device(tr->dev); + serio_close(serio); + serio_set_drvdata(serio, NULL); + input_put_device(tr->dev); + kfree(tr); +} + +/* + * tr_connect() is the routine that is called when someone adds a + * new serio device that supports the Touchright protocol and registers it as + * an input device. + */ + +static int tr_connect(struct serio *serio, struct serio_driver *drv) +{ + struct tr *tr; + struct input_dev *input_dev; + int err; + + tr = kzalloc(sizeof(struct tr), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!tr || !input_dev) { + err = -ENOMEM; + goto fail1; + } + + tr->serio = serio; + tr->dev = input_dev; + snprintf(tr->phys, sizeof(tr->phys), "%s/input0", serio->phys); + + input_dev->private = tr; + input_dev->name = "Touchright Serial TouchScreen"; + input_dev->phys = tr->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_TOUCHRIGHT; + input_dev->id.product = 0; + input_dev->id.version = 0x0100; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_set_abs_params(tr->dev, ABS_X, TR_MIN_XC, TR_MAX_XC, 0, 0); + input_set_abs_params(tr->dev, ABS_Y, TR_MIN_YC, TR_MAX_YC, 0, 0); + + serio_set_drvdata(serio, tr); + + err = serio_open(serio, drv); + if (err) + goto fail2; + + err = input_register_device(tr->dev); + if (err) + goto fail3; + + return 0; + + fail3: serio_close(serio); + fail2: serio_set_drvdata(serio, NULL); + fail1: input_free_device(input_dev); + kfree(tr); + return err; +} + +/* + * The serio driver structure. + */ + +static struct serio_device_id tr_serio_ids[] = { + { + .type = SERIO_RS232, + .proto = SERIO_TOUCHRIGHT, + .id = SERIO_ANY, + .extra = SERIO_ANY, + }, + { 0 } +}; + +MODULE_DEVICE_TABLE(serio, tr_serio_ids); + +static struct serio_driver tr_drv = { + .driver = { + .name = "touchright", + }, + .description = DRIVER_DESC, + .id_table = tr_serio_ids, + .interrupt = tr_interrupt, + .connect = tr_connect, + .disconnect = tr_disconnect, +}; + +/* + * The functions for inserting/removing us as a module. + */ + +static int __init tr_init(void) +{ + serio_register_driver(&tr_drv); + return 0; +} + +static void __exit tr_exit(void) +{ + serio_unregister_driver(&tr_drv); +} + +module_init(tr_init); +module_exit(tr_exit); diff --git a/include/linux/serio.h b/include/linux/serio.h index ad546a0205c..15260641315 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -218,5 +218,6 @@ static inline void serio_unpin_driver(struct serio *serio) #define SERIO_ELO 0x29 #define SERIO_MICROTOUCH 0x30 #define SERIO_PENMOUNT 0x31 +#define SERIO_TOUCHRIGHT 0x32 #endif -- cgit v1.2.3-70-g09d2 From 11ea3173d5f2de71d037ef58ac43395795fed2bc Mon Sep 17 00:00:00 2001 From: Rick Koch Date: Sat, 5 Aug 2006 00:32:30 -0400 Subject: Input: add driver for Touchwin serial touchscreens Signed-off-by: Rick Koch Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 12 +++ drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/touchwin.c | 203 +++++++++++++++++++++++++++++++++++ include/linux/serio.h | 1 + 4 files changed, 217 insertions(+) create mode 100644 drivers/input/touchscreen/touchwin.c (limited to 'include') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 216db122937..9418bbe4707 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -132,4 +132,16 @@ config TOUCHSCREEN_TOUCHRIGHT To compile this driver as a module, choose M here: the module will be called touchright. +config TOUCHSCREEN_TOUCHWIN + tristate "Touchwin serial touchscreen" + select SERIO + help + Say Y here if you have a Touchwin serial touchscreen connected to + your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called touchwin. + endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index deda25e3680..1abb8f10d60 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -14,3 +14,4 @@ obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o +obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c new file mode 100644 index 00000000000..a7b4c755958 --- /dev/null +++ b/drivers/input/touchscreen/touchwin.c @@ -0,0 +1,203 @@ +/* + * Touchwindow serial touchscreen driver + * + * Copyright (c) 2006 Rick Koch + * + * Based on MicroTouch driver (drivers/input/touchscreen/mtouch.c) + * Copyright (c) 2004 Vojtech Pavlik + * and Dan Streetman + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +/* + * 2005/02/19 Rick Koch: + * The Touchwindow I used is made by Edmark Corp. and + * constantly outputs a stream of 0's unless it is touched. + * It then outputs 3 bytes: X, Y, and a copy of Y. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_DESC "Touchwindow serial touchscreen driver" + +MODULE_AUTHOR("Rick Koch "); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +/* + * Definitions & global arrays. + */ + +#define TW_LENGTH 3 + +#define TW_MIN_XC 0 +#define TW_MAX_XC 0xff +#define TW_MIN_YC 0 +#define TW_MAX_YC 0xff + +/* + * Per-touchscreen data. + */ + +struct tw { + struct input_dev *dev; + struct serio *serio; + int idx; + int touched; + unsigned char data[TW_LENGTH]; + char phys[32]; +}; + +static irqreturn_t tw_interrupt(struct serio *serio, + unsigned char data, unsigned int flags, struct pt_regs *regs) +{ + struct tw *tw = serio_get_drvdata(serio); + struct input_dev *dev = tw->dev; + + if (data) { /* touch */ + tw->touched = 1; + tw->data[tw->idx++] = data; + /* verify length and that the two Y's are the same */ + if (tw->idx == TW_LENGTH && tw->data[1] == tw->data[2]) { + input_regs(dev, regs); + input_report_abs(dev, ABS_X, tw->data[0]); + input_report_abs(dev, ABS_Y, tw->data[1]); + input_report_key(dev, BTN_TOUCH, 1); + input_sync(dev); + tw->idx = 0; + } + } else if (tw->touched) { /* untouch */ + input_report_key(dev, BTN_TOUCH, 0); + input_sync(dev); + tw->idx = 0; + tw->touched = 0; + } + + return IRQ_HANDLED; +} + +/* + * tw_disconnect() is the opposite of tw_connect() + */ + +static void tw_disconnect(struct serio *serio) +{ + struct tw *tw = serio_get_drvdata(serio); + + input_get_device(tw->dev); + input_unregister_device(tw->dev); + serio_close(serio); + serio_set_drvdata(serio, NULL); + input_put_device(tw->dev); + kfree(tw); +} + +/* + * tw_connect() is the routine that is called when someone adds a + * new serio device that supports the Touchwin protocol and registers it as + * an input device. + */ + +static int tw_connect(struct serio *serio, struct serio_driver *drv) +{ + struct tw *tw; + struct input_dev *input_dev; + int err; + + tw = kzalloc(sizeof(struct tw), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!tw || !input_dev) { + err = -ENOMEM; + goto fail1; + } + + tw->serio = serio; + tw->dev = input_dev; + snprintf(tw->phys, sizeof(tw->phys), "%s/input0", serio->phys); + + input_dev->private = tw; + input_dev->name = "Touchwindow Serial TouchScreen"; + input_dev->phys = tw->phys; + input_dev->id.bustype = BUS_RS232; + input_dev->id.vendor = SERIO_TOUCHWIN; + input_dev->id.product = 0; + input_dev->id.version = 0x0100; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_set_abs_params(tw->dev, ABS_X, TW_MIN_XC, TW_MAX_XC, 0, 0); + input_set_abs_params(tw->dev, ABS_Y, TW_MIN_YC, TW_MAX_YC, 0, 0); + + serio_set_drvdata(serio, tw); + + err = serio_open(serio, drv); + if (err) + goto fail2; + + err = input_register_device(tw->dev); + if (err) + goto fail3; + + return 0; + + fail3: serio_close(serio); + fail2: serio_set_drvdata(serio, NULL); + fail1: input_free_device(input_dev); + kfree(tw); + return err; +} + +/* + * The serio driver structure. + */ + +static struct serio_device_id tw_serio_ids[] = { + { + .type = SERIO_RS232, + .proto = SERIO_TOUCHWIN, + .id = SERIO_ANY, + .extra = SERIO_ANY, + }, + { 0 } +}; + +MODULE_DEVICE_TABLE(serio, tw_serio_ids); + +static struct serio_driver tw_drv = { + .driver = { + .name = "touchwin", + }, + .description = DRIVER_DESC, + .id_table = tw_serio_ids, + .interrupt = tw_interrupt, + .connect = tw_connect, + .disconnect = tw_disconnect, +}; + +/* + * The functions for inserting/removing us as a module. + */ + +static int __init tw_init(void) +{ + serio_register_driver(&tw_drv); + return 0; +} + +static void __exit tw_exit(void) +{ + serio_unregister_driver(&tw_drv); +} + +module_init(tw_init); +module_exit(tw_exit); diff --git a/include/linux/serio.h b/include/linux/serio.h index 15260641315..c9069310b6a 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -219,5 +219,6 @@ static inline void serio_unpin_driver(struct serio *serio) #define SERIO_MICROTOUCH 0x30 #define SERIO_PENMOUNT 0x31 #define SERIO_TOUCHRIGHT 0x32 +#define SERIO_TOUCHWIN 0x33 #endif -- cgit v1.2.3-70-g09d2 From 9807879bfdc0c2b5106b4b378f5475c6a333d853 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 14 Sep 2006 01:31:27 -0400 Subject: Input: atkbd - support Microsoft Natural Elite Pro keyboards Microsoft Natural Elite Pro keyboard produces unisual response to the GET ID command - single byte 0xaa (normally keyboards produce 2-byte response). Fail GET ID command so atkbd gets a change to do alternate probe. Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/atkbd.c | 4 +--- drivers/input/serio/libps2.c | 18 ++++++++++++++++-- include/linux/libps2.h | 1 + 3 files changed, 18 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index ce1f10e8984..9874072cf9d 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -635,9 +635,7 @@ static int atkbd_probe(struct atkbd *atkbd) return 0; } - if (param[0] != 0xab && param[0] != 0xac && /* Regular and NCD Sun keyboards */ - param[0] != 0x2b && param[0] != 0x5d && /* Trust keyboard, raw and translated */ - param[0] != 0x60 && param[0] != 0x47) /* NMB SGI keyboard, raw and translated */ + if (!ps2_is_keyboard_id(param[0])) return -1; atkbd->id = (param[0] << 8) | param[1]; diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index ed202f2f251..e0a2297a9d2 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -35,6 +35,7 @@ EXPORT_SYMBOL(ps2_schedule_command); EXPORT_SYMBOL(ps2_handle_ack); EXPORT_SYMBOL(ps2_handle_response); EXPORT_SYMBOL(ps2_cmd_aborted); +EXPORT_SYMBOL(ps2_is_keyboard_id); /* Work structure to schedule execution of a command */ struct ps2work { @@ -102,9 +103,9 @@ void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout) * known keyboard IDs. */ -static inline int ps2_is_keyboard_id(char id_byte) +int ps2_is_keyboard_id(char id_byte) { - static char keyboard_ids[] = { + const static char keyboard_ids[] = { 0xab, /* Regular keyboards */ 0xac, /* NCD Sun keyboard */ 0x2b, /* Trust keyboard, translated */ @@ -138,6 +139,19 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout) break; case PS2_CMD_GETID: + /* + * Microsoft Natural Elite keyboard responds to + * the GET ID command as it were a mouse, with + * a single byte. Fail the command so atkbd will + * use alternative probe to detect it. + */ + if (ps2dev->cmdbuf[1] == 0xaa) { + serio_pause_rx(ps2dev->serio); + ps2dev->flags = 0; + serio_continue_rx(ps2dev->serio); + timeout = 0; + } + /* * If device behind the port is not a keyboard there * won't be 2nd byte of ID response. diff --git a/include/linux/libps2.h b/include/linux/libps2.h index 08a450a9dbf..f6f301e2b0f 100644 --- a/include/linux/libps2.h +++ b/include/linux/libps2.h @@ -47,5 +47,6 @@ int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int comman int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data); int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data); void ps2_cmd_aborted(struct ps2dev *ps2dev); +int ps2_is_keyboard_id(char id); #endif /* _LIBPS2_H */ -- cgit v1.2.3-70-g09d2 From 66e66118837ed95a299328437c2d9fb4b5137352 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 14 Sep 2006 01:31:59 -0400 Subject: Input: constify input core Signed-off-by: Dmitry Torokhov --- drivers/char/keyboard.c | 4 ++-- drivers/input/evbug.c | 8 +++++--- drivers/input/evdev.c | 7 ++++--- drivers/input/input.c | 7 ++++--- drivers/input/joydev.c | 9 +++++---- drivers/input/mousedev.c | 7 ++++--- drivers/input/power.c | 4 ++-- drivers/input/tsdev.c | 8 +++----- include/linux/input.h | 10 +++++----- 9 files changed, 34 insertions(+), 30 deletions(-) (limited to 'include') diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 30a745428a0..797480768b4 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -1285,7 +1285,7 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type, */ static struct input_handle *kbd_connect(struct input_handler *handler, struct input_dev *dev, - struct input_device_id *id) + const struct input_device_id *id) { struct input_handle *handle; int i; @@ -1334,7 +1334,7 @@ static void kbd_start(struct input_handle *handle) tasklet_enable(&keyboard_tasklet); } -static struct input_device_id kbd_ids[] = { +static const struct input_device_id kbd_ids[] = { { .flags = INPUT_DEVICE_ID_MATCH_EVBIT, .evbit = { BIT(EV_KEY) }, diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c index 07358fb51b8..1d8ce7a1ec3 100644 --- a/drivers/input/evbug.c +++ b/drivers/input/evbug.c @@ -42,10 +42,12 @@ static char evbug_name[] = "evbug"; static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { - printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", handle->dev->phys, type, code, value); + printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", + handle->dev->phys, type, code, value); } -static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) +static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) { struct input_handle *handle; @@ -72,7 +74,7 @@ static void evbug_disconnect(struct input_handle *handle) kfree(handle); } -static struct input_device_id evbug_ids[] = { +static const struct input_device_id evbug_ids[] = { { .driver_info = 1 }, /* Matches all devices */ { }, /* Terminating zero entry */ }; diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 12c7ab876c3..154e423167b 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -601,7 +601,7 @@ static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned lon } #endif -static struct file_operations evdev_fops = { +static const struct file_operations evdev_fops = { .owner = THIS_MODULE, .read = evdev_read, .write = evdev_write, @@ -616,7 +616,8 @@ static struct file_operations evdev_fops = { .flush = evdev_flush }; -static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) +static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) { struct evdev *evdev; struct class_device *cdev; @@ -675,7 +676,7 @@ static void evdev_disconnect(struct input_handle *handle) evdev_free(evdev); } -static struct input_device_id evdev_ids[] = { +static const struct input_device_id evdev_ids[] = { { .driver_info = 1 }, /* Matches all devices */ { }, /* Terminating zero entry */ }; diff --git a/drivers/input/input.c b/drivers/input/input.c index 1c71dd6fe5c..4954c790ccb 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -313,7 +313,8 @@ static void input_link_handle(struct input_handle *handle) if (i != NBITS(max)) \ continue; -static struct input_device_id *input_match_device(struct input_device_id *id, struct input_dev *dev) +static const struct input_device_id *input_match_device(const struct input_device_id *id, + struct input_dev *dev) { int i; @@ -935,7 +936,7 @@ int input_register_device(struct input_dev *dev) static atomic_t input_no = ATOMIC_INIT(0); struct input_handle *handle; struct input_handler *handler; - struct input_device_id *id; + const struct input_device_id *id; const char *path; int error; @@ -1050,7 +1051,7 @@ void input_register_handler(struct input_handler *handler) { struct input_dev *dev; struct input_handle *handle; - struct input_device_id *id; + const struct input_device_id *id; if (!handler) return; diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index d67157513bf..033e3aac92a 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -451,7 +451,7 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd } } -static struct file_operations joydev_fops = { +static const struct file_operations joydev_fops = { .owner = THIS_MODULE, .read = joydev_read, .write = joydev_write, @@ -465,7 +465,8 @@ static struct file_operations joydev_fops = { .fasync = joydev_fasync, }; -static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) +static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) { struct joydev *joydev; struct class_device *cdev; @@ -562,7 +563,7 @@ static void joydev_disconnect(struct input_handle *handle) joydev_free(joydev); } -static struct input_device_id joydev_blacklist[] = { +static const struct input_device_id joydev_blacklist[] = { { .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, .evbit = { BIT(EV_KEY) }, @@ -571,7 +572,7 @@ static struct input_device_id joydev_blacklist[] = { { } /* Terminating entry */ }; -static struct input_device_id joydev_ids[] = { +static const struct input_device_id joydev_ids[] = { { .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, .evbit = { BIT(EV_ABS) }, diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 1f851acab30..cd02f1b62b6 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -614,7 +614,7 @@ static unsigned int mousedev_poll(struct file *file, poll_table *wait) (list->mousedev->exist ? 0 : (POLLHUP | POLLERR)); } -static struct file_operations mousedev_fops = { +static const struct file_operations mousedev_fops = { .owner = THIS_MODULE, .read = mousedev_read, .write = mousedev_write, @@ -624,7 +624,8 @@ static struct file_operations mousedev_fops = { .fasync = mousedev_fasync, }; -static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) +static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) { struct mousedev *mousedev; struct class_device *cdev; @@ -688,7 +689,7 @@ static void mousedev_disconnect(struct input_handle *handle) } } -static struct input_device_id mousedev_ids[] = { +static const struct input_device_id mousedev_ids[] = { { .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, diff --git a/drivers/input/power.c b/drivers/input/power.c index 51a519e24b6..75d018759cd 100644 --- a/drivers/input/power.c +++ b/drivers/input/power.c @@ -98,7 +98,7 @@ static void power_event(struct input_handle *handle, unsigned int type, static struct input_handle *power_connect(struct input_handler *handler, struct input_dev *dev, - struct input_device_id *id) + const struct input_device_id *id) { struct input_handle *handle; @@ -120,7 +120,7 @@ static void power_disconnect(struct input_handle *handle) kfree(handle); } -static struct input_device_id power_ids[] = { +static const struct input_device_id power_ids[] = { { .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, .evbit = { BIT(EV_KEY) }, diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c index 00e3929c628..162ee08223a 100644 --- a/drivers/input/tsdev.c +++ b/drivers/input/tsdev.c @@ -135,8 +135,6 @@ struct tsdev_list { #define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration) #define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration) -static struct input_handler tsdev_handler; - static struct tsdev *tsdev_table[TSDEV_MINORS/2]; static int tsdev_fasync(int fd, struct file *file, int on) @@ -263,7 +261,7 @@ static int tsdev_ioctl(struct inode *inode, struct file *file, return retval; } -static struct file_operations tsdev_fops = { +static const struct file_operations tsdev_fops = { .owner = THIS_MODULE, .open = tsdev_open, .release = tsdev_release, @@ -370,7 +368,7 @@ static void tsdev_event(struct input_handle *handle, unsigned int type, static struct input_handle *tsdev_connect(struct input_handler *handler, struct input_dev *dev, - struct input_device_id *id) + const struct input_device_id *id) { struct tsdev *tsdev; struct class_device *cdev; @@ -443,7 +441,7 @@ static void tsdev_disconnect(struct input_handle *handle) tsdev_free(tsdev); } -static struct input_device_id tsdev_ids[] = { +static const struct input_device_id tsdev_ids[] = { { .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, diff --git a/include/linux/input.h b/include/linux/input.h index a7a1f55a5ee..300036b7755 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1059,16 +1059,16 @@ struct input_handler { void *private; void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); - struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id); + struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id); void (*disconnect)(struct input_handle *handle); void (*start)(struct input_handle *handle); const struct file_operations *fops; int minor; - char *name; + const char *name; - struct input_device_id *id_table; - struct input_device_id *blacklist; + const struct input_device_id *id_table; + const struct input_device_id *blacklist; struct list_head h_list; struct list_head node; @@ -1079,7 +1079,7 @@ struct input_handle { void *private; int open; - char *name; + const char *name; struct input_dev *dev; struct input_handler *handler; -- cgit v1.2.3-70-g09d2 From 68c2a1607cd6dd12427c9566b39756e92708713c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 14 Sep 2006 01:32:28 -0400 Subject: Input: remove cruft that was needed for transition to sysfs Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 10 ---------- include/linux/input.h | 9 --------- 2 files changed, 19 deletions(-) (limited to 'include') diff --git a/drivers/input/input.c b/drivers/input/input.c index f2c85a60a0d..c3448364cc7 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -906,7 +906,6 @@ struct input_dev *input_allocate_device(void) dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL); if (dev) { - dev->dynalloc = 1; dev->cdev.class = &input_class; class_device_initialize(&dev->cdev); mutex_init(&dev->mutex); @@ -942,13 +941,6 @@ int input_register_device(struct input_dev *dev) const char *path; int error; - if (!dev->dynalloc) { - printk(KERN_WARNING "input: device %s is statically allocated, will not register\n" - "Please convert to input_allocate_device() or contact dtor_core@ameritech.net\n", - dev->name ? dev->name : ""); - return -EINVAL; - } - set_bit(EV_SYN, dev->evbit); /* @@ -964,10 +956,8 @@ int input_register_device(struct input_dev *dev) dev->rep[REP_PERIOD] = 33; } - INIT_LIST_HEAD(&dev->h_list); list_add_tail(&dev->node, &input_dev_list); - dev->cdev.class = &input_class; snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id), "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); diff --git a/include/linux/input.h b/include/linux/input.h index 300036b7755..155b2bc9684 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -978,9 +978,6 @@ struct input_dev { unsigned int users; struct class_device cdev; - struct device *dev; /* will be removed soon */ - - int dynalloc; /* temporarily */ struct list_head h_list; struct list_head node; @@ -1093,12 +1090,6 @@ struct input_handle { #define to_handle(n) container_of(n,struct input_handle,d_node) #define to_handle_h(n) container_of(n,struct input_handle,h_node) -static inline void init_input_dev(struct input_dev *dev) -{ - INIT_LIST_HEAD(&dev->h_list); - INIT_LIST_HEAD(&dev->node); -} - struct input_dev *input_allocate_device(void); void input_free_device(struct input_dev *dev); -- cgit v1.2.3-70-g09d2 From 4263cf0fac28122c8381b6f4f9441a43cd93c81f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 14 Sep 2006 01:32:39 -0400 Subject: Input: make input_register_handler() return error codes Signed-off-by: Dmitry Torokhov --- drivers/char/keyboard.c | 5 ++++- drivers/input/evbug.c | 3 +-- drivers/input/evdev.c | 3 +-- drivers/input/input.c | 12 +++++++----- drivers/input/joydev.c | 3 +-- drivers/input/mousedev.c | 21 +++++++++++++++++---- drivers/input/power.c | 3 +-- drivers/input/tsdev.c | 4 +--- include/linux/input.h | 2 +- 9 files changed, 34 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 797480768b4..bf2339c869e 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -1362,6 +1362,7 @@ static struct input_handler kbd_handler = { int __init kbd_init(void) { int i; + int error; for (i = 0; i < MAX_NR_CONSOLES; i++) { kbd_table[i].ledflagstate = KBD_DEFLEDS; @@ -1373,7 +1374,9 @@ int __init kbd_init(void) kbd_table[i].kbdmode = VC_XLATE; } - input_register_handler(&kbd_handler); + error = input_register_handler(&kbd_handler); + if (error) + return error; tasklet_enable(&keyboard_tasklet); tasklet_schedule(&keyboard_tasklet); diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c index 1d8ce7a1ec3..5a9653c3128 100644 --- a/drivers/input/evbug.c +++ b/drivers/input/evbug.c @@ -91,8 +91,7 @@ static struct input_handler evbug_handler = { static int __init evbug_init(void) { - input_register_handler(&evbug_handler); - return 0; + return input_register_handler(&evbug_handler); } static void __exit evbug_exit(void) diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 154e423167b..6439f378f6c 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -695,8 +695,7 @@ static struct input_handler evdev_handler = { static int __init evdev_init(void) { - input_register_handler(&evdev_handler); - return 0; + return input_register_handler(&evdev_handler); } static void __exit evdev_exit(void) diff --git a/drivers/input/input.c b/drivers/input/input.c index c3448364cc7..1c8c8a5bc4a 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1037,19 +1037,20 @@ void input_unregister_device(struct input_dev *dev) } EXPORT_SYMBOL(input_unregister_device); -void input_register_handler(struct input_handler *handler) +int input_register_handler(struct input_handler *handler) { struct input_dev *dev; struct input_handle *handle; const struct input_device_id *id; - if (!handler) - return; - INIT_LIST_HEAD(&handler->h_list); - if (handler->fops != NULL) + if (handler->fops != NULL) { + if (input_table[handler->minor >> 5]) + return -EBUSY; + input_table[handler->minor >> 5] = handler; + } list_add_tail(&handler->node, &input_handler_list); @@ -1063,6 +1064,7 @@ void input_register_handler(struct input_handler *handler) } input_wakeup_procfs_readers(); + return 0; } EXPORT_SYMBOL(input_register_handler); diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 033e3aac92a..9f3529ad3fd 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -606,8 +606,7 @@ static struct input_handler joydev_handler = { static int __init joydev_init(void) { - input_register_handler(&joydev_handler); - return 0; + return input_register_handler(&joydev_handler); } static void __exit joydev_exit(void) diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index cd02f1b62b6..a22a74a2a3d 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -738,7 +738,12 @@ static int psaux_registered; static int __init mousedev_init(void) { - input_register_handler(&mousedev_handler); + struct class_device *cdev; + int error; + + error = input_register_handler(&mousedev_handler); + if (error) + return error; memset(&mousedev_mix, 0, sizeof(struct mousedev)); INIT_LIST_HEAD(&mousedev_mix.list); @@ -747,12 +752,20 @@ static int __init mousedev_init(void) mousedev_mix.exist = 1; mousedev_mix.minor = MOUSEDEV_MIX; - class_device_create(&input_class, NULL, + cdev = class_device_create(&input_class, NULL, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), NULL, "mice"); + if (IS_ERR(cdev)) { + input_unregister_handler(&mousedev_handler); + return PTR_ERR(cdev); + } #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX - if (!(psaux_registered = !misc_register(&psaux_mouse))) - printk(KERN_WARNING "mice: could not misc_register the device\n"); + error = misc_register(&psaux_mouse); + if (error) + printk(KERN_WARNING "mice: could not register psaux device, " + "error: %d\n", error); + else + psaux_registered = 1; #endif printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n"); diff --git a/drivers/input/power.c b/drivers/input/power.c index 75d018759cd..ee82464a2fa 100644 --- a/drivers/input/power.c +++ b/drivers/input/power.c @@ -150,8 +150,7 @@ static struct input_handler power_handler = { static int __init power_init(void) { - input_register_handler(&power_handler); - return 0; + return input_register_handler(&power_handler); } static void __exit power_exit(void) diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c index 162ee08223a..a730c461227 100644 --- a/drivers/input/tsdev.c +++ b/drivers/input/tsdev.c @@ -479,9 +479,7 @@ static struct input_handler tsdev_handler = { static int __init tsdev_init(void) { - input_register_handler(&tsdev_handler); - printk(KERN_INFO "ts: Compaq touchscreen protocol output\n"); - return 0; + return input_register_handler(&tsdev_handler); } static void __exit tsdev_exit(void) diff --git a/include/linux/input.h b/include/linux/input.h index 155b2bc9684..7025432350f 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1106,7 +1106,7 @@ static inline void input_put_device(struct input_dev *dev) int input_register_device(struct input_dev *); void input_unregister_device(struct input_dev *); -void input_register_handler(struct input_handler *); +int input_register_handler(struct input_handler *); void input_unregister_handler(struct input_handler *); int input_grab_device(struct input_handle *); -- cgit v1.2.3-70-g09d2 From 9a87fdded5742a9d14780e5dfd9c940d7862e0ec Mon Sep 17 00:00:00 2001 From: Michael Hanselmann Date: Tue, 19 Sep 2006 01:59:49 -0400 Subject: Input: add new BUS_VIRTUAL bus type BUS_VIRTUAL can be used when creating virtual devices using uinput driver. Note that when uinput is used to drive a real piece of hardware "real" bus type (such as BUS_USB, BUS_BLUETOOTH) should be specified. Signed-off-by: Michael Hanselmann Signed-off-by: Dmitry Torokhov --- include/linux/input.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/linux/input.h b/include/linux/input.h index 7025432350f..22a36104054 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -645,6 +645,7 @@ struct input_absinfo { #define BUS_USB 0x03 #define BUS_HIL 0x04 #define BUS_BLUETOOTH 0x05 +#define BUS_VIRTUAL 0x06 #define BUS_ISA 0x10 #define BUS_I8042 0x11 -- cgit v1.2.3-70-g09d2 From 90da11514562020ea7d697982f912ac949adc317 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Sep 2006 01:59:55 -0400 Subject: Input: add KEY_BLUETOOTH and KEY_WLAN definitions Some laptops have separate "rfkill" buttons for disabling/enabling Bluetooth and WLAN. Signed-off-by: Lennart Poettering Signed-off-by: Dmitry Torokhov --- include/linux/input.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include') diff --git a/include/linux/input.h b/include/linux/input.h index 22a36104054..5770105471d 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -349,6 +349,9 @@ struct input_absinfo { #define KEY_BATTERY 236 +#define KEY_BLUETOOTH 237 +#define KEY_WLAN 238 + #define KEY_UNKNOWN 240 #define BTN_MISC 0x100 -- cgit v1.2.3-70-g09d2