Commit a12f66fc authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (35 commits)
  Input: wistron - add support for Acer TravelMate 2424NWXCi
  Input: wistron - fix setting up special buttons
  Input: add KEY_BLUETOOTH and KEY_WLAN definitions
  Input: add new BUS_VIRTUAL bus type
  Input: add driver for stowaway serial keyboards
  Input: make input_register_handler() return error codes
  Input: remove cruft that was needed for transition to sysfs
  Input: fix input module refcounting
  Input: constify input core
  Input: libps2 - rearrange exports
  Input: atkbd - support Microsoft Natural Elite Pro keyboards
  Input: i8042 - disable MUX mode on Toshiba Equium A110
  Input: i8042 - get rid of polling timer
  Input: send key up events at disconnect
  Input: constify psmouse driver
  Input: i8042 - add Amoi to the MUX blacklist
  Input: logips2pp - add sugnature 56 (Cordless MouseMan Wheel), cleanup
  Input: add driver for Touchwin serial touchscreens
  Input: add driver for Touchright serial touchscreens
  Input: add driver for Penmount serial touchscreens
  ...
parents 12dce626 bb088590
Force feedback for Linux. Force feedback for Linux.
By Johann Deneux <deneux@ifrance.com> on 2001/04/22. By Johann Deneux <deneux@ifrance.com> on 2001/04/22.
Updated by Anssi Hannula <anssi.hannula@gmail.com> on 2006/04/09.
You may redistribute this file. Please remember to include shape.fig and You may redistribute this file. Please remember to include shape.fig and
interactive.fig as well. interactive.fig as well.
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
0. Introduction 1. Introduction
~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~
This document describes how to use force feedback devices under Linux. The 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 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 (as it is already the case), but to really enable the rendering of force
effects. effects.
At the moment, only I-Force devices are supported, and not officially. That This document only describes the force feedback part of the Linux input
means I had to find out how the protocol works on my own. Of course, the interface. Please read joystick.txt and input.txt before reading further this
information I managed to grasp is far from being complete, and I can not document.
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.
2. Instructions to the user 2. Instructions to the user
~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
Here are instructions on how to compile and use the driver. In fact, this To enable force feedback, you have to:
driver is the normal iforce, input and evdev drivers written by Vojtech
Pavlik, plus additions to support force feedback. 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 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". 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 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. something goes wrong.
At the kernel's compilation: If you have a serial iforce device, you need to start inputattach. See
- Enable IForce/Serial joystick.txt for details.
- 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
2.1 Does it work ? 2.1 Does it work ?
~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~
...@@ -70,9 +40,9 @@ There is an utility called fftest that will allow you to test the driver. ...@@ -70,9 +40,9 @@ There is an utility called fftest that will allow you to test the driver.
3. Instructions to the developper 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. and write() on /dev/input/eventXX.
This information is subject to change. This information is subject to change.
3.1 Querying device capabilities 3.1 Querying device capabilities
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...@@ -86,18 +56,29 @@ int ioctl(int file_descriptor, int request, unsigned long *features); ...@@ -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 Returns the features supported by the device. features is a bitfield with the
following bits: 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_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_RAMP can render ramp effects
- FF_SPRING can simulate the presence of a spring - 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_DAMPER can simulate damper effects
- FF_RUMBLE rumble effects (normally the only effect supported by rumble - FF_RUMBLE rumble effects
pads)
- FF_INERTIA can simulate inertia - 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); int ioctl(int fd, EVIOCGEFFECTS, int *n);
...@@ -120,6 +101,9 @@ to the unique id assigned by the driver. This data is required for performing ...@@ -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). 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 This if field must be set to -1 by the user in order to tell the driver to
allocate a new effect. allocate a new effect.
Effects are file descriptor specific.
See <linux/input.h> for a description of the ff_effect struct. You should also See <linux/input.h> 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. find help in a few sketches, contained in files shape.fig and interactive.fig.
You need xfig to visualize these files. You need xfig to visualize these files.
...@@ -128,8 +112,8 @@ 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); int ioctl(int fd, EVIOCRMFF, effect.id);
This makes room for new effects in the device's memory. Please note this won't This makes room for new effects in the device's memory. Note that this also
stop the effect if it was playing. stops the effect if it was playing.
3.4 Controlling the playback of effects 3.4 Controlling the playback of effects
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...@@ -163,8 +147,7 @@ Control of playing is done with write(). Below is an example: ...@@ -163,8 +147,7 @@ Control of playing is done with write(). Below is an example:
~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~
Not all devices have the same strength. Therefore, users should set a 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 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 persistent across access to the driver.
you are writing games, as another utility probably already set this for you.
/* Set the gain of the device /* Set the gain of the device
int gain; /* between 0 and 100 */ int gain; /* between 0 and 100 */
...@@ -204,11 +187,14 @@ type of device, not all parameters can be dynamically updated. For example, ...@@ -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 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. 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 3.8 Information about the status of effects
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Every time the status of an effect is changed, an event is sent. The values 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: and meanings of the fields of the event are as follows:
struct input_event { struct input_event {
/* When the status of the effect changed */ /* When the status of the effect changed */
struct timeval time; struct timeval time;
...@@ -225,3 +211,9 @@ struct input_event { ...@@ -225,3 +211,9 @@ struct input_event {
FF_STATUS_STOPPED The effect stopped playing FF_STATUS_STOPPED The effect stopped playing
FF_STATUS_PLAYING The effect started to play 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.
...@@ -1293,7 +1293,7 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type, ...@@ -1293,7 +1293,7 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type,
*/ */
static struct input_handle *kbd_connect(struct input_handler *handler, static struct input_handle *kbd_connect(struct input_handler *handler,
struct input_dev *dev, struct input_dev *dev,
struct input_device_id *id) const struct input_device_id *id)
{ {
struct input_handle *handle; struct input_handle *handle;
int i; int i;
...@@ -1342,7 +1342,7 @@ static void kbd_start(struct input_handle *handle) ...@@ -1342,7 +1342,7 @@ static void kbd_start(struct input_handle *handle)
tasklet_enable(&keyboard_tasklet); 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, .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
.evbit = { BIT(EV_KEY) }, .evbit = { BIT(EV_KEY) },
...@@ -1370,6 +1370,7 @@ static struct input_handler kbd_handler = { ...@@ -1370,6 +1370,7 @@ static struct input_handler kbd_handler = {
int __init kbd_init(void) int __init kbd_init(void)
{ {
int i; int i;
int error;
for (i = 0; i < MAX_NR_CONSOLES; i++) { for (i = 0; i < MAX_NR_CONSOLES; i++) {
kbd_table[i].ledflagstate = KBD_DEFLEDS; kbd_table[i].ledflagstate = KBD_DEFLEDS;
...@@ -1381,7 +1382,9 @@ int __init kbd_init(void) ...@@ -1381,7 +1382,9 @@ int __init kbd_init(void)
kbd_table[i].kbdmode = VC_XLATE; 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_enable(&keyboard_tasklet);
tasklet_schedule(&keyboard_tasklet); tasklet_schedule(&keyboard_tasklet);
......
...@@ -24,6 +24,20 @@ config INPUT ...@@ -24,6 +24,20 @@ config INPUT
if 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" comment "Userland interfaces"
config INPUT_MOUSEDEV config INPUT_MOUSEDEV
......
...@@ -4,7 +4,11 @@ ...@@ -4,7 +4,11 @@
# Each configuration option enables a list of files. # Each configuration option enables a list of files.
obj-$(CONFIG_INPUT) += input.o 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_MOUSEDEV) += mousedev.o
obj-$(CONFIG_INPUT_JOYDEV) += joydev.o obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
obj-$(CONFIG_INPUT_EVDEV) += evdev.o obj-$(CONFIG_INPUT_EVDEV) += evdev.o
......
...@@ -42,10 +42,12 @@ static char evbug_name[] = "evbug"; ...@@ -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) 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; struct input_handle *handle;
...@@ -72,7 +74,7 @@ static void evbug_disconnect(struct input_handle *handle) ...@@ -72,7 +74,7 @@ static void evbug_disconnect(struct input_handle *handle)
kfree(handle); kfree(handle);
} }
static struct input_device_id evbug_ids[] = { static const struct input_device_id evbug_ids[] = {
{ .driver_info = 1 }, /* Matches all devices */ { .driver_info = 1 }, /* Matches all devices */
{ }, /* Terminating zero entry */ { }, /* Terminating zero entry */
}; };
...@@ -89,8 +91,7 @@ static struct input_handler evbug_handler = { ...@@ -89,8 +91,7 @@ static struct input_handler evbug_handler = {
static int __init evbug_init(void) static int __init evbug_init(void)
{ {
input_register_handler(&evbug_handler); return input_register_handler(&evbug_handler);
return 0;
} }
static void __exit evbug_exit(void) static void __exit evbug_exit(void)
......
...@@ -391,8 +391,10 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd, ...@@ -391,8 +391,10 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
struct evdev *evdev = list->evdev; struct evdev *evdev = list->evdev;
struct input_dev *dev = evdev->handle.dev; struct input_dev *dev = evdev->handle.dev;
struct input_absinfo abs; struct input_absinfo abs;
struct ff_effect effect;
int __user *ip = (int __user *)p; int __user *ip = (int __user *)p;
int i, t, u, v; int i, t, u, v;
int error;
if (!evdev->exist) if (!evdev->exist)
return -ENODEV; return -ENODEV;
...@@ -460,27 +462,22 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd, ...@@ -460,27 +462,22 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
return 0; return 0;
case EVIOCSFF: case EVIOCSFF:
if (dev->upload_effect) {
struct ff_effect effect;
int err;
if (copy_from_user(&effect, p, sizeof(effect))) if (copy_from_user(&effect, p, sizeof(effect)))
return -EFAULT; return -EFAULT;
err = dev->upload_effect(dev, &effect);
error = input_ff_upload(dev, &effect, file);
if (put_user(effect.id, &(((struct ff_effect __user *)p)->id))) if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
return -EFAULT; return -EFAULT;
return err;
} else
return -ENOSYS;
case EVIOCRMFF: return error;
if (!dev->erase_effect)
return -ENOSYS;
return dev->erase_effect(dev, (int)(unsigned long) p); case EVIOCRMFF:
return input_ff_erase(dev, (int)(unsigned long) p, file);
case EVIOCGEFFECTS: case EVIOCGEFFECTS:
if (put_user(dev->ff_effects_max, ip)) i = test_bit(EV_FF, dev->evbit) ? dev->ff->max_effects : 0;
if (put_user(i, ip))
return -EFAULT; return -EFAULT;
return 0; return 0;
...@@ -604,7 +601,7 @@ static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned lon ...@@ -604,7 +601,7 @@ static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned lon
} }
#endif #endif
static struct file_operations evdev_fops = { static const struct file_operations evdev_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.read = evdev_read, .read = evdev_read,
.write = evdev_write, .write = evdev_write,
...@@ -619,7 +616,8 @@ static struct file_operations evdev_fops = { ...@@ -619,7 +616,8 @@ static struct file_operations evdev_fops = {
.flush = evdev_flush .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 evdev *evdev;
struct class_device *cdev; struct class_device *cdev;
...@@ -669,6 +667,7 @@ static void evdev_disconnect(struct input_handle *handle) ...@@ -669,6 +667,7 @@ static void evdev_disconnect(struct input_handle *handle)
evdev->exist = 0; evdev->exist = 0;
if (evdev->open) { if (evdev->open) {
input_flush_device(handle, NULL);
input_close_device(handle); input_close_device(handle);
wake_up_interruptible(&evdev->wait); wake_up_interruptible(&evdev->wait);
list_for_each_entry(list, &evdev->list, node) list_for_each_entry(list, &evdev->list, node)
...@@ -677,7 +676,7 @@ static void evdev_disconnect(struct input_handle *handle) ...@@ -677,7 +676,7 @@ static void evdev_disconnect(struct input_handle *handle)
evdev_free(evdev); evdev_free(evdev);
} }
static struct input_device_id evdev_ids[] = { static const struct input_device_id evdev_ids[] = {
{ .driver_info = 1 }, /* Matches all devices */ { .driver_info = 1 }, /* Matches all devices */
{ }, /* Terminating zero entry */ { }, /* Terminating zero entry */
}; };
...@@ -696,8 +695,7 @@ static struct input_handler evdev_handler = { ...@@ -696,8 +695,7 @@ static struct input_handler evdev_handler = {
static int __init evdev_init(void) static int __init evdev_init(void)
{ {
input_register_handler(&evdev_handler); return input_register_handler(&evdev_handler);
return 0;
} }
static void __exit evdev_exit(void) static void __exit evdev_exit(void)
......
/*
* Force feedback support for Linux input subsystem
*
* Copyright (c) 2006 Anssi Hannula <anssi.hannula@gmail.com>
* Copyright (c) 2006 Dmitry Torokhov <dtor@mail.ru>
*/
/*
* 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-core: " format "\n", ## arg)
#include <linux/input.h>
#include <linux/module.h>
#include <linux/mutex.h>
/*
* Check that the effect_id is a valid effect and whether the user
* is the owner
*/
static int check_effect_access(struct ff_device *ff, int effect_id,
struct file *file)
{
if (effect_id < 0 || effect_id >= ff->max_effects ||
!ff->effect_owners[effect_id])
return -EINVAL;
if (file && ff->effect_owners[effect_id] != file)
return -EACCES;
return 0;
}
/*
* Checks whether 2 effects can be combined together
*/
static inline int check_effects_compatible(struct ff_effect *e1,
struct ff_effect *e2)
{
return e1->type == e2->type &&
(e1->type != FF_PERIODIC ||
e1->u.periodic.waveform == e2->u.periodic.waveform);
}
/*
* Convert an effect into compatible one
*/
static int compat_effect(struct ff_device *ff, struct ff_effect *effect)
{
int magnitude;
switch (effect->type) {
case FF_RUMBLE:
if (!test_bit(FF_PERIODIC, ff->ffbit))
return -EINVAL;
/*
* calculate manginude of sine wave as average of rumble's
* 2/3 of strong magnitude and 1/3 of weak magnitude
*/
magnitude = effect->u.rumble.strong_magnitude / 3 +
effect->u.rumble.weak_magnitude / 6;
effect->type = FF_PERIODIC;
effect->u.periodic.waveform = FF_SINE;
effect->u.periodic.period = 50;
effect->u.periodic.magnitude = max(magnitude, 0x7fff);
effect->u.periodic.offset = 0;
effect->u.periodic.phase = 0;
effect->u.periodic.envelope.attack_length = 0;
effect->u.periodic.envelope.attack_level = 0;
effect->u.periodic.envelope.fade_length = 0;
effect->u.periodic.envelope.fade_level = 0;
return 0;
default:
/* Let driver handle conversion */
return 0;
}
}
/**
* input_ff_upload() - upload effect into force-feedback device
* @dev: input device
* @effect: effect to be uploaded
* @file: owner of the effect
*/
int input_ff_upload(struct input_dev *dev, struct ff_effect *effect,
struct file *file)
{
struct ff_device *ff = dev->ff;
struct ff_effect *old;
int ret = 0;
int id;
if (!test_bit(EV_FF, dev->evbit))
return -ENOSYS;
if (effect->type < FF_EFFECT_MIN || effect->type > FF_EFFECT_MAX ||
!test_bit(effect->type, dev->ffbit)) {
debug("invalid or not supported effect type in upload");
return -EINVAL;
}
if (effect->type == FF_PERIODIC &&
(effect->u.periodic.waveform < FF_WAVEFORM_MIN ||
effect->u.periodic.waveform > FF_WAVEFORM_MAX ||
!test_bit(effect->u.periodic.waveform, dev->ffbit))) {
debug("invalid or not supported wave form in upload");
return -EINVAL;
}
if (!test_bit(effect->type, ff->ffbit)) {
ret = compat_effect(ff, effect);
if (ret)
return ret;
}
mutex_lock(&ff->mutex);
if (effect->id == -1) {
for (id = 0; id < ff->max_effects; id++)
if (!ff->effect_owners[id])
break;
if (id >= ff->max_effects) {
ret = -ENOSPC;
goto out;
}
effect->id = id;
old = NULL;
} else {
id = effect->id;
ret = check_effect_access(ff, id, file);
if (ret)
goto out;
old = &ff->effects[id];
if (!check_effects_compatible(effect, old)) {
ret = -EINVAL;
goto out;
}
}
ret = ff->upload(dev, effect, old);
if (ret)
goto out;
ff->effects[id] = *effect;
ff->effect_owners[id] = file;
out:
mutex_unlock(&ff->mutex);
return ret;
}
EXPORT_SYMBOL_GPL(input_ff_upload);
/*
* Erases the effect if the requester is also the effect owner. The mutex
* should already be locked before calling this function.
*/
static int erase_effect(struct input_dev *dev, int effect_id,
struct file *file)
{
struct ff_device *ff = dev->ff;
int error;
error = check_effect_access(ff, effect_id, file);
if (error)
return error;
ff->playback(dev, effect_id, 0);
if (ff->erase) {
error = ff->erase(dev, effect_id);
if (error)
return error;
}
ff->effect_owners[effect_id] = NULL;
return 0;
}
/**
* input_ff_erase - erase an effect from device
* @dev: input device to erase effect from
* @effect_id: id of the ffect to be erased
* @file: purported owner of the request
*
* This function erases a force-feedback effect from specified device.
* The effect will only be erased if it was uploaded through the same
* file handle that is requesting erase.
*/
int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file)
{
struct ff_device *ff = dev->ff;
int ret;
if (!test_bit(EV_FF, dev->evbit))
return -ENOSYS;
mutex_lock(&ff->mutex);
ret = erase_effect(dev, effect_id, file);
mutex_unlock(&ff->mutex);
return ret;
}
EXPORT_SYMBOL_GPL(input_ff_erase);
/*
* flush_effects - erase all effects owned by a file handle
*/
static int flush_effects(struct input_dev *dev, struct file *file)
{
struct ff_device *ff = dev->ff;
int i;
debug("flushing now");
mutex_lock(&ff->mutex);
for (i = 0; i < ff->max_effects; i++)
erase_effect(dev, i, file);
mutex_unlock(&ff->mutex);
return 0;
}
/**
* input_ff_event() - generic handler for force-feedback events
* @dev: input device to send the effect to
* @type: event type (anything but EV_FF is ignored)
* @code: event code
* @value: event value
*/
int input_ff_event(struct input_dev *dev, unsigned int type,
unsigned int code, int value)
{
struct ff_device *ff = dev->ff;
if (type != EV_FF)
return 0;
mutex_lock(&ff->mutex);
switch (code) {
case FF_GAIN:
if (!test_bit(FF_GAIN, dev->ffbit) || value > 0xffff)
break;
ff->set_gain(dev, value);
break;
case FF_AUTOCENTER:
if (!test_bit(FF_AUTOCENTER, dev->ffbit) || value > 0xffff)
break;
ff->set_autocenter(dev, value);
break;
default:
ff->playback(dev, code, value);
break;
}
mutex_unlock(&ff->mutex);
return 0;
}
EXPORT_SYMBOL_GPL(input_ff_event);
/**
* input_ff_create() - create force-feedback device
* @dev: input device supporting force-feedback
* @max_effects: maximum number of effects supported by the device
*
* This function allocates all necessary memory for a force feedback
* portion of an input device and installs all default handlers.
* @dev->ffbit should be already set up before calling this function.
* Once ff device is created you need to setup its upload, erase,
* playback and other handlers before registering input device
*/
int input_ff_create(struct input_dev *dev, int max_effects)
{
struct ff_device *ff;
int i;
if (!max_effects) {
printk(KERN_ERR
"ff-core: cannot allocate device without any effects\n");
return -EINVAL;
}
ff = kzalloc(sizeof(struct ff_device) +
max_effects * sizeof(struct file *), GFP_KERNEL);
if (!ff)
return -ENOMEM;
ff->effects = kcalloc(max_effects, sizeof(struct ff_effect),
GFP_KERNEL);
if (!ff->effects) {
kfree(ff);
return -ENOMEM;
}
ff->max_effects = max_effects;
mutex_init(&ff->mutex);
dev->ff = ff;
dev->flush = flush_effects;
dev->event = input_ff_event;
set_bit(EV_FF, dev->evbit);
/* Copy "true" bits into ff device bitmap */
for (i = 0; i <= FF_MAX; i++)
if (test_bit(i, dev->ffbit))
set_bit(i, ff->ffbit);
/* we can emulate RUMBLE with periodic effects */
if (test_bit(FF_PERIODIC, ff->ffbit))
set_bit(FF_RUMBLE, dev->ffbit);
return 0;
}
EXPORT_SYMBOL_GPL(input_ff_create);
/**
* input_ff_free() - frees force feedback portion of input device
* @dev: input device supporintg force feedback
*
* This function is only needed in error path as input core will
* automatically free force feedback structures when device is
* destroyed.
*/
void input_ff_destroy(struct input_dev *dev)
{
clear_bit(EV_FF, dev->evbit);
if (dev->ff) {
if (dev->ff->destroy)
dev->ff->destroy(dev->ff);
kfree(dev->ff->private);
kfree(dev->ff);
dev->ff = NULL;
}
}
EXPORT_SYMBOL_GPL(input_ff_destroy);
This diff is collapsed.
...@@ -176,6 +176,10 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in ...@@ -176,6 +176,10 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in
break; break;
case EV_FF: case EV_FF:
if (value < 0)
return;
if (dev->event) if (dev->event)
dev->event(dev, type, code, value); dev->event(dev, type, code, value);
break; break;
...@@ -309,7 +313,8 @@ static void input_link_handle(struct input_handle *handle) ...@@ -309,7 +313,8 @@ static void input_link_handle(struct input_handle *handle)
if (i != NBITS(max)) \ if (i != NBITS(max)) \
continue; 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; int i;
...@@ -762,7 +767,9 @@ static void input_dev_release(struct class_device *class_dev) ...@@ -762,7 +767,9 @@ static void input_dev_release(struct class_device *class_dev)
{ {
struct input_dev *dev = to_input_dev(class_dev); struct input_dev *dev = to_input_dev(class_dev);
input_ff_destroy(dev);
kfree(dev); kfree(dev);
module_put(THIS_MODULE); module_put(THIS_MODULE);
} }
...@@ -899,12 +906,13 @@ struct input_dev *input_allocate_device(void) ...@@ -899,12 +906,13 @@ struct input_dev *input_allocate_device(void)
dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL); dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);
if (dev) { if (dev) {
dev->dynalloc = 1;
dev->cdev.class = &input_class; dev->cdev.class = &input_class;
class_device_initialize(&dev->cdev); class_device_initialize(&dev->cdev);
mutex_init(&dev->mutex); mutex_init(&dev->mutex);
INIT_LIST_HEAD(&dev->h_list); INIT_LIST_HEAD(&dev->h_list);
INIT_LIST_HEAD(&dev->node); INIT_LIST_HEAD(&dev->node);
__module_get(THIS_MODULE);
} }
return dev; return dev;
...@@ -929,17 +937,10 @@ int input_register_device(struct input_dev *dev) ...@@ -929,17 +937,10 @@ int input_register_device(struct input_dev *dev)
static atomic_t input_no = ATOMIC_INIT(0); static atomic_t input_no = ATOMIC_INIT(0);
struct input_handle *handle; struct input_handle *handle;
struct input_handler *handler; struct input_handler *handler;
struct input_device_id *id; const struct input_device_id *id;
const char *path; const char *path;
int error; 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 : "<Unknown>");
return -EINVAL;
}
set_bit(EV_SYN, dev->evbit); set_bit(EV_SYN, dev->evbit);
/* /*
...@@ -955,10 +956,8 @@ int input_register_device(struct input_dev *dev) ...@@ -955,10 +956,8 @@ int input_register_device(struct input_dev *dev)
dev->rep[REP_PERIOD] = 33; dev->rep[REP_PERIOD] = 33;
} }
INIT_LIST_HEAD(&dev->h_list);
list_add_tail(&dev->node, &input_dev_list); list_add_tail(&dev->node, &input_dev_list);
dev->cdev.class = &input_class;
snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id), snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id),
"input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1);
...@@ -978,8 +977,6 @@ int input_register_device(struct input_dev *dev) ...@@ -978,8 +977,6 @@ int input_register_device(struct input_dev *dev)
if (error) if (error)
goto fail3; goto fail3;
__module_get(THIS_MODULE);
path = kobject_get_path(&dev->cdev.kobj, GFP_KERNEL); path = kobject_get_path(&dev->cdev.kobj, GFP_KERNEL);
printk(KERN_INFO "input: %s as %s\n", printk(KERN_INFO "input: %s as %s\n",
dev->name ? dev->name : "Unspecified device", path ? path : "N/A"); dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
...@@ -1008,9 +1005,12 @@ EXPORT_SYMBOL(input_register_device); ...@@ -1008,9 +1005,12 @@ EXPORT_SYMBOL(input_register_device);
void input_unregister_device(struct input_dev *dev) void input_unregister_device(struct input_dev *dev)
{ {
struct list_head *node, *next; struct list_head *node, *next;
int code;
if (!dev) for (code = 0; code <= KEY_MAX; code++)
return; if (test_bit(code, dev->key))
input_report_key(dev, code, 0);
input_sync(dev);
del_timer_sync(&dev->timer); del_timer_sync(&dev->timer);
...@@ -1037,19 +1037,20 @@ void input_unregister_device(struct input_dev *dev) ...@@ -1037,19 +1037,20 @@ void input_unregister_device(struct input_dev *dev)
} }
EXPORT_SYMBOL(input_unregister_device); 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_dev *dev;
struct input_handle *handle; struct input_handle *handle;
struct input_device_id *id; const struct input_device_id *id;
if (!handler)
return;
INIT_LIST_HEAD(&handler->h_list); 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; input_table[handler->minor >> 5] = handler;
}
list_add_tail(&handler->node, &input_handler_list); list_add_tail(&handler->node, &input_handler_list);
...@@ -1063,6 +1064,7 @@ void input_register_handler(struct input_handler *handler) ...@@ -1063,6 +1064,7 @@ void input_register_handler(struct input_handler *handler)
} }
input_wakeup_procfs_readers(); input_wakeup_procfs_readers();
return 0;
} }
EXPORT_SYMBOL(input_register_handler); EXPORT_SYMBOL(input_register_handler);
......
...@@ -451,7 +451,7 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd ...@@ -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, .owner = THIS_MODULE,
.read = joydev_read, .read = joydev_read,
.write = joydev_write, .write = joydev_write,
...@@ -465,7 +465,8 @@ static struct file_operations joydev_fops = { ...@@ -465,7 +465,8 @@ static struct file_operations joydev_fops = {
.fasync = joydev_fasync, .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 joydev *joydev;
struct class_device *cdev; struct class_device *cdev;
...@@ -562,7 +563,7 @@ static void joydev_disconnect(struct input_handle *handle) ...@@ -562,7 +563,7 @@ static void joydev_disconnect(struct input_handle *handle)
joydev_free(joydev); 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, .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
.evbit = { BIT(EV_KEY) }, .evbit = { BIT(EV_KEY) },
...@@ -571,7 +572,7 @@ static struct input_device_id joydev_blacklist[] = { ...@@ -571,7 +572,7 @@ static struct input_device_id joydev_blacklist[] = {
{ } /* Terminating entry */ { } /* 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, .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
.evbit = { BIT(EV_ABS) }, .evbit = { BIT(EV_ABS) },
...@@ -605,8 +606,7 @@ static struct input_handler joydev_handler = { ...@@ -605,8 +606,7 @@ static struct input_handler joydev_handler = {
static int __init joydev_init(void) static int __init joydev_init(void)
{ {
input_register_handler(&joydev_handler); return input_register_handler(&joydev_handler);
return 0;
} }
static void __exit joydev_exit(void) static void __exit joydev_exit(void)
......
This diff is collapsed.
...@@ -83,103 +83,57 @@ static struct iforce_device iforce_device[] = { ...@@ -83,103 +83,57 @@ static struct iforce_device iforce_device[] = {
{ 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce } { 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce }
}; };
static int iforce_playback(struct input_dev *dev, int effect_id, int value)
static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{ {
struct iforce* iforce = dev->private; struct iforce* iforce = dev->private;
unsigned char data[3]; struct iforce_core_effect *core_effect = &iforce->core_effects[effect_id];
if (type != EV_FF) if (value > 0)
return -1; set_bit(FF_CORE_SHOULD_PLAY, core_effect->flags);
else
clear_bit(FF_CORE_SHOULD_PLAY, core_effect->flags);
switch (code) { iforce_control_playback(iforce, effect_id, value);
return 0;
}
case FF_GAIN: static void iforce_set_gain(struct input_dev *dev, u16 gain)
{
struct iforce* iforce = dev->private;
unsigned char data[3];
data[0] = value >> 9; data[0] = gain >> 9;
iforce_send_packet(iforce, FF_CMD_GAIN, data); iforce_send_packet(iforce, FF_CMD_GAIN, data);
}
return 0; static void iforce_set_autocenter(struct input_dev *dev, u16 magnitude)
{
case FF_AUTOCENTER: struct iforce* iforce = dev->private;
unsigned char data[3];
data[0] = 0x03; data[0] = 0x03;
data[1] = value >> 9; data[1] = magnitude >> 9;
iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data); iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data);
data[0] = 0x04; data[0] = 0x04;
data[1] = 0x01; data[1] = 0x01;
iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data); iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data);
return 0;
default: /* Play or stop an effect */
if (!CHECK_OWNERSHIP(code, iforce)) {
return -1;
}
if (value > 0) {
set_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags);
}
else {
clear_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags);
}
iforce_control_playback(iforce, code, value);
return 0;
}
return -1;
} }
/* /*
* Function called when an ioctl is performed on the event dev entry. * Function called when an ioctl is performed on the event dev entry.
* It uploads an effect to the device * It uploads an effect to the device
*/ */
static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old)
{ {
struct iforce* iforce = dev->private; struct iforce* iforce = dev->private;
int id; struct iforce_core_effect *core_effect = &iforce->core_effects[effect->id];
int ret; int ret;
int is_update;
/* Check this effect type is supported by this device */
if (!test_bit(effect->type, iforce->dev->ffbit))
return -EINVAL;
/*
* If we want to create a new effect, get a free id
*/
if (effect->id == -1) {
for (id = 0; id < FF_EFFECTS_MAX; ++id)
if (!test_and_set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags))
break;
if (id == FF_EFFECTS_MAX || id >= iforce->dev->ff_effects_max)
return -ENOMEM;
effect->id = id;
iforce->core_effects[id].owner = current->pid;
iforce->core_effects[id].flags[0] = (1 << FF_CORE_IS_USED); /* Only IS_USED bit must be set */
is_update = FALSE;
}
else {
/* We want to update an effect */
if (!CHECK_OWNERSHIP(effect->id, iforce))
return -EACCES;
/* Parameter type cannot be updated */
if (effect->type != iforce->core_effects[effect->id].effect.type)
return -EINVAL;
if (__test_and_set_bit(FF_CORE_IS_USED, core_effect->flags)) {
/* Check the effect is not already being updated */ /* Check the effect is not already being updated */
if (test_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags)) if (test_bit(FF_CORE_UPDATE, core_effect->flags))
return -EAGAIN; return -EAGAIN;
is_update = TRUE;
} }
/* /*
...@@ -188,28 +142,28 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) ...@@ -188,28 +142,28 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect)
switch (effect->type) { switch (effect->type) {
case FF_PERIODIC: case FF_PERIODIC:
ret = iforce_upload_periodic(iforce, effect, is_update); ret = iforce_upload_periodic(iforce, effect, old);
break; break;
case FF_CONSTANT: case FF_CONSTANT:
ret = iforce_upload_constant(iforce, effect, is_update); ret = iforce_upload_constant(iforce, effect, old);
break; break;
case FF_SPRING: case FF_SPRING:
case FF_DAMPER: case FF_DAMPER:
ret = iforce_upload_condition(iforce, effect, is_update); ret = iforce_upload_condition(iforce, effect, old);
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }
if (ret == 0) { if (ret == 0) {
/* A packet was sent, forbid new updates until we are notified /* A packet was sent, forbid new updates until we are notified
* that the packet was updated * that the packet was updated
*/ */
set_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags); set_bit(FF_CORE_UPDATE, core_effect->flags);
} }
iforce->core_effects[effect->id].effect = *effect;
return ret; return ret;
} }
...@@ -219,20 +173,9 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) ...@@ -219,20 +173,9 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect)
*/ */
static int iforce_erase_effect(struct input_dev *dev, int effect_id) static int iforce_erase_effect(struct input_dev *dev, int effect_id)
{ {
struct iforce* iforce = dev->private; struct iforce *iforce = dev->private;
struct iforce_core_effect *core_effect = &iforce->core_effects[effect_id];
int err = 0; int err = 0;
struct iforce_core_effect* core_effect;
if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX)
return -EINVAL;
core_effect = &iforce->core_effects[effect_id];
/* Check who is trying to erase this effect */
if (core_effect->owner != current->pid) {
printk(KERN_WARNING "iforce-main.c: %d tried to erase an effect belonging to %d\n", current->pid, core_effect->owner);
return -EACCES;
}
if (test_bit(FF_MOD1_IS_USED, core_effect->flags)) if (test_bit(FF_MOD1_IS_USED, core_effect->flags))
err = release_resource(&core_effect->mod1_chunk); err = release_resource(&core_effect->mod1_chunk);
...@@ -240,7 +183,7 @@ static int iforce_erase_effect(struct input_dev *dev, int effect_id) ...@@ -240,7 +183,7 @@ static int iforce_erase_effect(struct input_dev *dev, int effect_id)
if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags)) if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags))
err = release_resource(&core_effect->mod2_chunk); err = release_resource(&core_effect->mod2_chunk);
/*TODO: remember to change that if more FF_MOD* bits are added */ /* TODO: remember to change that if more FF_MOD* bits are added */
core_effect->flags[0] = 0; core_effect->flags[0] = 0;
return err; return err;
...@@ -260,33 +203,11 @@ static int iforce_open(struct input_dev *dev) ...@@ -260,33 +203,11 @@ static int iforce_open(struct input_dev *dev)
#endif #endif
} }
if (test_bit(EV_FF, dev->evbit)) {
/* Enable force feedback */ /* Enable force feedback */
iforce_send_packet(iforce, FF_CMD_ENABLE, "\004"); iforce_send_packet(iforce, FF_CMD_ENABLE, "\004");
return 0;
}
static int iforce_flush(struct input_dev *dev, struct file *file)
{
struct iforce *iforce = dev->private;
int i;
/* Erase all effects this process owns */
for (i=0; i<dev->ff_effects_max; ++i) {
if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) &&
current->pid == iforce->core_effects[i].owner) {
/* Stop effect */
input_report_ff(dev, i, 0);
/* Free ressources assigned to effect */
if (iforce_erase_effect(dev, i)) {
printk(KERN_WARNING "iforce_flush: erase effect %d failed\n", i);
}
} }
}
return 0; return 0;
} }
...@@ -295,17 +216,18 @@ static void iforce_release(struct input_dev *dev) ...@@ -295,17 +216,18 @@ static void iforce_release(struct input_dev *dev)
struct iforce *iforce = dev->private; struct iforce *iforce = dev->private;
int i; int i;
/* Check: no effect should be present in memory */ if (test_bit(EV_FF, dev->evbit)) {
for (i=0; i<dev->ff_effects_max; ++i) { /* Check: no effects should be present in memory */
if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags)) for (i = 0; i < dev->ff->max_effects; i++) {
if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags)) {
printk(KERN_WARNING "iforce_release: Device still owns effects\n");
break; break;
} }
if (i<dev->ff_effects_max) {
printk(KERN_WARNING "iforce_release: Device still owns effects\n");
} }
/* Disable force feedback playback */ /* Disable force feedback playback */
iforce_send_packet(iforce, FF_CMD_ENABLE, "\001"); iforce_send_packet(iforce, FF_CMD_ENABLE, "\001");
}
switch (iforce->bus) { switch (iforce->bus) {
#ifdef CONFIG_JOYSTICK_IFORCE_USB #ifdef CONFIG_JOYSTICK_IFORCE_USB
...@@ -342,8 +264,10 @@ void iforce_delete_device(struct iforce *iforce) ...@@ -342,8 +264,10 @@ void iforce_delete_device(struct iforce *iforce)
int iforce_init_device(struct iforce *iforce) int iforce_init_device(struct iforce *iforce)
{ {
struct input_dev *input_dev; struct input_dev *input_dev;
struct ff_device *ff;
unsigned char c[] = "CEOV"; unsigned char c[] = "CEOV";
int i; int i, error;
int ff_effects = 0;
input_dev = input_allocate_device(); input_dev = input_allocate_device();
if (!input_dev) if (!input_dev)
...@@ -378,11 +302,6 @@ int iforce_init_device(struct iforce *iforce) ...@@ -378,11 +302,6 @@ int iforce_init_device(struct iforce *iforce)
input_dev->name = "Unknown I-Force device"; input_dev->name = "Unknown I-Force device";
input_dev->open = iforce_open; input_dev->open = iforce_open;
input_dev->close = iforce_release; input_dev->close = iforce_release;
input_dev->flush = iforce_flush;
input_dev->event = iforce_input_event;
input_dev->upload_effect = iforce_upload_effect;
input_dev->erase_effect = iforce_erase_effect;
input_dev->ff_effects_max = 10;
/* /*
* On-device memory allocation. * On-device memory allocation.
...@@ -430,15 +349,15 @@ int iforce_init_device(struct iforce *iforce) ...@@ -430,15 +349,15 @@ int iforce_init_device(struct iforce *iforce)
printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet B\n"); printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet B\n");
if (!iforce_get_id_packet(iforce, "N")) if (!iforce_get_id_packet(iforce, "N"))
iforce->dev->ff_effects_max = iforce->edata[1]; ff_effects = iforce->edata[1];
else else
printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet N\n"); printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet N\n");
/* Check if the device can store more effects than the driver can really handle */ /* Check if the device can store more effects than the driver can really handle */
if (iforce->dev->ff_effects_max > FF_EFFECTS_MAX) { if (ff_effects > IFORCE_EFFECTS_MAX) {
printk(KERN_WARNING "input??: Device can handle %d effects, but N_EFFECTS_MAX is set to %d in iforce.h\n", printk(KERN_WARNING "iforce: Limiting number of effects to %d (device reports %d)\n",
iforce->dev->ff_effects_max, FF_EFFECTS_MAX); IFORCE_EFFECTS_MAX, ff_effects);
iforce->dev->ff_effects_max = FF_EFFECTS_MAX; ff_effects = IFORCE_EFFECTS_MAX;
} }
/* /*
...@@ -472,12 +391,10 @@ int iforce_init_device(struct iforce *iforce) ...@@ -472,12 +391,10 @@ int iforce_init_device(struct iforce *iforce)
* Set input device bitfields and ranges. * Set input device bitfields and ranges.
*/ */
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF) | BIT(EV_FF_STATUS); input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF_STATUS);
for (i = 0; iforce->type->btn[i] >= 0; i++) { for (i = 0; iforce->type->btn[i] >= 0; i++)
signed short t = iforce->type->btn[i]; set_bit(iforce->type->btn[i], input_dev->keybit);
set_bit(t, input_dev->keybit);
}
set_bit(BTN_DEAD, input_dev->keybit); set_bit(BTN_DEAD, input_dev->keybit);
for (i = 0; iforce->type->abs[i] >= 0; i++) { for (i = 0; iforce->type->abs[i] >= 0; i++) {
...@@ -516,9 +433,24 @@ int iforce_init_device(struct iforce *iforce) ...@@ -516,9 +433,24 @@ int iforce_init_device(struct iforce *iforce)
} }
} }
if (ff_effects) {
for (i = 0; iforce->type->ff[i] >= 0; i++) for (i = 0; iforce->type->ff[i] >= 0; i++)
set_bit(iforce->type->ff[i], input_dev->ffbit); set_bit(iforce->type->ff[i], input_dev->ffbit);
error = input_ff_create(input_dev, ff_effects);
if (error) {
input_free_device(input_dev);
return error;
}
ff = input_dev->ff;
ff->upload = iforce_upload_effect;
ff->erase = iforce_erase_effect;
ff->set_gain = iforce_set_gain;
ff->set_autocenter = iforce_set_autocenter;
ff->playback = iforce_playback;
}
/* /*
* Register input device. * Register input device.
*/ */
......
...@@ -140,7 +140,10 @@ static int mark_core_as_ready(struct iforce *iforce, unsigned short addr) ...@@ -140,7 +140,10 @@ static int mark_core_as_ready(struct iforce *iforce, unsigned short addr)
{ {
int i; int i;
for (i = 0; i < iforce->dev->ff_effects_max; ++i) { if (!iforce->dev->ff)
return 0;
for (i = 0; i < iforce->dev->ff->max_effects; ++i) {
if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) && if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) &&
(iforce->core_effects[i].mod1_chunk.start == addr || (iforce->core_effects[i].mod1_chunk.start == addr ||
iforce->core_effects[i].mod2_chunk.start == addr)) { iforce->core_effects[i].mod2_chunk.start == addr)) {
...@@ -232,17 +235,15 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data, ...@@ -232,17 +235,15 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data,
/* Report play event */ /* Report play event */
input_report_ff_status(dev, i, FF_STATUS_PLAYING); input_report_ff_status(dev, i, FF_STATUS_PLAYING);
} }
} } else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
/* Report stop event */ /* Report stop event */
input_report_ff_status(dev, i, FF_STATUS_STOPPED); input_report_ff_status(dev, i, FF_STATUS_STOPPED);
} }
if (LO(cmd) > 3) { if (LO(cmd) > 3) {
int j; int j;
for (j=3; j<LO(cmd); j+=2) { for (j = 3; j < LO(cmd); j += 2)
mark_core_as_ready(iforce, data[j] | (data[j+1]<<8)); mark_core_as_ready(iforce, data[j] | (data[j+1]<<8));
} }
}
break; break;
} }
being_used--; being_used--;
......
...@@ -51,10 +51,7 @@ ...@@ -51,10 +51,7 @@
#define IFORCE_232 1 #define IFORCE_232 1
#define IFORCE_USB 2 #define IFORCE_USB 2
#define FALSE 0 #define IFORCE_EFFECTS_MAX 32
#define TRUE 1
#define FF_EFFECTS_MAX 32
/* Each force feedback effect is made of one core effect, which can be /* Each force feedback effect is made of one core effect, which can be
* associated to at most to effect modifiers * associated to at most to effect modifiers
...@@ -67,24 +64,11 @@ ...@@ -67,24 +64,11 @@
#define FF_CORE_UPDATE 5 /* Effect is being updated */ #define FF_CORE_UPDATE 5 /* Effect is being updated */
#define FF_MODCORE_MAX 5 #define FF_MODCORE_MAX 5
#define CHECK_OWNERSHIP(i, iforce) \
((i) < FF_EFFECTS_MAX && i >= 0 && \
test_bit(FF_CORE_IS_USED, (iforce)->core_effects[(i)].flags) && \
(current->pid == 0 || \
(iforce)->core_effects[(i)].owner == current->pid))
struct iforce_core_effect { struct iforce_core_effect {
/* Information about where modifiers are stored in the device's memory */ /* Information about where modifiers are stored in the device's memory */
struct resource mod1_chunk; struct resource mod1_chunk;
struct resource mod2_chunk; struct resource mod2_chunk;
unsigned long flags[NBITS(FF_MODCORE_MAX)]; unsigned long flags[NBITS(FF_MODCORE_MAX)];
pid_t owner;
/* Used to keep track of parameters of an effect. They are needed
* to know what parts of an effect changed in an update operation.
* We try to send only parameter packets if possible, as sending
* effect parameter requires the effect to be stoped and restarted
*/
struct ff_effect effect;
}; };
#define FF_CMD_EFFECT 0x010e #define FF_CMD_EFFECT 0x010e
...@@ -145,7 +129,7 @@ struct iforce { ...@@ -145,7 +129,7 @@ struct iforce {
/* Force Feedback */ /* Force Feedback */
wait_queue_head_t wait; wait_queue_head_t wait;
struct resource device_memory; struct resource device_memory;
struct iforce_core_effect core_effects[FF_EFFECTS_MAX]; struct iforce_core_effect core_effects[IFORCE_EFFECTS_MAX];
struct mutex mem_mutex; struct mutex mem_mutex;
}; };
...@@ -182,9 +166,9 @@ void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) ; ...@@ -182,9 +166,9 @@ void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) ;
int iforce_get_id_packet(struct iforce *iforce, char *packet); int iforce_get_id_packet(struct iforce *iforce, char *packet);
/* iforce-ff.c */ /* iforce-ff.c */
int iforce_upload_periodic(struct iforce*, struct ff_effect*, int is_update); int iforce_upload_periodic(struct iforce *, struct ff_effect *, struct ff_effect *);
int iforce_upload_constant(struct iforce*, struct ff_effect*, int is_update); int iforce_upload_constant(struct iforce *, struct ff_effect *, struct ff_effect *);
int iforce_upload_condition(struct iforce*, struct ff_effect*, int is_update); int iforce_upload_condition(struct iforce *, struct ff_effect *, struct ff_effect *);
/* Public variables */ /* Public variables */
extern struct serio_driver iforce_serio_drv; extern struct serio_driver iforce_serio_drv;
......
...@@ -121,6 +121,17 @@ config KEYBOARD_NEWTON ...@@ -121,6 +121,17 @@ config KEYBOARD_NEWTON
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called newtonkbd. module will be called newtonkbd.
config KEYBOARD_STOWAWAY
tristate "Stowaway keyboard"
select SERIO
help
Say Y here if you have a Stowaway keyboard on a serial port.
Stowaway compatible keyboards like Dicota Input-PDA keyboard
are also supported by this driver.
To compile this driver as a module, choose M here: the
module will be called stowaway.
config KEYBOARD_CORGI config KEYBOARD_CORGI
tristate "Corgi keyboard" tristate "Corgi keyboard"
depends on PXA_SHARPSL depends on PXA_SHARPSL
......
...@@ -11,6 +11,7 @@ obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o ...@@ -11,6 +11,7 @@ obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o
obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o
obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
......
...@@ -652,9 +652,7 @@ static int atkbd_probe(struct atkbd *atkbd) ...@@ -652,9 +652,7 @@ static int atkbd_probe(struct atkbd *atkbd)
return 0; return 0;
} }
if (param[0] != 0xab && param[0] != 0xac && /* Regular and NCD Sun keyboards */ if (!ps2_is_keyboard_id(param[0]))
param[0] != 0x2b && param[0] != 0x5d && /* Trust keyboard, raw and translated */
param[0] != 0x60 && param[0] != 0x47) /* NMB SGI keyboard, raw and translated */
return -1; return -1;
atkbd->id = (param[0] << 8) | param[1]; atkbd->id = (param[0] << 8) | param[1];
......
/*
* Stowaway keyboard driver for Linux
*/
/*
* Copyright (c) 2006 Marek Vasut
*
* Based on Newton keyboard driver for Linux
* by Justin Cormack
*/
/*
* 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
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <marek.vasut@gmail.com>, or by paper mail:
* Marek Vasut, Liskovecka 559, Frydek-Mistek, 738 01 Czech Republic
*/
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
#define DRIVER_DESC "Stowaway keyboard driver"
MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
#define SKBD_KEY_MASK 0x7f
#define SKBD_RELEASE 0x80
static unsigned char skbd_keycode[128] = {
KEY_1, KEY_2, KEY_3, KEY_Z, KEY_4, KEY_5, KEY_6, KEY_7,
0, KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, KEY_Y, KEY_GRAVE,
KEY_X, KEY_A, KEY_S, KEY_D, KEY_F, KEY_G, KEY_H, KEY_SPACE,
KEY_CAPSLOCK, KEY_TAB, KEY_LEFTCTRL, 0, 0, 0, 0, 0,
0, 0, 0, KEY_LEFTALT, 0, 0, 0, 0,
0, 0, 0, 0, KEY_C, KEY_V, KEY_B, KEY_N,
KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, KEY_HOME, KEY_8, KEY_9, KEY_0, KEY_ESC,
KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_BACKSLASH, KEY_END, KEY_U, KEY_I, KEY_O, KEY_P,
KEY_APOSTROPHE, KEY_ENTER, KEY_PAGEUP,0, KEY_J, KEY_K, KEY_L, KEY_SEMICOLON,
KEY_SLASH, KEY_UP, KEY_PAGEDOWN, 0,KEY_M, KEY_COMMA, KEY_DOT, KEY_INSERT,
KEY_DELETE, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0,
KEY_LEFTSHIFT, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7,
KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, 0, 0, 0
};
struct skbd {
unsigned char keycode[128];
struct input_dev *dev;
struct serio *serio;
char phys[32];
};
static irqreturn_t skbd_interrupt(struct serio *serio, unsigned char data,
unsigned int flags, struct pt_regs *regs)
{
struct skbd *skbd = serio_get_drvdata(serio);
struct input_dev *dev = skbd->dev;
if (skbd->keycode[data & SKBD_KEY_MASK]) {
input_regs(dev, regs);
input_report_key(dev, skbd->keycode[data & SKBD_KEY_MASK],
!(data & SKBD_RELEASE));
input_sync(dev);
}
return IRQ_HANDLED;
}
static int skbd_connect(struct serio *serio, struct serio_driver *drv)
{
struct skbd *skbd;
struct input_dev *input_dev;
int err = -ENOMEM;
int i;
skbd = kzalloc(sizeof(struct skbd), GFP_KERNEL);
input_dev = input_allocate_device();
if (!skbd || !input_dev)
goto fail1;
skbd->serio = serio;
skbd->dev = input_dev;
snprintf(skbd->phys, sizeof(skbd->phys), "%s/input0", serio->phys);
memcpy(skbd->keycode, skbd_keycode, sizeof(skbd->keycode));
input_dev->name = "Stowaway Keyboard";
input_dev->phys = skbd->phys;
input_dev->id.bustype = BUS_RS232;
input_dev->id.vendor = SERIO_STOWAWAY;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
input_dev->cdev.dev = &serio->dev;
input_dev->private = skbd;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
input_dev->keycode = skbd->keycode;
input_dev->keycodesize = sizeof(unsigned char);
input_dev->keycodemax = ARRAY_SIZE(skbd_keycode);
for (i = 0; i < ARRAY_SIZE(skbd_keycode); i++)
set_bit(skbd_keycode[i], input_dev->keybit);
clear_bit(0, input_dev->keybit);
serio_set_drvdata(serio, skbd);
err = serio_open(serio, drv);
if (err)
goto fail2;
err = input_register_device(skbd->dev);
if (err)
goto fail3;
return 0;
fail3: serio_close(serio);
fail2: serio_set_drvdata(serio, NULL);
fail1: input_free_device(input_dev);
kfree(skbd);
return err;
}
static void skbd_disconnect(struct serio *serio)
{
struct skbd *skbd = serio_get_drvdata(serio);
serio_close(serio);
serio_set_drvdata(serio, NULL);
input_unregister_device(skbd->dev);
kfree(skbd);
}
static struct serio_device_id skbd_serio_ids[] = {
{
.type = SERIO_RS232,
.proto = SERIO_STOWAWAY,
.id = SERIO_ANY,
.extra = SERIO_ANY,
},
{ 0 }
};
MODULE_DEVICE_TABLE(serio, skbd_serio_ids);
static struct serio_driver skbd_drv = {
.driver = {
.name = "stowaway",
},
.description = DRIVER_DESC,
.id_table = skbd_serio_ids,
.interrupt = skbd_interrupt,
.connect = skbd_connect,
.disconnect = skbd_disconnect,
};
static int __init skbd_init(void)
{
serio_register_driver(&skbd_drv);
return 0;
}
static void __exit skbd_exit(void)
{
serio_unregister_driver(&skbd_drv);
}
module_init(skbd_init);
module_exit(skbd_exit);
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
* Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
* *
* Changes/Revisions: * Changes/Revisions:
* 0.3 09/04/2006 (Anssi Hannula <anssi.hannula@gmail.com>)
* - updated ff support for the changes in kernel interface
* - added MODULE_VERSION
* 0.2 16/10/2004 (Micah Dowty <micah@navi.cx>) * 0.2 16/10/2004 (Micah Dowty <micah@navi.cx>)
* - added force feedback support * - added force feedback support
* - added UI_SET_PHYS * - added UI_SET_PHYS
...@@ -107,18 +110,31 @@ static int uinput_request_submit(struct input_dev *dev, struct uinput_request *r ...@@ -107,18 +110,31 @@ static int uinput_request_submit(struct input_dev *dev, struct uinput_request *r
return request->retval; 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; struct uinput_request request;
int retval; int retval;
if (!test_bit(EV_FF, dev->evbit))
return -ENOSYS;
request.id = -1; request.id = -1;
init_completion(&request.done); init_completion(&request.done);
request.code = UI_FF_UPLOAD; 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); retval = uinput_request_reserve_slot(dev->private, &request);
if (!retval) if (!retval)
...@@ -168,6 +184,7 @@ static void uinput_destroy_device(struct uinput_device *udev) ...@@ -168,6 +184,7 @@ static void uinput_destroy_device(struct uinput_device *udev)
static int uinput_create_device(struct uinput_device *udev) static int uinput_create_device(struct uinput_device *udev)
{ {
struct input_dev *dev = udev->dev;
int error; int error;
if (udev->state != UIST_SETUP_COMPLETE) { if (udev->state != UIST_SETUP_COMPLETE) {
...@@ -175,15 +192,29 @@ static int uinput_create_device(struct uinput_device *udev) ...@@ -175,15 +192,29 @@ static int uinput_create_device(struct uinput_device *udev)
return -EINVAL; return -EINVAL;
} }
error = input_register_device(udev->dev); if (udev->ff_effects_max) {
if (error) { error = input_ff_create(dev, udev->ff_effects_max);
uinput_destroy_device(udev); if (error)
return 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; udev->state = UIST_CREATED;
return 0; return 0;
fail2: input_ff_destroy(dev);
fail1: uinput_destroy_device(udev);
return error;
} }
static int uinput_open(struct inode *inode, struct file *file) static int uinput_open(struct inode *inode, struct file *file)
...@@ -243,8 +274,6 @@ static int uinput_allocate_device(struct uinput_device *udev) ...@@ -243,8 +274,6 @@ static int uinput_allocate_device(struct uinput_device *udev)
return -ENOMEM; return -ENOMEM;
udev->dev->event = uinput_dev_event; 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; udev->dev->private = udev;
return 0; return 0;
...@@ -278,6 +307,8 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu ...@@ -278,6 +307,8 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu
goto exit; goto exit;
} }
udev->ff_effects_max = user_dev->ff_effects_max;
size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1; size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1;
if (!size) { if (!size) {
retval = -EINVAL; retval = -EINVAL;
...@@ -296,7 +327,6 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu ...@@ -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.vendor = user_dev->id.vendor;
dev->id.product = user_dev->id.product; dev->id.product = user_dev->id.product;
dev->id.version = user_dev->id.version; dev->id.version = user_dev->id.version;
dev->ff_effects_max = user_dev->ff_effects_max;
size = sizeof(int) * (ABS_MAX + 1); size = sizeof(int) * (ABS_MAX + 1);
memcpy(dev->absmax, user_dev->absmax, size); memcpy(dev->absmax, user_dev->absmax, size);
...@@ -525,12 +555,17 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -525,12 +555,17 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break; break;
} }
req = uinput_request_find(udev, ff_up.request_id); 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; retval = -EINVAL;
break; break;
} }
ff_up.retval = 0; 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))) { if (copy_to_user(p, &ff_up, sizeof(ff_up))) {
retval = -EFAULT; retval = -EFAULT;
break; break;
...@@ -561,12 +596,11 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -561,12 +596,11 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break; break;
} }
req = uinput_request_find(udev, ff_up.request_id); 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; retval = -EINVAL;
break; break;
} }
req->retval = ff_up.retval; req->retval = ff_up.retval;
memcpy(req->u.effect, &ff_up.effect, sizeof(struct ff_effect));
uinput_request_done(udev, req); uinput_request_done(udev, req);
break; break;
...@@ -622,6 +656,7 @@ static void __exit uinput_exit(void) ...@@ -622,6 +656,7 @@ static void __exit uinput_exit(void)
MODULE_AUTHOR("Aristeu Sergio Rozanski Filho"); MODULE_AUTHOR("Aristeu Sergio Rozanski Filho");
MODULE_DESCRIPTION("User level driver support for input subsystem"); MODULE_DESCRIPTION("User level driver support for input subsystem");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_VERSION("0.3");
module_init(uinput_init); module_init(uinput_init);
module_exit(uinput_exit); module_exit(uinput_exit);
......
...@@ -248,13 +248,10 @@ static int __init dmi_matched(struct dmi_system_id *dmi) ...@@ -248,13 +248,10 @@ static int __init dmi_matched(struct dmi_system_id *dmi)
keymap = dmi->driver_data; keymap = dmi->driver_data;
for (key = keymap; key->type != KE_END; key++) { for (key = keymap; key->type != KE_END; key++) {
if (key->type == KE_WIFI) { if (key->type == KE_WIFI)
have_wifi = 1; have_wifi = 1;
break; else if (key->type == KE_BLUETOOTH)
} else if (key->type == KE_BLUETOOTH) {
have_bluetooth = 1; have_bluetooth = 1;
break;
}
} }
return 1; return 1;
} }
...@@ -389,6 +386,15 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -389,6 +386,15 @@ static struct dmi_system_id dmi_ids[] __initdata = {
}, },
.driver_data = keymap_acer_travelmate_240 .driver_data = keymap_acer_travelmate_240
}, },
{
.callback = dmi_matched,
.ident = "Acer TravelMate 2424NWXCi",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2420"),
},
.driver_data = keymap_acer_travelmate_240
},
{ {
.callback = dmi_matched, .callback = dmi_matched,
.ident = "AOpen 1559AS", .ident = "AOpen 1559AS",
......
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
#define ALPS_PASS 0x20 #define ALPS_PASS 0x20
#define ALPS_FW_BK_2 0x40 #define ALPS_FW_BK_2 0x40
static struct alps_model_info alps_model_data[] = { static const struct alps_model_info alps_model_data[] = {
{ { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */ { { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */
{ { 0x53, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, { { 0x53, 0x02, 0x0a }, 0xf8, 0xf8, 0 },
{ { 0x53, 0x02, 0x14 }, 0xf8, 0xf8, 0 }, { { 0x53, 0x02, 0x14 }, 0xf8, 0xf8, 0 },
...@@ -209,10 +209,10 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse, struct pt_regs * ...@@ -209,10 +209,10 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse, struct pt_regs *
return PSMOUSE_GOOD_DATA; return PSMOUSE_GOOD_DATA;
} }
static struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version) static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version)
{ {
struct ps2dev *ps2dev = &psmouse->ps2dev; struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 }; static const unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 };
unsigned char param[4]; unsigned char param[4];
int i; int i;
...@@ -504,7 +504,7 @@ int alps_init(struct psmouse *psmouse) ...@@ -504,7 +504,7 @@ int alps_init(struct psmouse *psmouse)
int alps_detect(struct psmouse *psmouse, int set_properties) int alps_detect(struct psmouse *psmouse, int set_properties)
{ {
int version; int version;
struct alps_model_info *model; const struct alps_model_info *model;
if (!(model = alps_get_model(psmouse, &version))) if (!(model = alps_get_model(psmouse, &version)))
return -1; return -1;
......
...@@ -25,7 +25,7 @@ struct alps_data { ...@@ -25,7 +25,7 @@ struct alps_data {
struct input_dev *dev2; /* Relative device */ struct input_dev *dev2; /* Relative device */
char name[32]; /* Name */ char name[32]; /* Name */
char phys[32]; /* Phys */ char phys[32]; /* Phys */
struct alps_model_info *i; /* Info */ const struct alps_model_info *i;/* Info */
int prev_fin; /* Finger bit from previous packet */ int prev_fin; /* Finger bit from previous packet */
}; };
......
...@@ -115,13 +115,15 @@ static int lifebook_absolute_mode(struct psmouse *psmouse) ...@@ -115,13 +115,15 @@ static int lifebook_absolute_mode(struct psmouse *psmouse)
static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution) static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution)
{ {
unsigned char params[] = { 0, 1, 2, 2, 3 }; static const unsigned char params[] = { 0, 1, 2, 2, 3 };
unsigned char p;
if (resolution == 0 || resolution > 400) if (resolution == 0 || resolution > 400)
resolution = 400; resolution = 400;
ps2_command(&psmouse->ps2dev, &params[resolution / 100], PSMOUSE_CMD_SETRES); p = params[resolution / 100];
psmouse->resolution = 50 << params[resolution / 100]; ps2_command(&psmouse->ps2dev, &p, PSMOUSE_CMD_SETRES);
psmouse->resolution = 50 << p;
} }
static void lifebook_disconnect(struct psmouse *psmouse) static void lifebook_disconnect(struct psmouse *psmouse)
......
...@@ -30,9 +30,9 @@ ...@@ -30,9 +30,9 @@
#define PS2PP_NAV_BTN 0x20 #define PS2PP_NAV_BTN 0x20
struct ps2pp_info { struct ps2pp_info {
const int model; u8 model;
unsigned const int kind; u8 kind;
unsigned const int features; u16 features;
}; };
/* /*
...@@ -199,9 +199,9 @@ static void ps2pp_disconnect(struct psmouse *psmouse) ...@@ -199,9 +199,9 @@ static void ps2pp_disconnect(struct psmouse *psmouse)
device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll.dattr); device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll.dattr);
} }
static struct ps2pp_info *get_model_info(unsigned char model) static const struct ps2pp_info *get_model_info(unsigned char model)
{ {
static struct ps2pp_info ps2pp_list[] = { static const struct ps2pp_info ps2pp_list[] = {
{ 12, 0, PS2PP_SIDE_BTN}, { 12, 0, PS2PP_SIDE_BTN},
{ 13, 0, 0 }, { 13, 0, 0 },
{ 15, PS2PP_KIND_MX, /* MX1000 */ { 15, PS2PP_KIND_MX, /* MX1000 */
...@@ -215,6 +215,7 @@ static struct ps2pp_info *get_model_info(unsigned char model) ...@@ -215,6 +215,7 @@ static struct ps2pp_info *get_model_info(unsigned char model)
{ 51, 0, 0 }, { 51, 0, 0 },
{ 52, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, { 52, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL },
{ 53, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, { 53, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
{ 56, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, /* Cordless MouseMan Wheel */
{ 61, PS2PP_KIND_MX, /* MX700 */ { 61, PS2PP_KIND_MX, /* MX700 */
PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
...@@ -244,12 +245,11 @@ static struct ps2pp_info *get_model_info(unsigned char model) ...@@ -244,12 +245,11 @@ static struct ps2pp_info *get_model_info(unsigned char model)
PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
{ 114, PS2PP_KIND_MX, /* MX310 */ { 114, PS2PP_KIND_MX, /* MX310 */
PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_WHEEL | PS2PP_SIDE_BTN |
PS2PP_TASK_BTN | PS2PP_EXTRA_BTN }, PS2PP_TASK_BTN | PS2PP_EXTRA_BTN }
{ }
}; };
int i; int i;
for (i = 0; ps2pp_list[i].model; i++) for (i = 0; i < ARRAY_SIZE(ps2pp_list); i++)
if (model == ps2pp_list[i].model) if (model == ps2pp_list[i].model)
return &ps2pp_list[i]; return &ps2pp_list[i];
...@@ -261,7 +261,8 @@ static struct ps2pp_info *get_model_info(unsigned char model) ...@@ -261,7 +261,8 @@ static struct ps2pp_info *get_model_info(unsigned char model)
* Set up input device's properties based on the detected mouse model. * Set up input device's properties based on the detected mouse model.
*/ */
static void ps2pp_set_model_properties(struct psmouse *psmouse, struct ps2pp_info *model_info, static void ps2pp_set_model_properties(struct psmouse *psmouse,
const struct ps2pp_info *model_info,
int using_ps2pp) int using_ps2pp)
{ {
struct input_dev *input_dev = psmouse->dev; struct input_dev *input_dev = psmouse->dev;
...@@ -327,7 +328,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties) ...@@ -327,7 +328,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
struct ps2dev *ps2dev = &psmouse->ps2dev; struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4]; unsigned char param[4];
unsigned char model, buttons; unsigned char model, buttons;
struct ps2pp_info *model_info; const struct ps2pp_info *model_info;
int use_ps2pp = 0; int use_ps2pp = 0;
param[0] = 0; param[0] = 0;
...@@ -349,7 +350,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties) ...@@ -349,7 +350,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
/* /*
* Do Logitech PS2++ / PS2T++ magic init. * Do Logitech PS2++ / PS2T++ magic init.
*/ */
if (model == 97) { /* Touch Pad 3 */ if (model_info->kind == PS2PP_KIND_TP3) { /* Touch Pad 3 */
/* Unprotect RAM */ /* Unprotect RAM */
param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; param[0] = 0x11; param[1] = 0x04; param[2] = 0x68;
......
...@@ -112,8 +112,8 @@ static struct workqueue_struct *kpsmoused_wq; ...@@ -112,8 +112,8 @@ static struct workqueue_struct *kpsmoused_wq;
struct psmouse_protocol { struct psmouse_protocol {
enum psmouse_type type; enum psmouse_type type;
char *name; const char *name;
char *alias; const char *alias;
int maxproto; int maxproto;
int (*detect)(struct psmouse *, int); int (*detect)(struct psmouse *, int);
int (*init)(struct psmouse *); int (*init)(struct psmouse *);
...@@ -507,15 +507,17 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties) ...@@ -507,15 +507,17 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties)
{ {
struct ps2dev *ps2dev = &psmouse->ps2dev; struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[2]; unsigned char param[2];
unsigned char seq[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20, 0 }; static const unsigned char seq[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 };
int i; int i;
param[0] = 10; param[0] = 10;
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
param[0] = 0; param[0] = 0;
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
for (i = 0; seq[i]; i++) for (i = 0; i < ARRAY_SIZE(seq); i++) {
ps2_command(ps2dev, seq + i, PSMOUSE_CMD_SETRATE); param[0] = seq[i];
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
}
ps2_command(ps2dev, param, PSMOUSE_CMD_GETID); ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
if (param[0] != 2) if (param[0] != 2)
...@@ -652,7 +654,7 @@ static int psmouse_extensions(struct psmouse *psmouse, ...@@ -652,7 +654,7 @@ static int psmouse_extensions(struct psmouse *psmouse,
return PSMOUSE_PS2; return PSMOUSE_PS2;
} }
static struct psmouse_protocol psmouse_protocols[] = { static const struct psmouse_protocol psmouse_protocols[] = {
{ {
.type = PSMOUSE_PS2, .type = PSMOUSE_PS2,
.name = "PS/2", .name = "PS/2",
...@@ -726,7 +728,7 @@ static struct psmouse_protocol psmouse_protocols[] = { ...@@ -726,7 +728,7 @@ static struct psmouse_protocol psmouse_protocols[] = {
}, },
}; };
static struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type) static const struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type)
{ {
int i; int i;
...@@ -738,9 +740,9 @@ static struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type) ...@@ -738,9 +740,9 @@ static struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type)
return &psmouse_protocols[0]; return &psmouse_protocols[0];
} }
static struct psmouse_protocol *psmouse_protocol_by_name(const char *name, size_t len) static const struct psmouse_protocol *psmouse_protocol_by_name(const char *name, size_t len)
{ {
struct psmouse_protocol *p; const struct psmouse_protocol *p;
int i; int i;
for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++) { for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++) {
...@@ -795,13 +797,15 @@ static int psmouse_probe(struct psmouse *psmouse) ...@@ -795,13 +797,15 @@ static int psmouse_probe(struct psmouse *psmouse)
void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution) void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution)
{ {
unsigned char params[] = { 0, 1, 2, 2, 3 }; static const unsigned char params[] = { 0, 1, 2, 2, 3 };
unsigned char p;
if (resolution == 0 || resolution > 200) if (resolution == 0 || resolution > 200)
resolution = 200; resolution = 200;
ps2_command(&psmouse->ps2dev, &params[resolution / 50], PSMOUSE_CMD_SETRES); p = params[resolution / 50];
psmouse->resolution = 25 << params[resolution / 50]; ps2_command(&psmouse->ps2dev, &p, PSMOUSE_CMD_SETRES);
psmouse->resolution = 25 << p;
} }
/* /*
...@@ -810,12 +814,14 @@ void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution) ...@@ -810,12 +814,14 @@ void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution)
static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate) static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate)
{ {
unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 }; static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 };
unsigned char r;
int i = 0; int i = 0;
while (rates[i] > rate) i++; while (rates[i] > rate) i++;
ps2_command(&psmouse->ps2dev, &rates[i], PSMOUSE_CMD_SETRATE); r = rates[i];
psmouse->rate = rates[i]; ps2_command(&psmouse->ps2dev, &r, PSMOUSE_CMD_SETRATE);
psmouse->rate = r;
} }
/* /*
...@@ -1031,7 +1037,7 @@ static void psmouse_disconnect(struct serio *serio) ...@@ -1031,7 +1037,7 @@ static void psmouse_disconnect(struct serio *serio)
mutex_unlock(&psmouse_mutex); mutex_unlock(&psmouse_mutex);
} }
static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_protocol *proto) static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse_protocol *proto)
{ {
struct input_dev *input_dev = psmouse->dev; struct input_dev *input_dev = psmouse->dev;
...@@ -1362,7 +1368,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co ...@@ -1362,7 +1368,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co
struct serio *serio = psmouse->ps2dev.serio; struct serio *serio = psmouse->ps2dev.serio;
struct psmouse *parent = NULL; struct psmouse *parent = NULL;
struct input_dev *new_dev; struct input_dev *new_dev;
struct psmouse_protocol *proto; const struct psmouse_protocol *proto;
int retry = 0; int retry = 0;
if (!(proto = psmouse_protocol_by_name(buf, count))) if (!(proto = psmouse_protocol_by_name(buf, count)))
...@@ -1459,7 +1465,7 @@ static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, void *data, ...@@ -1459,7 +1465,7 @@ static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, void *data,
static int psmouse_set_maxproto(const char *val, struct kernel_param *kp) static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
{ {
struct psmouse_protocol *proto; const struct psmouse_protocol *proto;
if (!val) if (!val)
return -EINVAL; return -EINVAL;
......
...@@ -42,7 +42,7 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); ...@@ -42,7 +42,7 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION(DRIVER_DESC); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse", static const char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse",
"Logitech M+ Mouse", "Microsoft MZ Mouse", "Logitech MZ+ Mouse", "Logitech M+ Mouse", "Microsoft MZ Mouse", "Logitech MZ+ Mouse",
"Logitech MZ++ Mouse"}; "Logitech MZ++ Mouse"};
......
...@@ -430,11 +430,11 @@ static void synaptics_process_packet(struct psmouse *psmouse) ...@@ -430,11 +430,11 @@ static void synaptics_process_packet(struct psmouse *psmouse)
static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type) static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type)
{ {
static unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 }; static const unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 };
static unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 }; static const unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 };
static unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 }; static const unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 };
static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 }; static const unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 }; static const unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
if (idx < 0 || idx > 4) if (idx < 0 || idx > 4)
return 0; return 0;
......
...@@ -614,7 +614,7 @@ static unsigned int mousedev_poll(struct file *file, poll_table *wait) ...@@ -614,7 +614,7 @@ static unsigned int mousedev_poll(struct file *file, poll_table *wait)
(list->mousedev->exist ? 0 : (POLLHUP | POLLERR)); (list->mousedev->exist ? 0 : (POLLHUP | POLLERR));
} }
static struct file_operations mousedev_fops = { static const struct file_operations mousedev_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.read = mousedev_read, .read = mousedev_read,
.write = mousedev_write, .write = mousedev_write,
...@@ -624,7 +624,8 @@ static struct file_operations mousedev_fops = { ...@@ -624,7 +624,8 @@ static struct file_operations mousedev_fops = {
.fasync = mousedev_fasync, .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 mousedev *mousedev;
struct class_device *cdev; struct class_device *cdev;
...@@ -688,7 +689,7 @@ static void mousedev_disconnect(struct input_handle *handle) ...@@ -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, .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
.evbit = { BIT(EV_KEY) | BIT(EV_REL) }, .evbit = { BIT(EV_KEY) | BIT(EV_REL) },
...@@ -737,7 +738,12 @@ static int psaux_registered; ...@@ -737,7 +738,12 @@ static int psaux_registered;
static int __init mousedev_init(void) 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)); memset(&mousedev_mix, 0, sizeof(struct mousedev));
INIT_LIST_HEAD(&mousedev_mix.list); INIT_LIST_HEAD(&mousedev_mix.list);
...@@ -746,12 +752,20 @@ static int __init mousedev_init(void) ...@@ -746,12 +752,20 @@ static int __init mousedev_init(void)
mousedev_mix.exist = 1; mousedev_mix.exist = 1;
mousedev_mix.minor = MOUSEDEV_MIX; 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"); 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 #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
if (!(psaux_registered = !misc_register(&psaux_mouse))) error = misc_register(&psaux_mouse);
printk(KERN_WARNING "mice: could not misc_register the device\n"); if (error)
printk(KERN_WARNING "mice: could not register psaux device, "
"error: %d\n", error);
else
psaux_registered = 1;
#endif #endif
printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n"); printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n");
......
...@@ -98,7 +98,7 @@ static void power_event(struct input_handle *handle, unsigned int type, ...@@ -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, static struct input_handle *power_connect(struct input_handler *handler,
struct input_dev *dev, struct input_dev *dev,
struct input_device_id *id) const struct input_device_id *id)
{ {
struct input_handle *handle; struct input_handle *handle;
...@@ -120,7 +120,7 @@ static void power_disconnect(struct input_handle *handle) ...@@ -120,7 +120,7 @@ static void power_disconnect(struct input_handle *handle)
kfree(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, .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
.evbit = { BIT(EV_KEY) }, .evbit = { BIT(EV_KEY) },
...@@ -150,8 +150,7 @@ static struct input_handler power_handler = { ...@@ -150,8 +150,7 @@ static struct input_handler power_handler = {
static int __init power_init(void) static int __init power_init(void)
{ {
input_register_handler(&power_handler); return input_register_handler(&power_handler);
return 0;
} }
static void __exit power_exit(void) static void __exit power_exit(void)
......
...@@ -159,6 +159,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { ...@@ -159,6 +159,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P10"), DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P10"),
}, },
}, },
{
.ident = "Toshiba Equium A110",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_MATCH(DMI_PRODUCT_NAME, "EQUIUM A110"),
},
},
{ {
.ident = "Alienware Sentia", .ident = "Alienware Sentia",
.matches = { .matches = {
...@@ -180,6 +187,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { ...@@ -180,6 +187,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FS115B"), DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FS115B"),
}, },
}, },
{
.ident = "Amoi M636/A737",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Amoi Electronics CO.,LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "M636/A737 platform"),
},
},
{ } { }
}; };
......
This diff is collapsed.
...@@ -36,15 +36,6 @@ ...@@ -36,15 +36,6 @@
#define I8042_CTL_TIMEOUT 10000 #define I8042_CTL_TIMEOUT 10000
/*
* When the device isn't opened and it's interrupts aren't used, we poll it at
* regular intervals to see if any characters arrived. If yes, we can start
* probing for any mouse / keyboard connected. This is the period of the
* polling.
*/
#define I8042_POLL_PERIOD HZ/20
/* /*
* Status register bits. * Status register bits.
*/ */
......
...@@ -27,15 +27,6 @@ MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); ...@@ -27,15 +27,6 @@ MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
MODULE_DESCRIPTION("PS/2 driver library"); MODULE_DESCRIPTION("PS/2 driver library");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
EXPORT_SYMBOL(ps2_init);
EXPORT_SYMBOL(ps2_sendbyte);
EXPORT_SYMBOL(ps2_drain);
EXPORT_SYMBOL(ps2_command);
EXPORT_SYMBOL(ps2_schedule_command);
EXPORT_SYMBOL(ps2_handle_ack);
EXPORT_SYMBOL(ps2_handle_response);
EXPORT_SYMBOL(ps2_cmd_aborted);
/* Work structure to schedule execution of a command */ /* Work structure to schedule execution of a command */
struct ps2work { struct ps2work {
struct work_struct work; struct work_struct work;
...@@ -71,6 +62,7 @@ int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout) ...@@ -71,6 +62,7 @@ int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
return -ps2dev->nak; return -ps2dev->nak;
} }
EXPORT_SYMBOL(ps2_sendbyte);
/* /*
* ps2_drain() waits for device to transmit requested number of bytes * ps2_drain() waits for device to transmit requested number of bytes
...@@ -96,15 +88,16 @@ void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout) ...@@ -96,15 +88,16 @@ void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout)
msecs_to_jiffies(timeout)); msecs_to_jiffies(timeout));
mutex_unlock(&ps2dev->cmd_mutex); mutex_unlock(&ps2dev->cmd_mutex);
} }
EXPORT_SYMBOL(ps2_drain);
/* /*
* ps2_is_keyboard_id() checks received ID byte against the list of * ps2_is_keyboard_id() checks received ID byte against the list of
* known keyboard IDs. * 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 */ 0xab, /* Regular keyboards */
0xac, /* NCD Sun keyboard */ 0xac, /* NCD Sun keyboard */
0x2b, /* Trust keyboard, translated */ 0x2b, /* Trust keyboard, translated */
...@@ -115,6 +108,7 @@ static inline int ps2_is_keyboard_id(char id_byte) ...@@ -115,6 +108,7 @@ static inline int ps2_is_keyboard_id(char id_byte)
return memchr(keyboard_ids, id_byte, sizeof(keyboard_ids)) != NULL; return memchr(keyboard_ids, id_byte, sizeof(keyboard_ids)) != NULL;
} }
EXPORT_SYMBOL(ps2_is_keyboard_id);
/* /*
* ps2_adjust_timeout() is called after receiving 1st byte of command * ps2_adjust_timeout() is called after receiving 1st byte of command
...@@ -138,6 +132,19 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout) ...@@ -138,6 +132,19 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout)
break; break;
case PS2_CMD_GETID: 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 * If device behind the port is not a keyboard there
* won't be 2nd byte of ID response. * won't be 2nd byte of ID response.
...@@ -237,6 +244,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) ...@@ -237,6 +244,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
mutex_unlock(&ps2dev->cmd_mutex); mutex_unlock(&ps2dev->cmd_mutex);
return rc; return rc;
} }
EXPORT_SYMBOL(ps2_command);
/* /*
* ps2_execute_scheduled_command() sends a command, previously scheduled by * ps2_execute_scheduled_command() sends a command, previously scheduled by
...@@ -279,6 +287,7 @@ int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int comman ...@@ -279,6 +287,7 @@ int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int comman
return 0; return 0;
} }
EXPORT_SYMBOL(ps2_schedule_command);
/* /*
* ps2_init() initializes ps2dev structure * ps2_init() initializes ps2dev structure
...@@ -290,6 +299,7 @@ void ps2_init(struct ps2dev *ps2dev, struct serio *serio) ...@@ -290,6 +299,7 @@ void ps2_init(struct ps2dev *ps2dev, struct serio *serio)
init_waitqueue_head(&ps2dev->wait); init_waitqueue_head(&ps2dev->wait);
ps2dev->serio = serio; ps2dev->serio = serio;
} }
EXPORT_SYMBOL(ps2_init);
/* /*
* ps2_handle_ack() is supposed to be used in interrupt handler * ps2_handle_ack() is supposed to be used in interrupt handler
...@@ -335,6 +345,7 @@ int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data) ...@@ -335,6 +345,7 @@ int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data)
return 1; return 1;
} }
EXPORT_SYMBOL(ps2_handle_ack);
/* /*
* ps2_handle_response() is supposed to be used in interrupt handler * ps2_handle_response() is supposed to be used in interrupt handler
...@@ -360,6 +371,7 @@ int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data) ...@@ -360,6 +371,7 @@ int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data)
return 1; return 1;
} }
EXPORT_SYMBOL(ps2_handle_response);
void ps2_cmd_aborted(struct ps2dev *ps2dev) void ps2_cmd_aborted(struct ps2dev *ps2dev)
{ {
...@@ -371,4 +383,4 @@ void ps2_cmd_aborted(struct ps2dev *ps2dev) ...@@ -371,4 +383,4 @@ void ps2_cmd_aborted(struct ps2dev *ps2dev)
ps2dev->flags = 0; ps2dev->flags = 0;
} }
EXPORT_SYMBOL(ps2_cmd_aborted);
...@@ -108,4 +108,40 @@ config TOUCHSCREEN_HP600 ...@@ -108,4 +108,40 @@ config TOUCHSCREEN_HP600
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called hp680_ts_input. 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.
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.
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 endif
...@@ -12,3 +12,6 @@ obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o ...@@ -12,3 +12,6 @@ obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o
obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.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
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/ctype.h>
#define DRIVER_DESC "Elo serial touchscreen driver" #define DRIVER_DESC "Elo serial touchscreen driver"
...@@ -36,6 +37,18 @@ MODULE_LICENSE("GPL"); ...@@ -36,6 +37,18 @@ MODULE_LICENSE("GPL");
#define ELO_MAX_LENGTH 10 #define ELO_MAX_LENGTH 10
#define ELO10_PACKET_LEN 8
#define ELO10_TOUCH 0x03
#define ELO10_PRESSURE 0x80
#define ELO10_LEAD_BYTE 'U'
#define ELO10_ID_CMD 'i'
#define ELO10_TOUCH_PACKET 'T'
#define ELO10_ACK_PACKET 'A'
#define ELI10_ID_PACKET 'I'
/* /*
* Per-touchscreen data. * Per-touchscreen data.
*/ */
...@@ -43,51 +56,67 @@ MODULE_LICENSE("GPL"); ...@@ -43,51 +56,67 @@ MODULE_LICENSE("GPL");
struct elo { struct elo {
struct input_dev *dev; struct input_dev *dev;
struct serio *serio; struct serio *serio;
struct mutex cmd_mutex;
struct completion cmd_done;
int id; int id;
int idx; int idx;
unsigned char expected_packet;
unsigned char csum; unsigned char csum;
unsigned char data[ELO_MAX_LENGTH]; unsigned char data[ELO_MAX_LENGTH];
unsigned char response[ELO10_PACKET_LEN];
char phys[32]; char phys[32];
}; };
static void elo_process_data_10(struct elo* elo, unsigned char data, struct pt_regs *regs) static void elo_process_data_10(struct elo *elo, unsigned char data, struct pt_regs *regs)
{ {
struct input_dev *dev = elo->dev; struct input_dev *dev = elo->dev;
elo->csum += elo->data[elo->idx] = data; elo->data[elo->idx] = data;
switch (elo->idx++) { switch (elo->idx++) {
case 0: case 0:
if (data != 'U') { elo->csum = 0xaa;
if (data != ELO10_LEAD_BYTE) {
pr_debug("elo: unsynchronized data: 0x%02x\n", data);
elo->idx = 0; elo->idx = 0;
elo->csum = 0;
} }
break; break;
case 1: case 9:
if (data != 'T') {
elo->idx = 0; elo->idx = 0;
elo->csum = 0; if (data != elo->csum) {
pr_debug("elo: bad checksum: 0x%02x, expected 0x%02x\n",
data, elo->csum);
break;
} }
if (elo->data[1] != elo->expected_packet) {
if (elo->data[1] != ELO10_TOUCH_PACKET)
pr_debug("elo: unexpected packet: 0x%02x\n",
elo->data[1]);
break; break;
}
case 9: if (likely(elo->data[1] == ELO10_TOUCH_PACKET)) {
if (elo->csum) {
input_regs(dev, regs); input_regs(dev, regs);
input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]); input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]);
input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]); input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]);
input_report_abs(dev, ABS_PRESSURE, (elo->data[8] << 8) | elo->data[7]); if (elo->data[2] & ELO10_PRESSURE)
input_report_key(dev, BTN_TOUCH, elo->data[8] || elo->data[7]); input_report_abs(dev, ABS_PRESSURE,
(elo->data[8] << 8) | elo->data[7]);
input_report_key(dev, BTN_TOUCH, elo->data[2] & ELO10_TOUCH);
input_sync(dev); input_sync(dev);
} else if (elo->data[1] == ELO10_ACK_PACKET) {
if (elo->data[2] == '0')
elo->expected_packet = ELO10_TOUCH_PACKET;
complete(&elo->cmd_done);
} else {
memcpy(elo->response, &elo->data[1], ELO10_PACKET_LEN);
elo->expected_packet = ELO10_ACK_PACKET;
} }
elo->idx = 0;
elo->csum = 0;
break; break;
} }
elo->csum += data;
} }
static void elo_process_data_6(struct elo* elo, unsigned char data, struct pt_regs *regs) static void elo_process_data_6(struct elo *elo, unsigned char data, struct pt_regs *regs)
{ {
struct input_dev *dev = elo->dev; struct input_dev *dev = elo->dev;
...@@ -135,7 +164,7 @@ static void elo_process_data_6(struct elo* elo, unsigned char data, struct pt_re ...@@ -135,7 +164,7 @@ static void elo_process_data_6(struct elo* elo, unsigned char data, struct pt_re
} }
} }
static void elo_process_data_3(struct elo* elo, unsigned char data, struct pt_regs *regs) static void elo_process_data_3(struct elo *elo, unsigned char data, struct pt_regs *regs)
{ {
struct input_dev *dev = elo->dev; struct input_dev *dev = elo->dev;
...@@ -161,7 +190,7 @@ static void elo_process_data_3(struct elo* elo, unsigned char data, struct pt_re ...@@ -161,7 +190,7 @@ static void elo_process_data_3(struct elo* elo, unsigned char data, struct pt_re
static irqreturn_t elo_interrupt(struct serio *serio, static irqreturn_t elo_interrupt(struct serio *serio,
unsigned char data, unsigned int flags, struct pt_regs *regs) unsigned char data, unsigned int flags, struct pt_regs *regs)
{ {
struct elo* elo = serio_get_drvdata(serio); struct elo *elo = serio_get_drvdata(serio);
switch(elo->id) { switch(elo->id) {
case 0: case 0:
...@@ -181,17 +210,81 @@ static irqreturn_t elo_interrupt(struct serio *serio, ...@@ -181,17 +210,81 @@ static irqreturn_t elo_interrupt(struct serio *serio,
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int elo_command_10(struct elo *elo, unsigned char *packet)
{
int rc = -1;
int i;
unsigned char csum = 0xaa + ELO10_LEAD_BYTE;
mutex_lock(&elo->cmd_mutex);
serio_pause_rx(elo->serio);
elo->expected_packet = toupper(packet[0]);
init_completion(&elo->cmd_done);
serio_continue_rx(elo->serio);
if (serio_write(elo->serio, ELO10_LEAD_BYTE))
goto out;
for (i = 0; i < ELO10_PACKET_LEN; i++) {
csum += packet[i];
if (serio_write(elo->serio, packet[i]))
goto out;
}
if (serio_write(elo->serio, csum))
goto out;
wait_for_completion_timeout(&elo->cmd_done, HZ);
if (elo->expected_packet == ELO10_TOUCH_PACKET) {
/* We are back in reporting mode, the command was ACKed */
memcpy(packet, elo->response, ELO10_PACKET_LEN);
rc = 0;
}
out:
mutex_unlock(&elo->cmd_mutex);
return rc;
}
static int elo_setup_10(struct elo *elo)
{
static const char *elo_types[] = { "Accu", "Dura", "Intelli", "Carroll" };
struct input_dev *dev = elo->dev;
unsigned char packet[ELO10_PACKET_LEN] = { ELO10_ID_CMD };
if (elo_command_10(elo, packet))
return -1;
dev->id.version = (packet[5] << 8) | packet[4];
input_set_abs_params(dev, ABS_X, 96, 4000, 0, 0);
input_set_abs_params(dev, ABS_Y, 96, 4000, 0, 0);
if (packet[3] & ELO10_PRESSURE)
input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
printk(KERN_INFO "elo: %sTouch touchscreen, fw: %02x.%02x, "
"features: %x02x, controller: 0x%02x\n",
elo_types[(packet[1] -'0') & 0x03],
packet[5], packet[4], packet[3], packet[7]);
return 0;
}
/* /*
* elo_disconnect() is the opposite of elo_connect() * elo_disconnect() is the opposite of elo_connect()
*/ */
static void elo_disconnect(struct serio *serio) static void elo_disconnect(struct serio *serio)
{ {
struct elo* elo = serio_get_drvdata(serio); struct elo *elo = serio_get_drvdata(serio);
input_get_device(elo->dev);
input_unregister_device(elo->dev); input_unregister_device(elo->dev);
serio_close(serio); serio_close(serio);
serio_set_drvdata(serio, NULL); serio_set_drvdata(serio, NULL);
input_put_device(elo->dev);
kfree(elo); kfree(elo);
} }
...@@ -211,12 +304,15 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv) ...@@ -211,12 +304,15 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
input_dev = input_allocate_device(); input_dev = input_allocate_device();
if (!elo || !input_dev) { if (!elo || !input_dev) {
err = -ENOMEM; err = -ENOMEM;
goto fail; goto fail1;
} }
elo->serio = serio; elo->serio = serio;
elo->id = serio->id.id; elo->id = serio->id.id;
elo->dev = input_dev; elo->dev = input_dev;
elo->expected_packet = ELO10_TOUCH_PACKET;
mutex_init(&elo->cmd_mutex);
init_completion(&elo->cmd_done);
snprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys); snprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys);
input_dev->private = elo; input_dev->private = elo;
...@@ -231,12 +327,17 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv) ...@@ -231,12 +327,17 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
serio_set_drvdata(serio, elo);
err = serio_open(serio, drv);
if (err)
goto fail2;
switch (elo->id) { switch (elo->id) {
case 0: /* 10-byte protocol */ case 0: /* 10-byte protocol */
input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0); if (elo_setup_10(elo))
input_set_abs_params(input_dev, ABS_Y, 96, 4000, 0, 0); goto fail3;
input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0);
break; break;
case 1: /* 6-byte protocol */ case 1: /* 6-byte protocol */
...@@ -253,17 +354,15 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv) ...@@ -253,17 +354,15 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
break; break;
} }
serio_set_drvdata(serio, elo); err = input_register_device(elo->dev);
err = serio_open(serio, drv);
if (err) if (err)
goto fail; goto fail3;
input_register_device(elo->dev);
return 0; return 0;
fail: serio_set_drvdata(serio, NULL); fail3: serio_close(serio);
input_free_device(input_dev); fail2: serio_set_drvdata(serio, NULL);
fail1: input_free_device(input_dev);
kfree(elo); kfree(elo);
return err; return err;
} }
......
/*
* Penmount serial touchscreen driver
*
* Copyright (c) 2006 Rick Koch <n1gp@hotmail.com>
*
* 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 <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/init.h>
#define DRIVER_DESC "Penmount serial touchscreen driver"
MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>");
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);
/*
* Touchright serial touchscreen driver
*
* Copyright (c) 2006 Rick Koch <n1gp@hotmail.com>
*
* Based on MicroTouch driver (drivers/input/touchscreen/mtouch.c)
* Copyright (c) 2004 Vojtech Pavlik
* and Dan Streetman <ddstreet@ieee.org>
*/
/*
* 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 <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/init.h>
#define DRIVER_DESC "Touchright serial touchscreen driver"
MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>");
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);
/*
* Touchwindow serial touchscreen driver
*
* Copyright (c) 2006 Rick Koch <n1gp@hotmail.com>
*
* Based on MicroTouch driver (drivers/input/touchscreen/mtouch.c)
* Copyright (c) 2004 Vojtech Pavlik
* and Dan Streetman <ddstreet@ieee.org>
*/
/*
* 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 <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/init.h>
#define DRIVER_DESC "Touchwindow serial touchscreen driver"
MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>");
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);
This diff is collapsed.
This diff is collapsed.
...@@ -15,7 +15,7 @@ ifeq ($(CONFIG_USB_HIDINPUT),y) ...@@ -15,7 +15,7 @@ ifeq ($(CONFIG_USB_HIDINPUT),y)
usbhid-objs += hid-input.o usbhid-objs += hid-input.o
endif endif
ifeq ($(CONFIG_HID_PID),y) ifeq ($(CONFIG_HID_PID),y)
usbhid-objs += pid.o usbhid-objs += hid-pidff.o
endif endif
ifeq ($(CONFIG_LOGITECH_FF),y) ifeq ($(CONFIG_LOGITECH_FF),y)
usbhid-objs += hid-lgff.o usbhid-objs += hid-lgff.o
...@@ -23,6 +23,9 @@ endif ...@@ -23,6 +23,9 @@ endif
ifeq ($(CONFIG_THRUSTMASTER_FF),y) ifeq ($(CONFIG_THRUSTMASTER_FF),y)
usbhid-objs += hid-tmff.o usbhid-objs += hid-tmff.o
endif endif
ifeq ($(CONFIG_ZEROPLUS_FF),y)
usbhid-objs += hid-zpff.o
endif
ifeq ($(CONFIG_HID_FF),y) ifeq ($(CONFIG_HID_FF),y)
usbhid-objs += hid-ff.o usbhid-objs += hid-ff.o
endif endif
......
...@@ -543,8 +543,6 @@ static void hid_free_device(struct hid_device *device) ...@@ -543,8 +543,6 @@ static void hid_free_device(struct hid_device *device)
{ {
unsigned i,j; unsigned i,j;
hid_ff_exit(device);
for (i = 0; i < HID_REPORT_TYPES; i++) { for (i = 0; i < HID_REPORT_TYPES; i++) {
struct hid_report_enum *report_enum = device->report_enum + i; struct hid_report_enum *report_enum = device->report_enum + i;
...@@ -1109,7 +1107,7 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value) ...@@ -1109,7 +1107,7 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
/* /*
* Find a report field with a specified HID usage. * Find a report field with a specified HID usage.
*/ */
#if 0
struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_usage, int type) struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_usage, int type)
{ {
struct hid_report *report; struct hid_report *report;
...@@ -1121,6 +1119,7 @@ struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_u ...@@ -1121,6 +1119,7 @@ struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_u
return report->field[i]; return report->field[i];
return NULL; return NULL;
} }
#endif /* 0 */
static int hid_submit_out(struct hid_device *hid) static int hid_submit_out(struct hid_device *hid)
{ {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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