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.
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
interactive.fig as well.
----------------------------------------------------------------------------
0. Introduction
1. Introduction
~~~~~~~~~~~~~~~
This document describes how to use force feedback devices under Linux. The
goal is not to support these devices as if they were simple input-only devices
(as it is already the case), but to really enable the rendering of force
effects.
At the moment, only I-Force devices are supported, and not officially. That
means I had to find out how the protocol works on my own. Of course, the
information I managed to grasp is far from being complete, and I can not
guarranty that this driver will work for you.
This document only describes the force feedback part of the driver for I-Force
devices. Please read joystick.txt before reading further this document.
This document only describes the force feedback part of the Linux input
interface. Please read joystick.txt and input.txt before reading further this
document.
2. Instructions to the user
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Here are instructions on how to compile and use the driver. In fact, this
driver is the normal iforce, input and evdev drivers written by Vojtech
Pavlik, plus additions to support force feedback.
To enable force feedback, you have to:
1. have your kernel configured with evdev and a driver that supports your
device.
2. make sure evdev module is loaded and /dev/input/event* device files are
created.
Before you start, let me WARN you that some devices shake violently during the
initialisation phase. This happens for example with my "AVB Top Shot Pegasus".
To stop this annoying behaviour, move you joystick to its limits. Anyway, you
should keep a hand on your device, in order to avoid it to brake down if
should keep a hand on your device, in order to avoid it to break down if
something goes wrong.
At the kernel's compilation:
- Enable IForce/Serial
- Enable Event interface
Compile the modules, install them.
You also need inputattach.
You then need to insert the modules into the following order:
% modprobe joydev
% modprobe serport # Only for serial
% modprobe iforce
% modprobe evdev
% ./inputattach -ifor $2 & # Only for serial
If you are using USB, you don't need the inputattach step.
Please check that you have all the /dev/input entries needed:
cd /dev
rm js*
mkdir input
mknod input/js0 c 13 0
mknod input/js1 c 13 1
mknod input/js2 c 13 2
mknod input/js3 c 13 3
ln -s input/js0 js0
ln -s input/js1 js1
ln -s input/js2 js2
ln -s input/js3 js3
mknod input/event0 c 13 64
mknod input/event1 c 13 65
mknod input/event2 c 13 66
mknod input/event3 c 13 67
If you have a serial iforce device, you need to start inputattach. See
joystick.txt for details.
2.1 Does it work ?
~~~~~~~~~~~~~~~~~~
......@@ -70,9 +40,9 @@ There is an utility called fftest that will allow you to test the driver.
3. Instructions to the developper
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
All interactions are done using the event API. That is, you can use ioctl()
All interactions are done using the event API. That is, you can use ioctl()
and write() on /dev/input/eventXX.
This information is subject to change.
This information is subject to change.
3.1 Querying device capabilities
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
......@@ -86,18 +56,29 @@ int ioctl(int file_descriptor, int request, unsigned long *features);
Returns the features supported by the device. features is a bitfield with the
following bits:
- FF_X has an X axis (usually joysticks)
- FF_Y has an Y axis (usually joysticks)
- FF_WHEEL has a wheel (usually sterring wheels)
- FF_CONSTANT can render constant force effects
- FF_PERIODIC can render periodic effects (sine, triangle, square...)
- FF_PERIODIC can render periodic effects with the following waveforms:
- FF_SQUARE square waveform
- FF_TRIANGLE triangle waveform
- FF_SINE sine waveform
- FF_SAW_UP sawtooth up waveform
- FF_SAW_DOWN sawtooth down waveform
- FF_CUSTOM custom waveform
- FF_RAMP can render ramp effects
- FF_SPRING can simulate the presence of a spring
- FF_FRICTION can simulate friction
- FF_DAMPER can simulate damper effects
- FF_RUMBLE rumble effects (normally the only effect supported by rumble
pads)
- FF_RUMBLE rumble effects
- FF_INERTIA can simulate inertia
- FF_GAIN gain is adjustable
- FF_AUTOCENTER autocenter is adjustable
Note: In most cases you should use FF_PERIODIC instead of FF_RUMBLE. All
devices that support FF_RUMBLE support FF_PERIODIC (square, triangle,
sine) and the other way around.
Note: The exact syntax FF_CUSTOM is undefined for the time being as no driver
supports it yet.
int ioctl(int fd, EVIOCGEFFECTS, int *n);
......@@ -120,6 +101,9 @@ to the unique id assigned by the driver. This data is required for performing
some operations (removing an effect, controlling the playback).
This if field must be set to -1 by the user in order to tell the driver to
allocate a new effect.
Effects are file descriptor specific.
See <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.
You need xfig to visualize these files.
......@@ -128,8 +112,8 @@ You need xfig to visualize these files.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int ioctl(int fd, EVIOCRMFF, effect.id);
This makes room for new effects in the device's memory. Please note this won't
stop the effect if it was playing.
This makes room for new effects in the device's memory. Note that this also
stops the effect if it was playing.
3.4 Controlling the playback of effects
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
......@@ -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
factor depending on how strong they want effects to be. This setting is
persistent across access to the driver, so you should not care about it if
you are writing games, as another utility probably already set this for you.
persistent across access to the driver.
/* Set the gain of the device
int gain; /* between 0 and 100 */
......@@ -204,11 +187,14 @@ type of device, not all parameters can be dynamically updated. For example,
the direction of an effect cannot be updated with iforce devices. In this
case, the driver stops the effect, up-load it, and restart it.
Therefore it is recommended to dynamically change direction while the effect
is playing only when it is ok to restart the effect with a replay count of 1.
3.8 Information about the status of effects
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Every time the status of an effect is changed, an event is sent. The values
and meanings of the fields of the event are as follows:
struct input_event {
/* When the status of the effect changed */
struct timeval time;
......@@ -225,3 +211,9 @@ struct input_event {
FF_STATUS_STOPPED The effect stopped playing
FF_STATUS_PLAYING The effect started to play
NOTE: Status feedback is only supported by iforce driver. If you have
a really good reason to use this, please contact
linux-joystick@atrey.karlin.mff.cuni.cz or anssi.hannula@gmail.com
so that support for it can be added to the rest of the drivers.
......@@ -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,
struct input_dev *dev,
struct input_device_id *id)
const struct input_device_id *id)
{
struct input_handle *handle;
int i;
......@@ -1342,7 +1342,7 @@ static void kbd_start(struct input_handle *handle)
tasklet_enable(&keyboard_tasklet);
}
static struct input_device_id kbd_ids[] = {
static const struct input_device_id kbd_ids[] = {
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
.evbit = { BIT(EV_KEY) },
......@@ -1370,6 +1370,7 @@ static struct input_handler kbd_handler = {
int __init kbd_init(void)
{
int i;
int error;
for (i = 0; i < MAX_NR_CONSOLES; i++) {
kbd_table[i].ledflagstate = KBD_DEFLEDS;
......@@ -1381,7 +1382,9 @@ int __init kbd_init(void)
kbd_table[i].kbdmode = VC_XLATE;
}
input_register_handler(&kbd_handler);
error = input_register_handler(&kbd_handler);
if (error)
return error;
tasklet_enable(&keyboard_tasklet);
tasklet_schedule(&keyboard_tasklet);
......
......@@ -24,6 +24,20 @@ config INPUT
if INPUT
config INPUT_FF_MEMLESS
tristate "Support for memoryless force-feedback devices"
default n
---help---
Say Y here if you have memoryless force-feedback input device
such as Logitech WingMan Force 3D, ThrustMaster FireStorm Dual
Power 2, or similar. You will also need to enable hardware-specific
driver.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called ff-memless.
comment "Userland interfaces"
config INPUT_MOUSEDEV
......
......@@ -4,7 +4,11 @@
# 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_JOYDEV) += joydev.o
obj-$(CONFIG_INPUT_EVDEV) += evdev.o
......
......@@ -42,10 +42,12 @@ static char evbug_name[] = "evbug";
static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", handle->dev->phys, type, code, value);
printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n",
handle->dev->phys, type, code, value);
}
static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev,
const struct input_device_id *id)
{
struct input_handle *handle;
......@@ -72,7 +74,7 @@ static void evbug_disconnect(struct input_handle *handle)
kfree(handle);
}
static struct input_device_id evbug_ids[] = {
static const struct input_device_id evbug_ids[] = {
{ .driver_info = 1 }, /* Matches all devices */
{ }, /* Terminating zero entry */
};
......@@ -89,8 +91,7 @@ static struct input_handler evbug_handler = {
static int __init evbug_init(void)
{
input_register_handler(&evbug_handler);
return 0;
return input_register_handler(&evbug_handler);
}
static void __exit evbug_exit(void)
......
......@@ -391,8 +391,10 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
struct evdev *evdev = list->evdev;
struct input_dev *dev = evdev->handle.dev;
struct input_absinfo abs;
struct ff_effect effect;
int __user *ip = (int __user *)p;
int i, t, u, v;
int error;
if (!evdev->exist)
return -ENODEV;
......@@ -460,27 +462,22 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
return 0;
case EVIOCSFF:
if (dev->upload_effect) {
struct ff_effect effect;
int err;
if (copy_from_user(&effect, p, sizeof(effect)))
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)))
return -EFAULT;
return err;
} else
return -ENOSYS;
case EVIOCRMFF:
if (!dev->erase_effect)
return -ENOSYS;
return error;
return dev->erase_effect(dev, (int)(unsigned long) p);
case EVIOCRMFF:
return input_ff_erase(dev, (int)(unsigned long) p, file);
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 0;
......@@ -604,7 +601,7 @@ static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned lon
}
#endif
static struct file_operations evdev_fops = {
static const struct file_operations evdev_fops = {
.owner = THIS_MODULE,
.read = evdev_read,
.write = evdev_write,
......@@ -619,7 +616,8 @@ static struct file_operations evdev_fops = {
.flush = evdev_flush
};
static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev,
const struct input_device_id *id)
{
struct evdev *evdev;
struct class_device *cdev;
......@@ -669,6 +667,7 @@ static void evdev_disconnect(struct input_handle *handle)
evdev->exist = 0;
if (evdev->open) {
input_flush_device(handle, NULL);
input_close_device(handle);
wake_up_interruptible(&evdev->wait);
list_for_each_entry(list, &evdev->list, node)
......@@ -677,7 +676,7 @@ static void evdev_disconnect(struct input_handle *handle)
evdev_free(evdev);
}
static struct input_device_id evdev_ids[] = {
static const struct input_device_id evdev_ids[] = {
{ .driver_info = 1 }, /* Matches all devices */
{ }, /* Terminating zero entry */
};
......@@ -696,8 +695,7 @@ static struct input_handler evdev_handler = {
static int __init evdev_init(void)
{
input_register_handler(&evdev_handler);
return 0;
return input_register_handler(&evdev_handler);
}
static void __exit evdev_exit(void)
......
/*
* 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
break;
case EV_FF:
if (value < 0)
return;
if (dev->event)
dev->event(dev, type, code, value);
break;
......@@ -309,7 +313,8 @@ static void input_link_handle(struct input_handle *handle)
if (i != NBITS(max)) \
continue;
static struct input_device_id *input_match_device(struct input_device_id *id, struct input_dev *dev)
static const struct input_device_id *input_match_device(const struct input_device_id *id,
struct input_dev *dev)
{
int i;
......@@ -762,7 +767,9 @@ static void input_dev_release(struct class_device *class_dev)
{
struct input_dev *dev = to_input_dev(class_dev);
input_ff_destroy(dev);
kfree(dev);
module_put(THIS_MODULE);
}
......@@ -899,12 +906,13 @@ struct input_dev *input_allocate_device(void)
dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);
if (dev) {
dev->dynalloc = 1;
dev->cdev.class = &input_class;
class_device_initialize(&dev->cdev);
mutex_init(&dev->mutex);
INIT_LIST_HEAD(&dev->h_list);
INIT_LIST_HEAD(&dev->node);
__module_get(THIS_MODULE);
}
return dev;
......@@ -929,17 +937,10 @@ int input_register_device(struct input_dev *dev)
static atomic_t input_no = ATOMIC_INIT(0);
struct input_handle *handle;
struct input_handler *handler;
struct input_device_id *id;
const struct input_device_id *id;
const char *path;
int error;
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);
/*
......@@ -955,10 +956,8 @@ int input_register_device(struct input_dev *dev)
dev->rep[REP_PERIOD] = 33;
}
INIT_LIST_HEAD(&dev->h_list);
list_add_tail(&dev->node, &input_dev_list);
dev->cdev.class = &input_class;
snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id),
"input%ld", (unsigned long) atomic_inc_return(&input_no) - 1);
......@@ -978,8 +977,6 @@ int input_register_device(struct input_dev *dev)
if (error)
goto fail3;
__module_get(THIS_MODULE);
path = kobject_get_path(&dev->cdev.kobj, GFP_KERNEL);
printk(KERN_INFO "input: %s as %s\n",
dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
......@@ -1008,9 +1005,12 @@ EXPORT_SYMBOL(input_register_device);
void input_unregister_device(struct input_dev *dev)
{
struct list_head *node, *next;
int code;
if (!dev)
return;
for (code = 0; code <= KEY_MAX; code++)
if (test_bit(code, dev->key))
input_report_key(dev, code, 0);
input_sync(dev);
del_timer_sync(&dev->timer);
......@@ -1037,19 +1037,20 @@ void input_unregister_device(struct input_dev *dev)
}
EXPORT_SYMBOL(input_unregister_device);
void input_register_handler(struct input_handler *handler)
int input_register_handler(struct input_handler *handler)
{
struct input_dev *dev;
struct input_handle *handle;
struct input_device_id *id;
if (!handler)
return;
const struct input_device_id *id;
INIT_LIST_HEAD(&handler->h_list);
if (handler->fops != NULL)
if (handler->fops != NULL) {
if (input_table[handler->minor >> 5])
return -EBUSY;
input_table[handler->minor >> 5] = handler;
}
list_add_tail(&handler->node, &input_handler_list);
......@@ -1063,6 +1064,7 @@ void input_register_handler(struct input_handler *handler)
}
input_wakeup_procfs_readers();
return 0;
}
EXPORT_SYMBOL(input_register_handler);
......
......@@ -451,7 +451,7 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
}
}
static struct file_operations joydev_fops = {
static const struct file_operations joydev_fops = {
.owner = THIS_MODULE,
.read = joydev_read,
.write = joydev_write,
......@@ -465,7 +465,8 @@ static struct file_operations joydev_fops = {
.fasync = joydev_fasync,
};
static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev,
const struct input_device_id *id)
{
struct joydev *joydev;
struct class_device *cdev;
......@@ -562,7 +563,7 @@ static void joydev_disconnect(struct input_handle *handle)
joydev_free(joydev);
}
static struct input_device_id joydev_blacklist[] = {
static const struct input_device_id joydev_blacklist[] = {
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
.evbit = { BIT(EV_KEY) },
......@@ -571,7 +572,7 @@ static struct input_device_id joydev_blacklist[] = {
{ } /* Terminating entry */
};
static struct input_device_id joydev_ids[] = {
static const struct input_device_id joydev_ids[] = {
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
.evbit = { BIT(EV_ABS) },
......@@ -605,8 +606,7 @@ static struct input_handler joydev_handler = {
static int __init joydev_init(void)
{
input_register_handler(&joydev_handler);
return 0;
return input_register_handler(&joydev_handler);
}
static void __exit joydev_exit(void)
......
This diff is collapsed.
......@@ -83,103 +83,57 @@ static struct iforce_device iforce_device[] = {
{ 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce }
};
static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
static int iforce_playback(struct input_dev *dev, int effect_id, int value)
{
struct iforce* iforce = dev->private;
unsigned char data[3];
struct iforce_core_effect *core_effect = &iforce->core_effects[effect_id];
if (type != EV_FF)
return -1;
if (value > 0)
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);
}
return 0;
case FF_AUTOCENTER:
static void iforce_set_autocenter(struct input_dev *dev, u16 magnitude)
{
struct iforce* iforce = dev->private;
unsigned char data[3];
data[0] = 0x03;
data[1] = value >> 9;
data[1] = magnitude >> 9;
iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data);
data[0] = 0x04;
data[1] = 0x01;
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.
* 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;
int id;
struct iforce_core_effect *core_effect = &iforce->core_effects[effect->id];
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 */
if (test_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags))
if (test_bit(FF_CORE_UPDATE, core_effect->flags))
return -EAGAIN;
is_update = TRUE;
}
/*
......@@ -188,28 +142,28 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect)
switch (effect->type) {
case FF_PERIODIC:
ret = iforce_upload_periodic(iforce, effect, is_update);
ret = iforce_upload_periodic(iforce, effect, old);
break;
case FF_CONSTANT:
ret = iforce_upload_constant(iforce, effect, is_update);
ret = iforce_upload_constant(iforce, effect, old);
break;
case FF_SPRING:
case FF_DAMPER:
ret = iforce_upload_condition(iforce, effect, is_update);
ret = iforce_upload_condition(iforce, effect, old);
break;
default:
return -EINVAL;
}
if (ret == 0) {
/* A packet was sent, forbid new updates until we are notified
* 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;
}
......@@ -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)
{
struct iforce* iforce = dev->private;
struct iforce *iforce = dev->private;
struct iforce_core_effect *core_effect = &iforce->core_effects[effect_id];
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))
err = release_resource(&core_effect->mod1_chunk);
......@@ -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))
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;
return err;
......@@ -260,33 +203,11 @@ static int iforce_open(struct input_dev *dev)
#endif
}
if (test_bit(EV_FF, dev->evbit)) {
/* Enable force feedback */
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;
}
......@@ -295,17 +216,18 @@ static void iforce_release(struct input_dev *dev)
struct iforce *iforce = dev->private;
int i;
/* Check: no effect should be present in memory */
for (i=0; i<dev->ff_effects_max; ++i) {
if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags))
if (test_bit(EV_FF, dev->evbit)) {
/* Check: no effects should be present in memory */
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;
}
if (i<dev->ff_effects_max) {
printk(KERN_WARNING "iforce_release: Device still owns effects\n");
}
/* Disable force feedback playback */
iforce_send_packet(iforce, FF_CMD_ENABLE, "\001");
}
switch (iforce->bus) {
#ifdef CONFIG_JOYSTICK_IFORCE_USB
......@@ -342,8 +264,10 @@ void iforce_delete_device(struct iforce *iforce)
int iforce_init_device(struct iforce *iforce)
{
struct input_dev *input_dev;
struct ff_device *ff;
unsigned char c[] = "CEOV";
int i;
int i, error;
int ff_effects = 0;
input_dev = input_allocate_device();
if (!input_dev)
......@@ -378,11 +302,6 @@ int iforce_init_device(struct iforce *iforce)
input_dev->name = "Unknown I-Force device";
input_dev->open = iforce_open;
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.
......@@ -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");
if (!iforce_get_id_packet(iforce, "N"))
iforce->dev->ff_effects_max = iforce->edata[1];
ff_effects = iforce->edata[1];
else
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 */
if (iforce->dev->ff_effects_max > FF_EFFECTS_MAX) {
printk(KERN_WARNING "input??: Device can handle %d effects, but N_EFFECTS_MAX is set to %d in iforce.h\n",
iforce->dev->ff_effects_max, FF_EFFECTS_MAX);
iforce->dev->ff_effects_max = FF_EFFECTS_MAX;
if (ff_effects > IFORCE_EFFECTS_MAX) {
printk(KERN_WARNING "iforce: Limiting number of effects to %d (device reports %d)\n",
IFORCE_EFFECTS_MAX, ff_effects);
ff_effects = IFORCE_EFFECTS_MAX;
}
/*
......@@ -472,12 +391,10 @@ int iforce_init_device(struct iforce *iforce)
* 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++) {
signed short t = iforce->type->btn[i];
set_bit(t, input_dev->keybit);
}
for (i = 0; iforce->type->btn[i] >= 0; i++)
set_bit(iforce->type->btn[i], input_dev->keybit);
set_bit(BTN_DEAD, input_dev->keybit);
for (i = 0; iforce->type->abs[i] >= 0; i++) {
......@@ -516,9 +433,24 @@ int iforce_init_device(struct iforce *iforce)
}
}
if (ff_effects) {
for (i = 0; iforce->type->ff[i] >= 0; i++)
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.
*/
......
......@@ -140,7 +140,10 @@ static int mark_core_as_ready(struct iforce *iforce, unsigned short addr)
{
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) &&
(iforce->core_effects[i].mod1_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,
/* Report play event */
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 */
input_report_ff_status(dev, i, FF_STATUS_STOPPED);
}
if (LO(cmd) > 3) {
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));
}
}
break;
}
being_used--;
......
......@@ -51,10 +51,7 @@
#define IFORCE_232 1
#define IFORCE_USB 2
#define FALSE 0
#define TRUE 1
#define FF_EFFECTS_MAX 32
#define IFORCE_EFFECTS_MAX 32
/* Each force feedback effect is made of one core effect, which can be
* associated to at most to effect modifiers
......@@ -67,24 +64,11 @@
#define FF_CORE_UPDATE 5 /* Effect is being updated */
#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 {
/* Information about where modifiers are stored in the device's memory */
struct resource mod1_chunk;
struct resource mod2_chunk;
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
......@@ -145,7 +129,7 @@ struct iforce {
/* Force Feedback */
wait_queue_head_t wait;
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;
};
......@@ -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);
/* iforce-ff.c */
int iforce_upload_periodic(struct iforce*, struct ff_effect*, int is_update);
int iforce_upload_constant(struct iforce*, struct ff_effect*, int is_update);
int iforce_upload_condition(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 *, struct ff_effect *);
int iforce_upload_condition(struct iforce *, struct ff_effect *, struct ff_effect *);
/* Public variables */
extern struct serio_driver iforce_serio_drv;
......
......@@ -121,6 +121,17 @@ config KEYBOARD_NEWTON
To compile this driver as a module, choose M here: the
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
tristate "Corgi keyboard"
depends on PXA_SHARPSL
......
......@@ -11,6 +11,7 @@ obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o
obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o
obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
......
......@@ -652,9 +652,7 @@ static int atkbd_probe(struct atkbd *atkbd)
return 0;
}
if (param[0] != 0xab && param[0] != 0xac && /* Regular and NCD Sun keyboards */
param[0] != 0x2b && param[0] != 0x5d && /* Trust keyboard, raw and translated */
param[0] != 0x60 && param[0] != 0x47) /* NMB SGI keyboard, raw and translated */
if (!ps2_is_keyboard_id(param[0]))
return -1;
atkbd->id = (param[0] << 8) | param[1];
......
/*
* 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 @@
* Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
*
* 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>)
* - added force feedback support
* - added UI_SET_PHYS
......@@ -107,18 +110,31 @@ static int uinput_request_submit(struct input_dev *dev, struct uinput_request *r
return request->retval;
}
static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect)
static void uinput_dev_set_gain(struct input_dev *dev, u16 gain)
{
uinput_dev_event(dev, EV_FF, FF_GAIN, gain);
}
static void uinput_dev_set_autocenter(struct input_dev *dev, u16 magnitude)
{
uinput_dev_event(dev, EV_FF, FF_AUTOCENTER, magnitude);
}
static int uinput_dev_playback(struct input_dev *dev, int effect_id, int value)
{
return uinput_dev_event(dev, EV_FF, effect_id, value);
}
static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old)
{
struct uinput_request request;
int retval;
if (!test_bit(EV_FF, dev->evbit))
return -ENOSYS;
request.id = -1;
init_completion(&request.done);
request.code = UI_FF_UPLOAD;
request.u.effect = effect;
request.u.upload.effect = effect;
request.u.upload.old = old;
retval = uinput_request_reserve_slot(dev->private, &request);
if (!retval)
......@@ -168,6 +184,7 @@ static void uinput_destroy_device(struct uinput_device *udev)
static int uinput_create_device(struct uinput_device *udev)
{
struct input_dev *dev = udev->dev;
int error;
if (udev->state != UIST_SETUP_COMPLETE) {
......@@ -175,15 +192,29 @@ static int uinput_create_device(struct uinput_device *udev)
return -EINVAL;
}
error = input_register_device(udev->dev);
if (error) {
uinput_destroy_device(udev);
return error;
if (udev->ff_effects_max) {
error = input_ff_create(dev, udev->ff_effects_max);
if (error)
goto fail1;
dev->ff->upload = uinput_dev_upload_effect;
dev->ff->erase = uinput_dev_erase_effect;
dev->ff->playback = uinput_dev_playback;
dev->ff->set_gain = uinput_dev_set_gain;
dev->ff->set_autocenter = uinput_dev_set_autocenter;
}
error = input_register_device(udev->dev);
if (error)
goto fail2;
udev->state = UIST_CREATED;
return 0;
fail2: input_ff_destroy(dev);
fail1: uinput_destroy_device(udev);
return error;
}
static int uinput_open(struct inode *inode, struct file *file)
......@@ -243,8 +274,6 @@ static int uinput_allocate_device(struct uinput_device *udev)
return -ENOMEM;
udev->dev->event = uinput_dev_event;
udev->dev->upload_effect = uinput_dev_upload_effect;
udev->dev->erase_effect = uinput_dev_erase_effect;
udev->dev->private = udev;
return 0;
......@@ -278,6 +307,8 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu
goto exit;
}
udev->ff_effects_max = user_dev->ff_effects_max;
size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1;
if (!size) {
retval = -EINVAL;
......@@ -296,7 +327,6 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu
dev->id.vendor = user_dev->id.vendor;
dev->id.product = user_dev->id.product;
dev->id.version = user_dev->id.version;
dev->ff_effects_max = user_dev->ff_effects_max;
size = sizeof(int) * (ABS_MAX + 1);
memcpy(dev->absmax, user_dev->absmax, size);
......@@ -525,12 +555,17 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
}
req = uinput_request_find(udev, ff_up.request_id);
if (!(req && req->code == UI_FF_UPLOAD && req->u.effect)) {
if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) {
retval = -EINVAL;
break;
}
ff_up.retval = 0;
memcpy(&ff_up.effect, req->u.effect, sizeof(struct ff_effect));
memcpy(&ff_up.effect, req->u.upload.effect, sizeof(struct ff_effect));
if (req->u.upload.old)
memcpy(&ff_up.old, req->u.upload.old, sizeof(struct ff_effect));
else
memset(&ff_up.old, 0, sizeof(struct ff_effect));
if (copy_to_user(p, &ff_up, sizeof(ff_up))) {
retval = -EFAULT;
break;
......@@ -561,12 +596,11 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
}
req = uinput_request_find(udev, ff_up.request_id);
if (!(req && req->code == UI_FF_UPLOAD && req->u.effect)) {
if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) {
retval = -EINVAL;
break;
}
req->retval = ff_up.retval;
memcpy(req->u.effect, &ff_up.effect, sizeof(struct ff_effect));
uinput_request_done(udev, req);
break;
......@@ -622,6 +656,7 @@ static void __exit uinput_exit(void)
MODULE_AUTHOR("Aristeu Sergio Rozanski Filho");
MODULE_DESCRIPTION("User level driver support for input subsystem");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.3");
module_init(uinput_init);
module_exit(uinput_exit);
......
......@@ -248,13 +248,10 @@ static int __init dmi_matched(struct dmi_system_id *dmi)
keymap = dmi->driver_data;
for (key = keymap; key->type != KE_END; key++) {
if (key->type == KE_WIFI) {
if (key->type == KE_WIFI)
have_wifi = 1;
break;
} else if (key->type == KE_BLUETOOTH) {
else if (key->type == KE_BLUETOOTH)
have_bluetooth = 1;
break;
}
}
return 1;
}
......@@ -389,6 +386,15 @@ static struct dmi_system_id dmi_ids[] __initdata = {
},
.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,
.ident = "AOpen 1559AS",
......
......@@ -36,7 +36,7 @@
#define ALPS_PASS 0x20
#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 */
{ { 0x53, 0x02, 0x0a }, 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 *
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;
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];
int i;
......@@ -504,7 +504,7 @@ int alps_init(struct psmouse *psmouse)
int alps_detect(struct psmouse *psmouse, int set_properties)
{
int version;
struct alps_model_info *model;
const struct alps_model_info *model;
if (!(model = alps_get_model(psmouse, &version)))
return -1;
......
......@@ -25,7 +25,7 @@ struct alps_data {
struct input_dev *dev2; /* Relative device */
char name[32]; /* Name */
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 */
};
......
......@@ -115,13 +115,15 @@ static int lifebook_absolute_mode(struct psmouse *psmouse)
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)
resolution = 400;
ps2_command(&psmouse->ps2dev, &params[resolution / 100], PSMOUSE_CMD_SETRES);
psmouse->resolution = 50 << params[resolution / 100];
p = params[resolution / 100];
ps2_command(&psmouse->ps2dev, &p, PSMOUSE_CMD_SETRES);
psmouse->resolution = 50 << p;
}
static void lifebook_disconnect(struct psmouse *psmouse)
......
......@@ -30,9 +30,9 @@
#define PS2PP_NAV_BTN 0x20
struct ps2pp_info {
const int model;
unsigned const int kind;
unsigned const int features;
u8 model;
u8 kind;
u16 features;
};
/*
......@@ -199,9 +199,9 @@ static void ps2pp_disconnect(struct psmouse *psmouse)
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},
{ 13, 0, 0 },
{ 15, PS2PP_KIND_MX, /* MX1000 */
......@@ -215,6 +215,7 @@ static struct ps2pp_info *get_model_info(unsigned char model)
{ 51, 0, 0 },
{ 52, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | 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 */
PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
......@@ -244,12 +245,11 @@ static struct ps2pp_info *get_model_info(unsigned char model)
PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
{ 114, PS2PP_KIND_MX, /* MX310 */
PS2PP_WHEEL | PS2PP_SIDE_BTN |
PS2PP_TASK_BTN | PS2PP_EXTRA_BTN },
{ }
PS2PP_TASK_BTN | PS2PP_EXTRA_BTN }
};
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)
return &ps2pp_list[i];
......@@ -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.
*/
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)
{
struct input_dev *input_dev = psmouse->dev;
......@@ -327,7 +328,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4];
unsigned char model, buttons;
struct ps2pp_info *model_info;
const struct ps2pp_info *model_info;
int use_ps2pp = 0;
param[0] = 0;
......@@ -349,7 +350,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
/*
* Do Logitech PS2++ / PS2T++ magic init.
*/
if (model == 97) { /* Touch Pad 3 */
if (model_info->kind == PS2PP_KIND_TP3) { /* Touch Pad 3 */
/* Unprotect RAM */
param[0] = 0x11; param[1] = 0x04; param[2] = 0x68;
......
......@@ -112,8 +112,8 @@ static struct workqueue_struct *kpsmoused_wq;
struct psmouse_protocol {
enum psmouse_type type;
char *name;
char *alias;
const char *name;
const char *alias;
int maxproto;
int (*detect)(struct psmouse *, int);
int (*init)(struct psmouse *);
......@@ -507,15 +507,17 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
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;
param[0] = 10;
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
param[0] = 0;
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
for (i = 0; seq[i]; i++)
ps2_command(ps2dev, seq + i, PSMOUSE_CMD_SETRATE);
for (i = 0; i < ARRAY_SIZE(seq); i++) {
param[0] = seq[i];
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
}
ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
if (param[0] != 2)
......@@ -652,7 +654,7 @@ static int psmouse_extensions(struct psmouse *psmouse,
return PSMOUSE_PS2;
}
static struct psmouse_protocol psmouse_protocols[] = {
static const struct psmouse_protocol psmouse_protocols[] = {
{
.type = PSMOUSE_PS2,
.name = "PS/2",
......@@ -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;
......@@ -738,9 +740,9 @@ static struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type)
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;
for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++) {
......@@ -795,13 +797,15 @@ static int psmouse_probe(struct psmouse *psmouse)
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)
resolution = 200;
ps2_command(&psmouse->ps2dev, &params[resolution / 50], PSMOUSE_CMD_SETRES);
psmouse->resolution = 25 << params[resolution / 50];
p = 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)
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;
while (rates[i] > rate) i++;
ps2_command(&psmouse->ps2dev, &rates[i], PSMOUSE_CMD_SETRATE);
psmouse->rate = rates[i];
r = rates[i];
ps2_command(&psmouse->ps2dev, &r, PSMOUSE_CMD_SETRATE);
psmouse->rate = r;
}
/*
......@@ -1031,7 +1037,7 @@ static void psmouse_disconnect(struct serio *serio)
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;
......@@ -1362,7 +1368,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co
struct serio *serio = psmouse->ps2dev.serio;
struct psmouse *parent = NULL;
struct input_dev *new_dev;
struct psmouse_protocol *proto;
const struct psmouse_protocol *proto;
int retry = 0;
if (!(proto = psmouse_protocol_by_name(buf, count)))
......@@ -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)
{
struct psmouse_protocol *proto;
const struct psmouse_protocol *proto;
if (!val)
return -EINVAL;
......
......@@ -42,7 +42,7 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION(DRIVER_DESC);
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 MZ++ Mouse"};
......
......@@ -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 unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 };
static unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 };
static unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 };
static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
static const unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 };
static const unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 };
static const unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 };
static const unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
static const unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
if (idx < 0 || idx > 4)
return 0;
......
......@@ -614,7 +614,7 @@ static unsigned int mousedev_poll(struct file *file, poll_table *wait)
(list->mousedev->exist ? 0 : (POLLHUP | POLLERR));
}
static struct file_operations mousedev_fops = {
static const struct file_operations mousedev_fops = {
.owner = THIS_MODULE,
.read = mousedev_read,
.write = mousedev_write,
......@@ -624,7 +624,8 @@ static struct file_operations mousedev_fops = {
.fasync = mousedev_fasync,
};
static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev,
const struct input_device_id *id)
{
struct mousedev *mousedev;
struct class_device *cdev;
......@@ -688,7 +689,7 @@ static void mousedev_disconnect(struct input_handle *handle)
}
}
static struct input_device_id mousedev_ids[] = {
static const struct input_device_id mousedev_ids[] = {
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
.evbit = { BIT(EV_KEY) | BIT(EV_REL) },
......@@ -737,7 +738,12 @@ static int psaux_registered;
static int __init mousedev_init(void)
{
input_register_handler(&mousedev_handler);
struct class_device *cdev;
int error;
error = input_register_handler(&mousedev_handler);
if (error)
return error;
memset(&mousedev_mix, 0, sizeof(struct mousedev));
INIT_LIST_HEAD(&mousedev_mix.list);
......@@ -746,12 +752,20 @@ static int __init mousedev_init(void)
mousedev_mix.exist = 1;
mousedev_mix.minor = MOUSEDEV_MIX;
class_device_create(&input_class, NULL,
cdev = class_device_create(&input_class, NULL,
MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), NULL, "mice");
if (IS_ERR(cdev)) {
input_unregister_handler(&mousedev_handler);
return PTR_ERR(cdev);
}
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
if (!(psaux_registered = !misc_register(&psaux_mouse)))
printk(KERN_WARNING "mice: could not misc_register the device\n");
error = misc_register(&psaux_mouse);
if (error)
printk(KERN_WARNING "mice: could not register psaux device, "
"error: %d\n", error);
else
psaux_registered = 1;
#endif
printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n");
......
......@@ -98,7 +98,7 @@ static void power_event(struct input_handle *handle, unsigned int type,
static struct input_handle *power_connect(struct input_handler *handler,
struct input_dev *dev,
struct input_device_id *id)
const struct input_device_id *id)
{
struct input_handle *handle;
......@@ -120,7 +120,7 @@ static void power_disconnect(struct input_handle *handle)
kfree(handle);
}
static struct input_device_id power_ids[] = {
static const struct input_device_id power_ids[] = {
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
.evbit = { BIT(EV_KEY) },
......@@ -150,8 +150,7 @@ static struct input_handler power_handler = {
static int __init power_init(void)
{
input_register_handler(&power_handler);
return 0;
return input_register_handler(&power_handler);
}
static void __exit power_exit(void)
......
......@@ -159,6 +159,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
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",
.matches = {
......@@ -180,6 +187,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
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 @@
#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.
*/
......
......@@ -27,15 +27,6 @@ MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
MODULE_DESCRIPTION("PS/2 driver library");
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 */
struct ps2work {
struct work_struct work;
......@@ -71,6 +62,7 @@ int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
return -ps2dev->nak;
}
EXPORT_SYMBOL(ps2_sendbyte);
/*
* 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)
msecs_to_jiffies(timeout));
mutex_unlock(&ps2dev->cmd_mutex);
}
EXPORT_SYMBOL(ps2_drain);
/*
* ps2_is_keyboard_id() checks received ID byte against the list of
* known keyboard IDs.
*/
static inline int ps2_is_keyboard_id(char id_byte)
int ps2_is_keyboard_id(char id_byte)
{
static char keyboard_ids[] = {
const static char keyboard_ids[] = {
0xab, /* Regular keyboards */
0xac, /* NCD Sun keyboard */
0x2b, /* Trust keyboard, translated */
......@@ -115,6 +108,7 @@ static inline int ps2_is_keyboard_id(char id_byte)
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
......@@ -138,6 +132,19 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout)
break;
case PS2_CMD_GETID:
/*
* Microsoft Natural Elite keyboard responds to
* the GET ID command as it were a mouse, with
* a single byte. Fail the command so atkbd will
* use alternative probe to detect it.
*/
if (ps2dev->cmdbuf[1] == 0xaa) {
serio_pause_rx(ps2dev->serio);
ps2dev->flags = 0;
serio_continue_rx(ps2dev->serio);
timeout = 0;
}
/*
* If device behind the port is not a keyboard there
* won't be 2nd byte of ID response.
......@@ -237,6 +244,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
mutex_unlock(&ps2dev->cmd_mutex);
return rc;
}
EXPORT_SYMBOL(ps2_command);
/*
* 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
return 0;
}
EXPORT_SYMBOL(ps2_schedule_command);
/*
* ps2_init() initializes ps2dev structure
......@@ -290,6 +299,7 @@ void ps2_init(struct ps2dev *ps2dev, struct serio *serio)
init_waitqueue_head(&ps2dev->wait);
ps2dev->serio = serio;
}
EXPORT_SYMBOL(ps2_init);
/*
* 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)
return 1;
}
EXPORT_SYMBOL(ps2_handle_ack);
/*
* 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)
return 1;
}
EXPORT_SYMBOL(ps2_handle_response);
void ps2_cmd_aborted(struct ps2dev *ps2dev)
{
......@@ -371,4 +383,4 @@ void ps2_cmd_aborted(struct ps2dev *ps2dev)
ps2dev->flags = 0;
}
EXPORT_SYMBOL(ps2_cmd_aborted);
......@@ -108,4 +108,40 @@ config TOUCHSCREEN_HP600
To compile this driver as a module, choose M here: the
module will be called hp680_ts_input.
config TOUCHSCREEN_PENMOUNT
tristate "Penmount serial touchscreen"
select SERIO
help
Say Y here if you have a Penmount serial touchscreen connected to
your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called penmount.
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
......@@ -12,3 +12,6 @@ obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o
obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
......@@ -23,6 +23,7 @@
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/init.h>
#include <linux/ctype.h>
#define DRIVER_DESC "Elo serial touchscreen driver"
......@@ -36,6 +37,18 @@ MODULE_LICENSE("GPL");
#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.
*/
......@@ -43,51 +56,67 @@ MODULE_LICENSE("GPL");
struct elo {
struct input_dev *dev;
struct serio *serio;
struct mutex cmd_mutex;
struct completion cmd_done;
int id;
int idx;
unsigned char expected_packet;
unsigned char csum;
unsigned char data[ELO_MAX_LENGTH];
unsigned char response[ELO10_PACKET_LEN];
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;
elo->csum += elo->data[elo->idx] = data;
elo->data[elo->idx] = data;
switch (elo->idx++) {
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->csum = 0;
}
break;
case 1:
if (data != 'T') {
case 9:
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;
case 9:
if (elo->csum) {
}
if (likely(elo->data[1] == ELO10_TOUCH_PACKET)) {
input_regs(dev, regs);
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_PRESSURE, (elo->data[8] << 8) | elo->data[7]);
input_report_key(dev, BTN_TOUCH, elo->data[8] || elo->data[7]);
if (elo->data[2] & ELO10_PRESSURE)
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);
} 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;
}
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;
......@@ -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;
......@@ -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,
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) {
case 0:
......@@ -181,17 +210,81 @@ static irqreturn_t elo_interrupt(struct serio *serio,
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()
*/
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);
serio_close(serio);
serio_set_drvdata(serio, NULL);
input_put_device(elo->dev);
kfree(elo);
}
......@@ -211,12 +304,15 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
input_dev = input_allocate_device();
if (!elo || !input_dev) {
err = -ENOMEM;
goto fail;
goto fail1;
}
elo->serio = serio;
elo->id = serio->id.id;
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);
input_dev->private = elo;
......@@ -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->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
serio_set_drvdata(serio, elo);
err = serio_open(serio, drv);
if (err)
goto fail2;
switch (elo->id) {
case 0: /* 10-byte protocol */
input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 96, 4000, 0, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0);
if (elo_setup_10(elo))
goto fail3;
break;
case 1: /* 6-byte protocol */
......@@ -253,17 +354,15 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
break;
}
serio_set_drvdata(serio, elo);
err = serio_open(serio, drv);
err = input_register_device(elo->dev);
if (err)
goto fail;
goto fail3;
input_register_device(elo->dev);
return 0;
fail: serio_set_drvdata(serio, NULL);
input_free_device(input_dev);
fail3: serio_close(serio);
fail2: serio_set_drvdata(serio, NULL);
fail1: input_free_device(input_dev);
kfree(elo);
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)
usbhid-objs += hid-input.o
endif
ifeq ($(CONFIG_HID_PID),y)
usbhid-objs += pid.o
usbhid-objs += hid-pidff.o
endif
ifeq ($(CONFIG_LOGITECH_FF),y)
usbhid-objs += hid-lgff.o
......@@ -23,6 +23,9 @@ endif
ifeq ($(CONFIG_THRUSTMASTER_FF),y)
usbhid-objs += hid-tmff.o
endif
ifeq ($(CONFIG_ZEROPLUS_FF),y)
usbhid-objs += hid-zpff.o
endif
ifeq ($(CONFIG_HID_FF),y)
usbhid-objs += hid-ff.o
endif
......
......@@ -543,8 +543,6 @@ static void hid_free_device(struct hid_device *device)
{
unsigned i,j;
hid_ff_exit(device);
for (i = 0; i < HID_REPORT_TYPES; 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)
/*
* 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_report *report;
......@@ -1121,6 +1119,7 @@ struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_u
return report->field[i];
return NULL;
}
#endif /* 0 */
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