Merge branch 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/dtor/input
* 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/dtor/input: (65 commits) Input: gpio_keys - add support for switches (EV_SW) Input: cobalt_btns - convert to use polldev library Input: add skeleton for simple polled devices Input: update some documentation Input: wistron - fix typo in keymap for Acer TM610 Input: add input_set_capability() helper Input: i8042 - add Fujitsu touchscreen/touchpad PNP IDs Input: i8042 - add Panasonic CF-29 to nomux list Input: lifebook - split into 2 devices Input: lifebook - add signature of Panasonic CF-29 Input: lifebook - activate 6-byte protocol on select models Input: lifebook - work properly on Panasonic CF-18 Input: cobalt buttons - separate device and driver registration Input: ati_remote - make button repeat sensitivity configurable Input: pxa27x - do not use deprecated SA_INTERRUPT flag Input: ucb1400 - make delays configurable Input: misc devices - switch to using input_dev->dev.parent Input: joysticks - switch to using input_dev->dev.parent Input: touchscreens - switch to using input_dev->dev.parent Input: mice - switch to using input_dev->dev.parent ... Fixed up conflicts with core device model removal of "struct subsystem" manually. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
commit
a3d52136ee
|
@ -1,5 +1,3 @@
|
||||||
$Id: input-programming.txt,v 1.4 2001/05/04 09:47:14 vojtech Exp $
|
|
||||||
|
|
||||||
Programming input drivers
|
Programming input drivers
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -20,28 +18,51 @@ pressed or released a BUTTON_IRQ happens. The driver could look like:
|
||||||
#include <asm/irq.h>
|
#include <asm/irq.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
|
|
||||||
|
static struct input_dev *button_dev;
|
||||||
|
|
||||||
static void button_interrupt(int irq, void *dummy, struct pt_regs *fp)
|
static void button_interrupt(int irq, void *dummy, struct pt_regs *fp)
|
||||||
{
|
{
|
||||||
input_report_key(&button_dev, BTN_1, inb(BUTTON_PORT) & 1);
|
input_report_key(button_dev, BTN_1, inb(BUTTON_PORT) & 1);
|
||||||
input_sync(&button_dev);
|
input_sync(button_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init button_init(void)
|
static int __init button_init(void)
|
||||||
{
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)) {
|
if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)) {
|
||||||
printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_irq);
|
printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_irq);
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
button_dev.evbit[0] = BIT(EV_KEY);
|
button_dev = input_allocate_device();
|
||||||
button_dev.keybit[LONG(BTN_0)] = BIT(BTN_0);
|
if (!button_dev) {
|
||||||
|
printk(KERN_ERR "button.c: Not enough memory\n");
|
||||||
|
error = -ENOMEM;
|
||||||
|
goto err_free_irq;
|
||||||
|
}
|
||||||
|
|
||||||
input_register_device(&button_dev);
|
button_dev->evbit[0] = BIT(EV_KEY);
|
||||||
|
button_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
|
||||||
|
|
||||||
|
error = input_register_device(button_dev);
|
||||||
|
if (error) {
|
||||||
|
printk(KERN_ERR "button.c: Failed to register device\n");
|
||||||
|
goto err_free_dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_free_dev:
|
||||||
|
input_free_device(button_dev);
|
||||||
|
err_free_irq:
|
||||||
|
free_irq(BUTTON_IRQ, button_interrupt);
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit button_exit(void)
|
static void __exit button_exit(void)
|
||||||
{
|
{
|
||||||
input_unregister_device(&button_dev);
|
input_unregister_device(button_dev);
|
||||||
free_irq(BUTTON_IRQ, button_interrupt);
|
free_irq(BUTTON_IRQ, button_interrupt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,11 +79,12 @@ In the _init function, which is called either upon module load or when
|
||||||
booting the kernel, it grabs the required resources (it should also check
|
booting the kernel, it grabs the required resources (it should also check
|
||||||
for the presence of the device).
|
for the presence of the device).
|
||||||
|
|
||||||
Then it sets the input bitfields. This way the device driver tells the other
|
Then it allocates a new input device structure with input_aloocate_device()
|
||||||
|
and sets up input bitfields. This way the device driver tells the other
|
||||||
parts of the input systems what it is - what events can be generated or
|
parts of the input systems what it is - what events can be generated or
|
||||||
accepted by this input device. Our example device can only generate EV_KEY type
|
accepted by this input device. Our example device can only generate EV_KEY
|
||||||
events, and from those only BTN_0 event code. Thus we only set these two
|
type events, and from those only BTN_0 event code. Thus we only set these
|
||||||
bits. We could have used
|
two bits. We could have used
|
||||||
|
|
||||||
set_bit(EV_KEY, button_dev.evbit);
|
set_bit(EV_KEY, button_dev.evbit);
|
||||||
set_bit(BTN_0, button_dev.keybit);
|
set_bit(BTN_0, button_dev.keybit);
|
||||||
|
@ -76,9 +98,8 @@ Then the example driver registers the input device structure by calling
|
||||||
|
|
||||||
This adds the button_dev structure to linked lists of the input driver and
|
This adds the button_dev structure to linked lists of the input driver and
|
||||||
calls device handler modules _connect functions to tell them a new input
|
calls device handler modules _connect functions to tell them a new input
|
||||||
device has appeared. Because the _connect functions may call kmalloc(,
|
device has appeared. input_register_device() may sleep and therefore must
|
||||||
GFP_KERNEL), which can sleep, input_register_device() must not be called
|
not be called from an interrupt or with a spinlock held.
|
||||||
from an interrupt or with a spinlock held.
|
|
||||||
|
|
||||||
While in use, the only used function of the driver is
|
While in use, the only used function of the driver is
|
||||||
|
|
||||||
|
@ -113,16 +134,10 @@ can use the open and close callback to know when it can stop polling or
|
||||||
release the interrupt and when it must resume polling or grab the interrupt
|
release the interrupt and when it must resume polling or grab the interrupt
|
||||||
again. To do that, we would add this to our example driver:
|
again. To do that, we would add this to our example driver:
|
||||||
|
|
||||||
int button_used = 0;
|
|
||||||
|
|
||||||
static int button_open(struct input_dev *dev)
|
static int button_open(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
if (button_used++)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)) {
|
if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)) {
|
||||||
printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_irq);
|
printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_irq);
|
||||||
button_used--;
|
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,20 +146,21 @@ static int button_open(struct input_dev *dev)
|
||||||
|
|
||||||
static void button_close(struct input_dev *dev)
|
static void button_close(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
if (!--button_used)
|
|
||||||
free_irq(IRQ_AMIGA_VERTB, button_interrupt);
|
free_irq(IRQ_AMIGA_VERTB, button_interrupt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init button_init(void)
|
static int __init button_init(void)
|
||||||
{
|
{
|
||||||
...
|
...
|
||||||
button_dev.open = button_open;
|
button_dev->open = button_open;
|
||||||
button_dev.close = button_close;
|
button_dev->close = button_close;
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
Note the button_used variable - we have to track how many times the open
|
Note that input core keeps track of number of users for the device and
|
||||||
function was called to know when exactly our device stops being used.
|
makes sure that dev->open() is called only when the first user connects
|
||||||
|
to the device and that dev->close() is called when the very last user
|
||||||
|
disconnects. Calls to both callbacks are serialized.
|
||||||
|
|
||||||
The open() callback should return a 0 in case of success or any nonzero value
|
The open() callback should return a 0 in case of success or any nonzero value
|
||||||
in case of failure. The close() callback (which is void) must always succeed.
|
in case of failure. The close() callback (which is void) must always succeed.
|
||||||
|
@ -187,6 +203,10 @@ the ABS_X axis:
|
||||||
button_dev.absfuzz[ABS_X] = 4;
|
button_dev.absfuzz[ABS_X] = 4;
|
||||||
button_dev.absflat[ABS_X] = 8;
|
button_dev.absflat[ABS_X] = 8;
|
||||||
|
|
||||||
|
Or, you can just say:
|
||||||
|
|
||||||
|
input_set_abs_params(button_dev, ABS_X, 0, 255, 4, 8);
|
||||||
|
|
||||||
This setting would be appropriate for a joystick X axis, with the minimum of
|
This setting would be appropriate for a joystick X axis, with the minimum of
|
||||||
0, maximum of 255 (which the joystick *must* be able to reach, no problem if
|
0, maximum of 255 (which the joystick *must* be able to reach, no problem if
|
||||||
it sometimes reports more, but it must be able to always reach the min and
|
it sometimes reports more, but it must be able to always reach the min and
|
||||||
|
@ -197,14 +217,7 @@ If you don't need absfuzz and absflat, you can set them to zero, which mean
|
||||||
that the thing is precise and always returns to exactly the center position
|
that the thing is precise and always returns to exactly the center position
|
||||||
(if it has any).
|
(if it has any).
|
||||||
|
|
||||||
1.4 The void *private field
|
1.4 NBITS(), LONG(), BIT()
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
This field in the input structure can be used to point to any private data
|
|
||||||
structures in the input device driver, in case the driver handles more than
|
|
||||||
one device. You'll need it in the open and close callbacks.
|
|
||||||
|
|
||||||
1.5 NBITS(), LONG(), BIT()
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
These three macros from input.h help some bitfield computations:
|
These three macros from input.h help some bitfield computations:
|
||||||
|
@ -213,13 +226,9 @@ These three macros from input.h help some bitfield computations:
|
||||||
LONG(x) - returns the index in the array in longs for bit x
|
LONG(x) - returns the index in the array in longs for bit x
|
||||||
BIT(x) - returns the index in a long for bit x
|
BIT(x) - returns the index in a long for bit x
|
||||||
|
|
||||||
1.6 The number, id* and name fields
|
1.5 The id* and name fields
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
The dev->number is assigned by the input system to the input device when it
|
|
||||||
is registered. It has no use except for identifying the device to the user
|
|
||||||
in system messages.
|
|
||||||
|
|
||||||
The dev->name should be set before registering the input device by the input
|
The dev->name should be set before registering the input device by the input
|
||||||
device driver. It's a string like 'Generic button device' containing a
|
device driver. It's a string like 'Generic button device' containing a
|
||||||
user friendly name of the device.
|
user friendly name of the device.
|
||||||
|
@ -234,15 +243,25 @@ driver.
|
||||||
|
|
||||||
The id and name fields can be passed to userland via the evdev interface.
|
The id and name fields can be passed to userland via the evdev interface.
|
||||||
|
|
||||||
1.7 The keycode, keycodemax, keycodesize fields
|
1.6 The keycode, keycodemax, keycodesize fields
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
These two fields will be used for any input devices that report their data
|
These three fields should be used by input devices that have dense keymaps.
|
||||||
as scancodes. If not all scancodes can be known by autodetection, they may
|
The keycode is an array used to map from scancodes to input system keycodes.
|
||||||
need to be set by userland utilities. The keycode array then is an array
|
The keycode max should contain the size of the array and keycodesize the
|
||||||
used to map from scancodes to input system keycodes. The keycode max will
|
size of each entry in it (in bytes).
|
||||||
contain the size of the array and keycodesize the size of each entry in it
|
|
||||||
(in bytes).
|
Userspace can query and alter current scancode to keycode mappings using
|
||||||
|
EVIOCGKEYCODE and EVIOCSKEYCODE ioctls on corresponding evdev interface.
|
||||||
|
When a device has all 3 aforementioned fields filled in, the driver may
|
||||||
|
rely on kernel's default implementation of setting and querying keycode
|
||||||
|
mappings.
|
||||||
|
|
||||||
|
1.7 dev->getkeycode() and dev->setkeycode()
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
getkeycode() and setkeycode() callbacks allow drivers to override default
|
||||||
|
keycode/keycodesize/keycodemax mapping mechanism provided by input core
|
||||||
|
and implement sparse keycode maps.
|
||||||
|
|
||||||
1.8 Key autorepeat
|
1.8 Key autorepeat
|
||||||
~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -266,7 +285,7 @@ direction - from the system to the input device driver. If your input device
|
||||||
driver can handle these events, it has to set the respective bits in evbit,
|
driver can handle these events, it has to set the respective bits in evbit,
|
||||||
*and* also the callback routine:
|
*and* also the callback routine:
|
||||||
|
|
||||||
button_dev.event = button_event;
|
button_dev->event = button_event;
|
||||||
|
|
||||||
int button_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
|
int button_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# Makefile for the Cobalt micro systems family specific parts of the kernel
|
# Makefile for the Cobalt micro systems family specific parts of the kernel
|
||||||
#
|
#
|
||||||
|
|
||||||
obj-y := irq.o reset.o setup.o
|
obj-y := irq.o reset.o setup.o buttons.o
|
||||||
|
|
||||||
obj-$(CONFIG_PCI) += pci.o
|
obj-$(CONFIG_PCI) += pci.o
|
||||||
obj-$(CONFIG_EARLY_PRINTK) += console.o
|
obj-$(CONFIG_EARLY_PRINTK) += console.o
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* Cobalt buttons platform device.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
|
||||||
|
static struct resource cobalt_buttons_resource __initdata = {
|
||||||
|
.start = 0x1d000000,
|
||||||
|
.end = 0x1d000003,
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
};
|
||||||
|
|
||||||
|
static __init int cobalt_add_buttons(void)
|
||||||
|
{
|
||||||
|
struct platform_device *pd;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
pd = platform_device_alloc("Cobalt buttons", -1);
|
||||||
|
if (!pd)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
error = platform_device_add_resources(pd, &cobalt_buttons_resource, 1);
|
||||||
|
if (error)
|
||||||
|
goto err_free_device;
|
||||||
|
|
||||||
|
error = platform_device_add(pd);
|
||||||
|
if (error)
|
||||||
|
goto err_free_device;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_free_device:
|
||||||
|
platform_device_put(pd);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
device_initcall(cobalt_add_buttons);
|
|
@ -41,7 +41,6 @@
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <linux/reboot.h>
|
#include <linux/reboot.h>
|
||||||
|
|
||||||
static void kbd_disconnect(struct input_handle *handle);
|
|
||||||
extern void ctrl_alt_del(void);
|
extern void ctrl_alt_del(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -159,65 +158,41 @@ static int sysrq_alt_use;
|
||||||
static int sysrq_alt;
|
static int sysrq_alt;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Translation of scancodes to keycodes. We set them on only the first attached
|
* Translation of scancodes to keycodes. We set them on only the first
|
||||||
* keyboard - for per-keyboard setting, /dev/input/event is more useful.
|
* keyboard in the list that accepts the scancode and keycode.
|
||||||
|
* Explanation for not choosing the first attached keyboard anymore:
|
||||||
|
* USB keyboards for example have two event devices: one for all "normal"
|
||||||
|
* keys and one for extra function keys (like "volume up", "make coffee",
|
||||||
|
* etc.). So this means that scancodes for the extra function keys won't
|
||||||
|
* be valid for the first event device, but will be for the second.
|
||||||
*/
|
*/
|
||||||
int getkeycode(unsigned int scancode)
|
int getkeycode(unsigned int scancode)
|
||||||
{
|
{
|
||||||
struct list_head *node;
|
struct input_handle *handle;
|
||||||
struct input_dev *dev = NULL;
|
int keycode;
|
||||||
|
int error = -ENODEV;
|
||||||
|
|
||||||
list_for_each(node, &kbd_handler.h_list) {
|
list_for_each_entry(handle, &kbd_handler.h_list, h_node) {
|
||||||
struct input_handle *handle = to_handle_h(node);
|
error = handle->dev->getkeycode(handle->dev, scancode, &keycode);
|
||||||
if (handle->dev->keycodesize) {
|
if (!error)
|
||||||
dev = handle->dev;
|
return keycode;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dev)
|
return error;
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
if (scancode >= dev->keycodemax)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return INPUT_KEYCODE(dev, scancode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int setkeycode(unsigned int scancode, unsigned int keycode)
|
int setkeycode(unsigned int scancode, unsigned int keycode)
|
||||||
{
|
{
|
||||||
struct list_head *node;
|
struct input_handle *handle;
|
||||||
struct input_dev *dev = NULL;
|
int error = -ENODEV;
|
||||||
unsigned int i, oldkey;
|
|
||||||
|
|
||||||
list_for_each(node, &kbd_handler.h_list) {
|
list_for_each_entry(handle, &kbd_handler.h_list, h_node) {
|
||||||
struct input_handle *handle = to_handle_h(node);
|
error = handle->dev->setkeycode(handle->dev, scancode, keycode);
|
||||||
if (handle->dev->keycodesize) {
|
if (!error)
|
||||||
dev = handle->dev;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!dev)
|
return error;
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
if (scancode >= dev->keycodemax)
|
|
||||||
return -EINVAL;
|
|
||||||
if (keycode < 0 || keycode > KEY_MAX)
|
|
||||||
return -EINVAL;
|
|
||||||
if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8)))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
oldkey = SET_INPUT_KEYCODE(dev, scancode, keycode);
|
|
||||||
|
|
||||||
clear_bit(oldkey, dev->keybit);
|
|
||||||
set_bit(keycode, dev->keybit);
|
|
||||||
|
|
||||||
for (i = 0; i < dev->keycodemax; i++)
|
|
||||||
if (INPUT_KEYCODE(dev,i) == oldkey)
|
|
||||||
set_bit(oldkey, dev->keybit);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -225,10 +200,9 @@ int setkeycode(unsigned int scancode, unsigned int keycode)
|
||||||
*/
|
*/
|
||||||
static void kd_nosound(unsigned long ignored)
|
static void kd_nosound(unsigned long ignored)
|
||||||
{
|
{
|
||||||
struct list_head *node;
|
struct input_handle *handle;
|
||||||
|
|
||||||
list_for_each(node, &kbd_handler.h_list) {
|
list_for_each_entry(handle, &kbd_handler.h_list, h_node) {
|
||||||
struct input_handle *handle = to_handle_h(node);
|
|
||||||
if (test_bit(EV_SND, handle->dev->evbit)) {
|
if (test_bit(EV_SND, handle->dev->evbit)) {
|
||||||
if (test_bit(SND_TONE, handle->dev->sndbit))
|
if (test_bit(SND_TONE, handle->dev->sndbit))
|
||||||
input_inject_event(handle, EV_SND, SND_TONE, 0);
|
input_inject_event(handle, EV_SND, SND_TONE, 0);
|
||||||
|
@ -1161,7 +1135,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
|
||||||
|
|
||||||
if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw)
|
if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw)
|
||||||
if (emulate_raw(vc, keycode, !down << 7))
|
if (emulate_raw(vc, keycode, !down << 7))
|
||||||
if (keycode < BTN_MISC)
|
if (keycode < BTN_MISC && printk_ratelimit())
|
||||||
printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode);
|
printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode);
|
||||||
|
|
||||||
#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */
|
#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */
|
||||||
|
@ -1285,11 +1259,11 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type,
|
||||||
* likes it, it can open it and get events from it. In this (kbd_connect)
|
* likes it, it can open it and get events from it. In this (kbd_connect)
|
||||||
* function, we should decide which VT to bind that keyboard to initially.
|
* function, we should decide which VT to bind that keyboard to initially.
|
||||||
*/
|
*/
|
||||||
static struct input_handle *kbd_connect(struct input_handler *handler,
|
static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
|
||||||
struct input_dev *dev,
|
|
||||||
const struct input_device_id *id)
|
const struct input_device_id *id)
|
||||||
{
|
{
|
||||||
struct input_handle *handle;
|
struct input_handle *handle;
|
||||||
|
int error;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = KEY_RESERVED; i < BTN_MISC; i++)
|
for (i = KEY_RESERVED; i < BTN_MISC; i++)
|
||||||
|
@ -1297,24 +1271,37 @@ static struct input_handle *kbd_connect(struct input_handler *handler,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit))
|
if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit))
|
||||||
return NULL;
|
return -ENODEV;
|
||||||
|
|
||||||
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
|
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
|
||||||
if (!handle)
|
if (!handle)
|
||||||
return NULL;
|
return -ENOMEM;
|
||||||
|
|
||||||
handle->dev = dev;
|
handle->dev = dev;
|
||||||
handle->handler = handler;
|
handle->handler = handler;
|
||||||
handle->name = "kbd";
|
handle->name = "kbd";
|
||||||
|
|
||||||
input_open_device(handle);
|
error = input_register_handle(handle);
|
||||||
|
if (error)
|
||||||
|
goto err_free_handle;
|
||||||
|
|
||||||
return handle;
|
error = input_open_device(handle);
|
||||||
|
if (error)
|
||||||
|
goto err_unregister_handle;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_unregister_handle:
|
||||||
|
input_unregister_handle(handle);
|
||||||
|
err_free_handle:
|
||||||
|
kfree(handle);
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kbd_disconnect(struct input_handle *handle)
|
static void kbd_disconnect(struct input_handle *handle)
|
||||||
{
|
{
|
||||||
input_close_device(handle);
|
input_close_device(handle);
|
||||||
|
input_unregister_handle(handle);
|
||||||
kfree(handle);
|
kfree(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ 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
|
||||||
obj-$(CONFIG_INPUT_TSDEV) += tsdev.o
|
obj-$(CONFIG_INPUT_TSDEV) += tsdev.o
|
||||||
obj-$(CONFIG_INPUT_POWER) += power.o
|
|
||||||
obj-$(CONFIG_INPUT_EVBUG) += evbug.o
|
obj-$(CONFIG_INPUT_EVBUG) += evbug.o
|
||||||
|
|
||||||
obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/
|
obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/
|
||||||
|
|
|
@ -38,31 +38,43 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||||
MODULE_DESCRIPTION("Input driver event debug module");
|
MODULE_DESCRIPTION("Input driver event debug module");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
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",
|
printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n",
|
||||||
handle->dev->phys, type, code, value);
|
handle->dev->phys, type, code, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev,
|
static int evbug_connect(struct input_handler *handler, struct input_dev *dev,
|
||||||
const struct input_device_id *id)
|
const struct input_device_id *id)
|
||||||
{
|
{
|
||||||
struct input_handle *handle;
|
struct input_handle *handle;
|
||||||
|
int error;
|
||||||
|
|
||||||
if (!(handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL)))
|
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
|
||||||
return NULL;
|
if (!handle)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
handle->dev = dev;
|
handle->dev = dev;
|
||||||
handle->handler = handler;
|
handle->handler = handler;
|
||||||
handle->name = evbug_name;
|
handle->name = "evbug";
|
||||||
|
|
||||||
input_open_device(handle);
|
error = input_register_handle(handle);
|
||||||
|
if (error)
|
||||||
|
goto err_free_handle;
|
||||||
|
|
||||||
|
error = input_open_device(handle);
|
||||||
|
if (error)
|
||||||
|
goto err_unregister_handle;
|
||||||
|
|
||||||
printk(KERN_DEBUG "evbug.c: Connected device: \"%s\", %s\n", dev->name, dev->phys);
|
printk(KERN_DEBUG "evbug.c: Connected device: \"%s\", %s\n", dev->name, dev->phys);
|
||||||
|
|
||||||
return handle;
|
return 0;
|
||||||
|
|
||||||
|
err_unregister_handle:
|
||||||
|
input_unregister_handle(handle);
|
||||||
|
err_free_handle:
|
||||||
|
kfree(handle);
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void evbug_disconnect(struct input_handle *handle)
|
static void evbug_disconnect(struct input_handle *handle)
|
||||||
|
@ -70,7 +82,7 @@ static void evbug_disconnect(struct input_handle *handle)
|
||||||
printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", handle->dev->phys);
|
printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", handle->dev->phys);
|
||||||
|
|
||||||
input_close_device(handle);
|
input_close_device(handle);
|
||||||
|
input_unregister_handle(handle);
|
||||||
kfree(handle);
|
kfree(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,11 +29,11 @@ struct evdev {
|
||||||
char name[16];
|
char name[16];
|
||||||
struct input_handle handle;
|
struct input_handle handle;
|
||||||
wait_queue_head_t wait;
|
wait_queue_head_t wait;
|
||||||
struct evdev_list *grab;
|
struct evdev_client *grab;
|
||||||
struct list_head list;
|
struct list_head client_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct evdev_list {
|
struct evdev_client {
|
||||||
struct input_event buffer[EVDEV_BUFFER_SIZE];
|
struct input_event buffer[EVDEV_BUFFER_SIZE];
|
||||||
int head;
|
int head;
|
||||||
int tail;
|
int tail;
|
||||||
|
@ -47,28 +47,28 @@ static struct evdev *evdev_table[EVDEV_MINORS];
|
||||||
static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
|
static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
|
||||||
{
|
{
|
||||||
struct evdev *evdev = handle->private;
|
struct evdev *evdev = handle->private;
|
||||||
struct evdev_list *list;
|
struct evdev_client *client;
|
||||||
|
|
||||||
if (evdev->grab) {
|
if (evdev->grab) {
|
||||||
list = evdev->grab;
|
client = evdev->grab;
|
||||||
|
|
||||||
do_gettimeofday(&list->buffer[list->head].time);
|
do_gettimeofday(&client->buffer[client->head].time);
|
||||||
list->buffer[list->head].type = type;
|
client->buffer[client->head].type = type;
|
||||||
list->buffer[list->head].code = code;
|
client->buffer[client->head].code = code;
|
||||||
list->buffer[list->head].value = value;
|
client->buffer[client->head].value = value;
|
||||||
list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);
|
client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1);
|
||||||
|
|
||||||
kill_fasync(&list->fasync, SIGIO, POLL_IN);
|
kill_fasync(&client->fasync, SIGIO, POLL_IN);
|
||||||
} else
|
} else
|
||||||
list_for_each_entry(list, &evdev->list, node) {
|
list_for_each_entry(client, &evdev->client_list, node) {
|
||||||
|
|
||||||
do_gettimeofday(&list->buffer[list->head].time);
|
do_gettimeofday(&client->buffer[client->head].time);
|
||||||
list->buffer[list->head].type = type;
|
client->buffer[client->head].type = type;
|
||||||
list->buffer[list->head].code = code;
|
client->buffer[client->head].code = code;
|
||||||
list->buffer[list->head].value = value;
|
client->buffer[client->head].value = value;
|
||||||
list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);
|
client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1);
|
||||||
|
|
||||||
kill_fasync(&list->fasync, SIGIO, POLL_IN);
|
kill_fasync(&client->fasync, SIGIO, POLL_IN);
|
||||||
}
|
}
|
||||||
|
|
||||||
wake_up_interruptible(&evdev->wait);
|
wake_up_interruptible(&evdev->wait);
|
||||||
|
@ -76,22 +76,23 @@ static void evdev_event(struct input_handle *handle, unsigned int type, unsigned
|
||||||
|
|
||||||
static int evdev_fasync(int fd, struct file *file, int on)
|
static int evdev_fasync(int fd, struct file *file, int on)
|
||||||
{
|
{
|
||||||
|
struct evdev_client *client = file->private_data;
|
||||||
int retval;
|
int retval;
|
||||||
struct evdev_list *list = file->private_data;
|
|
||||||
|
|
||||||
retval = fasync_helper(fd, file, on, &list->fasync);
|
retval = fasync_helper(fd, file, on, &client->fasync);
|
||||||
|
|
||||||
return retval < 0 ? retval : 0;
|
return retval < 0 ? retval : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int evdev_flush(struct file *file, fl_owner_t id)
|
static int evdev_flush(struct file *file, fl_owner_t id)
|
||||||
{
|
{
|
||||||
struct evdev_list *list = file->private_data;
|
struct evdev_client *client = file->private_data;
|
||||||
|
struct evdev *evdev = client->evdev;
|
||||||
|
|
||||||
if (!list->evdev->exist)
|
if (!evdev->exist)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
return input_flush_device(&list->evdev->handle, file);
|
return input_flush_device(&evdev->handle, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void evdev_free(struct evdev *evdev)
|
static void evdev_free(struct evdev *evdev)
|
||||||
|
@ -100,48 +101,62 @@ static void evdev_free(struct evdev *evdev)
|
||||||
kfree(evdev);
|
kfree(evdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int evdev_release(struct inode * inode, struct file * file)
|
static int evdev_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct evdev_list *list = file->private_data;
|
struct evdev_client *client = file->private_data;
|
||||||
|
struct evdev *evdev = client->evdev;
|
||||||
|
|
||||||
if (list->evdev->grab == list) {
|
if (evdev->grab == client) {
|
||||||
input_release_device(&list->evdev->handle);
|
input_release_device(&evdev->handle);
|
||||||
list->evdev->grab = NULL;
|
evdev->grab = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
evdev_fasync(-1, file, 0);
|
evdev_fasync(-1, file, 0);
|
||||||
list_del(&list->node);
|
list_del(&client->node);
|
||||||
|
kfree(client);
|
||||||
|
|
||||||
if (!--list->evdev->open) {
|
if (!--evdev->open) {
|
||||||
if (list->evdev->exist)
|
if (evdev->exist)
|
||||||
input_close_device(&list->evdev->handle);
|
input_close_device(&evdev->handle);
|
||||||
else
|
else
|
||||||
evdev_free(list->evdev);
|
evdev_free(evdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
kfree(list);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int evdev_open(struct inode * inode, struct file * file)
|
static int evdev_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct evdev_list *list;
|
struct evdev_client *client;
|
||||||
|
struct evdev *evdev;
|
||||||
int i = iminor(inode) - EVDEV_MINOR_BASE;
|
int i = iminor(inode) - EVDEV_MINOR_BASE;
|
||||||
|
int error;
|
||||||
|
|
||||||
if (i >= EVDEV_MINORS || !evdev_table[i] || !evdev_table[i]->exist)
|
if (i >= EVDEV_MINORS)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if (!(list = kzalloc(sizeof(struct evdev_list), GFP_KERNEL)))
|
evdev = evdev_table[i];
|
||||||
|
|
||||||
|
if (!evdev || !evdev->exist)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL);
|
||||||
|
if (!client)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
list->evdev = evdev_table[i];
|
client->evdev = evdev;
|
||||||
list_add_tail(&list->node, &evdev_table[i]->list);
|
list_add_tail(&client->node, &evdev->client_list);
|
||||||
file->private_data = list;
|
|
||||||
|
|
||||||
if (!list->evdev->open++)
|
if (!evdev->open++ && evdev->exist) {
|
||||||
if (list->evdev->exist)
|
error = input_open_device(&evdev->handle);
|
||||||
input_open_device(&list->evdev->handle);
|
if (error) {
|
||||||
|
list_del(&client->node);
|
||||||
|
kfree(client);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file->private_data = client;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,54 +258,55 @@ static int evdev_event_to_user(char __user *buffer, const struct input_event *ev
|
||||||
|
|
||||||
#endif /* CONFIG_COMPAT */
|
#endif /* CONFIG_COMPAT */
|
||||||
|
|
||||||
static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
|
static ssize_t evdev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
|
||||||
{
|
{
|
||||||
struct evdev_list *list = file->private_data;
|
struct evdev_client *client = file->private_data;
|
||||||
|
struct evdev *evdev = client->evdev;
|
||||||
struct input_event event;
|
struct input_event event;
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
if (!list->evdev->exist)
|
if (!evdev->exist)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
while (retval < count) {
|
while (retval < count) {
|
||||||
|
|
||||||
if (evdev_event_from_user(buffer + retval, &event))
|
if (evdev_event_from_user(buffer + retval, &event))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
input_inject_event(&list->evdev->handle, event.type, event.code, event.value);
|
input_inject_event(&evdev->handle, event.type, event.code, event.value);
|
||||||
retval += evdev_event_size();
|
retval += evdev_event_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
|
static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
|
||||||
{
|
{
|
||||||
struct evdev_list *list = file->private_data;
|
struct evdev_client *client = file->private_data;
|
||||||
|
struct evdev *evdev = client->evdev;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if (count < evdev_event_size())
|
if (count < evdev_event_size())
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))
|
if (client->head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK))
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
retval = wait_event_interruptible(list->evdev->wait,
|
retval = wait_event_interruptible(evdev->wait,
|
||||||
list->head != list->tail || (!list->evdev->exist));
|
client->head != client->tail || !evdev->exist);
|
||||||
|
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
if (!list->evdev->exist)
|
if (!evdev->exist)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
while (list->head != list->tail && retval + evdev_event_size() <= count) {
|
while (client->head != client->tail && retval + evdev_event_size() <= count) {
|
||||||
|
|
||||||
struct input_event *event = (struct input_event *) list->buffer + list->tail;
|
struct input_event *event = (struct input_event *) client->buffer + client->tail;
|
||||||
|
|
||||||
if (evdev_event_to_user(buffer + retval, event))
|
if (evdev_event_to_user(buffer + retval, event))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
|
client->tail = (client->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
|
||||||
retval += evdev_event_size();
|
retval += evdev_event_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,11 +316,12 @@ static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count
|
||||||
/* No kernel lock - fine */
|
/* No kernel lock - fine */
|
||||||
static unsigned int evdev_poll(struct file *file, poll_table *wait)
|
static unsigned int evdev_poll(struct file *file, poll_table *wait)
|
||||||
{
|
{
|
||||||
struct evdev_list *list = file->private_data;
|
struct evdev_client *client = file->private_data;
|
||||||
|
struct evdev *evdev = client->evdev;
|
||||||
|
|
||||||
poll_wait(file, &list->evdev->wait, wait);
|
poll_wait(file, &evdev->wait, wait);
|
||||||
return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) |
|
return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) |
|
||||||
(list->evdev->exist ? 0 : (POLLHUP | POLLERR));
|
(evdev->exist ? 0 : (POLLHUP | POLLERR));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
|
@ -387,8 +404,8 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p)
|
||||||
static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
|
static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
|
||||||
void __user *p, int compat_mode)
|
void __user *p, int compat_mode)
|
||||||
{
|
{
|
||||||
struct evdev_list *list = file->private_data;
|
struct evdev_client *client = file->private_data;
|
||||||
struct evdev *evdev = list->evdev;
|
struct evdev *evdev = client->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;
|
struct ff_effect effect;
|
||||||
|
@ -434,32 +451,21 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
|
||||||
case EVIOCGKEYCODE:
|
case EVIOCGKEYCODE:
|
||||||
if (get_user(t, ip))
|
if (get_user(t, ip))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (t < 0 || t >= dev->keycodemax || !dev->keycodesize)
|
|
||||||
return -EINVAL;
|
error = dev->getkeycode(dev, t, &v);
|
||||||
if (put_user(INPUT_KEYCODE(dev, t), ip + 1))
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
if (put_user(v, ip + 1))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case EVIOCSKEYCODE:
|
case EVIOCSKEYCODE:
|
||||||
if (get_user(t, ip))
|
if (get_user(t, ip) || get_user(v, ip + 1))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (t < 0 || t >= dev->keycodemax || !dev->keycodesize)
|
|
||||||
return -EINVAL;
|
|
||||||
if (get_user(v, ip + 1))
|
|
||||||
return -EFAULT;
|
|
||||||
if (v < 0 || v > KEY_MAX)
|
|
||||||
return -EINVAL;
|
|
||||||
if (dev->keycodesize < sizeof(v) && (v >> (dev->keycodesize * 8)))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
u = SET_INPUT_KEYCODE(dev, t, v);
|
return dev->setkeycode(dev, t, v);
|
||||||
clear_bit(u, dev->keybit);
|
|
||||||
set_bit(v, dev->keybit);
|
|
||||||
for (i = 0; i < dev->keycodemax; i++)
|
|
||||||
if (INPUT_KEYCODE(dev, i) == u)
|
|
||||||
set_bit(u, dev->keybit);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case EVIOCSFF:
|
case EVIOCSFF:
|
||||||
if (copy_from_user(&effect, p, sizeof(effect)))
|
if (copy_from_user(&effect, p, sizeof(effect)))
|
||||||
|
@ -487,10 +493,10 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
if (input_grab_device(&evdev->handle))
|
if (input_grab_device(&evdev->handle))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
evdev->grab = list;
|
evdev->grab = client;
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
if (evdev->grab != list)
|
if (evdev->grab != client)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
input_release_device(&evdev->handle);
|
input_release_device(&evdev->handle);
|
||||||
evdev->grab = NULL;
|
evdev->grab = NULL;
|
||||||
|
@ -616,23 +622,26 @@ static const 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,
|
static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
|
||||||
const struct input_device_id *id)
|
const struct input_device_id *id)
|
||||||
{
|
{
|
||||||
struct evdev *evdev;
|
struct evdev *evdev;
|
||||||
struct class_device *cdev;
|
struct class_device *cdev;
|
||||||
|
dev_t devt;
|
||||||
int minor;
|
int minor;
|
||||||
|
int error;
|
||||||
|
|
||||||
for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
|
for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
|
||||||
if (minor == EVDEV_MINORS) {
|
if (minor == EVDEV_MINORS) {
|
||||||
printk(KERN_ERR "evdev: no more free evdev devices\n");
|
printk(KERN_ERR "evdev: no more free evdev devices\n");
|
||||||
return NULL;
|
return -ENFILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL)))
|
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
|
||||||
return NULL;
|
if (!evdev)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&evdev->list);
|
INIT_LIST_HEAD(&evdev->client_list);
|
||||||
init_waitqueue_head(&evdev->wait);
|
init_waitqueue_head(&evdev->wait);
|
||||||
|
|
||||||
evdev->exist = 1;
|
evdev->exist = 1;
|
||||||
|
@ -645,21 +654,43 @@ static struct input_handle *evdev_connect(struct input_handler *handler, struct
|
||||||
|
|
||||||
evdev_table[minor] = evdev;
|
evdev_table[minor] = evdev;
|
||||||
|
|
||||||
cdev = class_device_create(&input_class, &dev->cdev,
|
devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
|
||||||
MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
|
|
||||||
|
cdev = class_device_create(&input_class, &dev->cdev, devt,
|
||||||
dev->cdev.dev, evdev->name);
|
dev->cdev.dev, evdev->name);
|
||||||
|
if (IS_ERR(cdev)) {
|
||||||
|
error = PTR_ERR(cdev);
|
||||||
|
goto err_free_evdev;
|
||||||
|
}
|
||||||
|
|
||||||
/* temporary symlink to keep userspace happy */
|
/* temporary symlink to keep userspace happy */
|
||||||
sysfs_create_link(&input_class.subsys.kobj, &cdev->kobj,
|
error = sysfs_create_link(&input_class.subsys.kobj,
|
||||||
evdev->name);
|
&cdev->kobj, evdev->name);
|
||||||
|
if (error)
|
||||||
|
goto err_cdev_destroy;
|
||||||
|
|
||||||
return &evdev->handle;
|
error = input_register_handle(&evdev->handle);
|
||||||
|
if (error)
|
||||||
|
goto err_remove_link;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_remove_link:
|
||||||
|
sysfs_remove_link(&input_class.subsys.kobj, evdev->name);
|
||||||
|
err_cdev_destroy:
|
||||||
|
class_device_destroy(&input_class, devt);
|
||||||
|
err_free_evdev:
|
||||||
|
kfree(evdev);
|
||||||
|
evdev_table[minor] = NULL;
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void evdev_disconnect(struct input_handle *handle)
|
static void evdev_disconnect(struct input_handle *handle)
|
||||||
{
|
{
|
||||||
struct evdev *evdev = handle->private;
|
struct evdev *evdev = handle->private;
|
||||||
struct evdev_list *list;
|
struct evdev_client *client;
|
||||||
|
|
||||||
|
input_unregister_handle(handle);
|
||||||
|
|
||||||
sysfs_remove_link(&input_class.subsys.kobj, evdev->name);
|
sysfs_remove_link(&input_class.subsys.kobj, evdev->name);
|
||||||
class_device_destroy(&input_class,
|
class_device_destroy(&input_class,
|
||||||
|
@ -670,8 +701,8 @@ static void evdev_disconnect(struct input_handle *handle)
|
||||||
input_flush_device(handle, NULL);
|
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(client, &evdev->client_list, node)
|
||||||
kill_fasync(&list->fasync, SIGIO, POLL_HUP);
|
kill_fasync(&client->fasync, SIGIO, POLL_HUP);
|
||||||
} else
|
} else
|
||||||
evdev_free(evdev);
|
evdev_free(evdev);
|
||||||
}
|
}
|
||||||
|
|
|
@ -299,12 +299,87 @@ void input_close_device(struct input_handle *handle)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(input_close_device);
|
EXPORT_SYMBOL(input_close_device);
|
||||||
|
|
||||||
static void input_link_handle(struct input_handle *handle)
|
static int input_fetch_keycode(struct input_dev *dev, int scancode)
|
||||||
{
|
{
|
||||||
list_add_tail(&handle->d_node, &handle->dev->h_list);
|
switch (dev->keycodesize) {
|
||||||
list_add_tail(&handle->h_node, &handle->handler->h_list);
|
case 1:
|
||||||
|
return ((u8 *)dev->keycode)[scancode];
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
return ((u16 *)dev->keycode)[scancode];
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ((u32 *)dev->keycode)[scancode];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int input_default_getkeycode(struct input_dev *dev,
|
||||||
|
int scancode, int *keycode)
|
||||||
|
{
|
||||||
|
if (!dev->keycodesize)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (scancode < 0 || scancode >= dev->keycodemax)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
*keycode = input_fetch_keycode(dev, scancode);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int input_default_setkeycode(struct input_dev *dev,
|
||||||
|
int scancode, int keycode)
|
||||||
|
{
|
||||||
|
int old_keycode;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (scancode < 0 || scancode >= dev->keycodemax)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (keycode < 0 || keycode > KEY_MAX)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!dev->keycodesize)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
switch (dev->keycodesize) {
|
||||||
|
case 1: {
|
||||||
|
u8 *k = (u8 *)dev->keycode;
|
||||||
|
old_keycode = k[scancode];
|
||||||
|
k[scancode] = keycode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2: {
|
||||||
|
u16 *k = (u16 *)dev->keycode;
|
||||||
|
old_keycode = k[scancode];
|
||||||
|
k[scancode] = keycode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
u32 *k = (u32 *)dev->keycode;
|
||||||
|
old_keycode = k[scancode];
|
||||||
|
k[scancode] = keycode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_bit(old_keycode, dev->keybit);
|
||||||
|
set_bit(keycode, dev->keybit);
|
||||||
|
|
||||||
|
for (i = 0; i < dev->keycodemax; i++) {
|
||||||
|
if (input_fetch_keycode(dev, i) == old_keycode) {
|
||||||
|
set_bit(old_keycode, dev->keybit);
|
||||||
|
break; /* Setting the bit twice is useless, so break */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#define MATCH_BIT(bit, max) \
|
#define MATCH_BIT(bit, max) \
|
||||||
for (i = 0; i < NBITS(max); i++) \
|
for (i = 0; i < NBITS(max); i++) \
|
||||||
if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \
|
if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \
|
||||||
|
@ -351,6 +426,29 @@ static const struct input_device_id *input_match_device(const struct input_devic
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
|
||||||
|
{
|
||||||
|
const struct input_device_id *id;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (handler->blacklist && input_match_device(handler->blacklist, dev))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
id = input_match_device(handler->id_table, dev);
|
||||||
|
if (!id)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
error = handler->connect(handler, dev, id);
|
||||||
|
if (error && error != -ENODEV)
|
||||||
|
printk(KERN_ERR
|
||||||
|
"input: failed to attach handler %s to device %s, "
|
||||||
|
"error: %d\n",
|
||||||
|
handler->name, kobject_name(&dev->cdev.kobj), error);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_PROC_FS
|
#ifdef CONFIG_PROC_FS
|
||||||
|
|
||||||
static struct proc_dir_entry *proc_bus_input_dir;
|
static struct proc_dir_entry *proc_bus_input_dir;
|
||||||
|
@ -439,6 +537,7 @@ static int input_devices_seq_show(struct seq_file *seq, void *v)
|
||||||
seq_printf(seq, "N: Name=\"%s\"\n", dev->name ? dev->name : "");
|
seq_printf(seq, "N: Name=\"%s\"\n", dev->name ? dev->name : "");
|
||||||
seq_printf(seq, "P: Phys=%s\n", dev->phys ? dev->phys : "");
|
seq_printf(seq, "P: Phys=%s\n", dev->phys ? dev->phys : "");
|
||||||
seq_printf(seq, "S: Sysfs=%s\n", path ? path : "");
|
seq_printf(seq, "S: Sysfs=%s\n", path ? path : "");
|
||||||
|
seq_printf(seq, "U: Uniq=%s\n", dev->uniq ? dev->uniq : "");
|
||||||
seq_printf(seq, "H: Handlers=");
|
seq_printf(seq, "H: Handlers=");
|
||||||
|
|
||||||
list_for_each_entry(handle, &dev->h_list, d_node)
|
list_for_each_entry(handle, &dev->h_list, d_node)
|
||||||
|
@ -753,6 +852,13 @@ static struct attribute_group input_dev_caps_attr_group = {
|
||||||
.attrs = input_dev_caps_attrs,
|
.attrs = input_dev_caps_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct attribute_group *input_dev_attr_groups[] = {
|
||||||
|
&input_dev_attr_group,
|
||||||
|
&input_dev_id_attr_group,
|
||||||
|
&input_dev_caps_attr_group,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
static void input_dev_release(struct class_device *class_dev)
|
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);
|
||||||
|
@ -906,6 +1012,7 @@ 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->cdev.class = &input_class;
|
dev->cdev.class = &input_class;
|
||||||
|
dev->cdev.groups = input_dev_attr_groups;
|
||||||
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);
|
||||||
|
@ -934,23 +1041,71 @@ EXPORT_SYMBOL(input_allocate_device);
|
||||||
*/
|
*/
|
||||||
void input_free_device(struct input_dev *dev)
|
void input_free_device(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
if (dev) {
|
if (dev)
|
||||||
|
|
||||||
mutex_lock(&dev->mutex);
|
|
||||||
dev->name = dev->phys = dev->uniq = NULL;
|
|
||||||
mutex_unlock(&dev->mutex);
|
|
||||||
|
|
||||||
input_put_device(dev);
|
input_put_device(dev);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(input_free_device);
|
EXPORT_SYMBOL(input_free_device);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* input_set_capability - mark device as capable of a certain event
|
||||||
|
* @dev: device that is capable of emitting or accepting event
|
||||||
|
* @type: type of the event (EV_KEY, EV_REL, etc...)
|
||||||
|
* @code: event code
|
||||||
|
*
|
||||||
|
* In addition to setting up corresponding bit in appropriate capability
|
||||||
|
* bitmap the function also adjusts dev->evbit.
|
||||||
|
*/
|
||||||
|
void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case EV_KEY:
|
||||||
|
__set_bit(code, dev->keybit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_REL:
|
||||||
|
__set_bit(code, dev->relbit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_ABS:
|
||||||
|
__set_bit(code, dev->absbit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_MSC:
|
||||||
|
__set_bit(code, dev->mscbit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_SW:
|
||||||
|
__set_bit(code, dev->swbit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_LED:
|
||||||
|
__set_bit(code, dev->ledbit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_SND:
|
||||||
|
__set_bit(code, dev->sndbit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_FF:
|
||||||
|
__set_bit(code, dev->ffbit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
printk(KERN_ERR
|
||||||
|
"input_set_capability: unknown type %u (code %u)\n",
|
||||||
|
type, code);
|
||||||
|
dump_stack();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
__set_bit(type, dev->evbit);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(input_set_capability);
|
||||||
|
|
||||||
int input_register_device(struct input_dev *dev)
|
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_handler *handler;
|
struct input_handler *handler;
|
||||||
const struct input_device_id *id;
|
|
||||||
const char *path;
|
const char *path;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
@ -969,55 +1124,41 @@ int input_register_device(struct input_dev *dev)
|
||||||
dev->rep[REP_PERIOD] = 33;
|
dev->rep[REP_PERIOD] = 33;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!dev->getkeycode)
|
||||||
|
dev->getkeycode = input_default_getkeycode;
|
||||||
|
|
||||||
|
if (!dev->setkeycode)
|
||||||
|
dev->setkeycode = input_default_setkeycode;
|
||||||
|
|
||||||
list_add_tail(&dev->node, &input_dev_list);
|
list_add_tail(&dev->node, &input_dev_list);
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
if (!dev->cdev.dev)
|
||||||
|
dev->cdev.dev = dev->dev.parent;
|
||||||
|
|
||||||
error = class_device_add(&dev->cdev);
|
error = class_device_add(&dev->cdev);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
error = sysfs_create_group(&dev->cdev.kobj, &input_dev_attr_group);
|
|
||||||
if (error)
|
|
||||||
goto fail1;
|
|
||||||
|
|
||||||
error = sysfs_create_group(&dev->cdev.kobj, &input_dev_id_attr_group);
|
|
||||||
if (error)
|
|
||||||
goto fail2;
|
|
||||||
|
|
||||||
error = sysfs_create_group(&dev->cdev.kobj, &input_dev_caps_attr_group);
|
|
||||||
if (error)
|
|
||||||
goto fail3;
|
|
||||||
|
|
||||||
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");
|
||||||
kfree(path);
|
kfree(path);
|
||||||
|
|
||||||
list_for_each_entry(handler, &input_handler_list, node)
|
list_for_each_entry(handler, &input_handler_list, node)
|
||||||
if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
|
input_attach_handler(dev, handler);
|
||||||
if ((id = input_match_device(handler->id_table, dev)))
|
|
||||||
if ((handle = handler->connect(handler, dev, id))) {
|
|
||||||
input_link_handle(handle);
|
|
||||||
if (handler->start)
|
|
||||||
handler->start(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
input_wakeup_procfs_readers();
|
input_wakeup_procfs_readers();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail3: sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group);
|
|
||||||
fail2: sysfs_remove_group(&dev->cdev.kobj, &input_dev_attr_group);
|
|
||||||
fail1: class_device_del(&dev->cdev);
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(input_register_device);
|
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 input_handle *handle, *next;
|
||||||
int code;
|
int code;
|
||||||
|
|
||||||
for (code = 0; code <= KEY_MAX; code++)
|
for (code = 0; code <= KEY_MAX; code++)
|
||||||
|
@ -1027,19 +1168,12 @@ void input_unregister_device(struct input_dev *dev)
|
||||||
|
|
||||||
del_timer_sync(&dev->timer);
|
del_timer_sync(&dev->timer);
|
||||||
|
|
||||||
list_for_each_safe(node, next, &dev->h_list) {
|
list_for_each_entry_safe(handle, next, &dev->h_list, d_node)
|
||||||
struct input_handle * handle = to_handle(node);
|
|
||||||
list_del_init(&handle->d_node);
|
|
||||||
list_del_init(&handle->h_node);
|
|
||||||
handle->handler->disconnect(handle);
|
handle->handler->disconnect(handle);
|
||||||
}
|
WARN_ON(!list_empty(&dev->h_list));
|
||||||
|
|
||||||
list_del_init(&dev->node);
|
list_del_init(&dev->node);
|
||||||
|
|
||||||
sysfs_remove_group(&dev->cdev.kobj, &input_dev_caps_attr_group);
|
|
||||||
sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group);
|
|
||||||
sysfs_remove_group(&dev->cdev.kobj, &input_dev_attr_group);
|
|
||||||
|
|
||||||
class_device_unregister(&dev->cdev);
|
class_device_unregister(&dev->cdev);
|
||||||
|
|
||||||
input_wakeup_procfs_readers();
|
input_wakeup_procfs_readers();
|
||||||
|
@ -1049,8 +1183,6 @@ EXPORT_SYMBOL(input_unregister_device);
|
||||||
int 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;
|
|
||||||
const struct input_device_id *id;
|
|
||||||
|
|
||||||
INIT_LIST_HEAD(&handler->h_list);
|
INIT_LIST_HEAD(&handler->h_list);
|
||||||
|
|
||||||
|
@ -1064,13 +1196,7 @@ int input_register_handler(struct input_handler *handler)
|
||||||
list_add_tail(&handler->node, &input_handler_list);
|
list_add_tail(&handler->node, &input_handler_list);
|
||||||
|
|
||||||
list_for_each_entry(dev, &input_dev_list, node)
|
list_for_each_entry(dev, &input_dev_list, node)
|
||||||
if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
|
input_attach_handler(dev, handler);
|
||||||
if ((id = input_match_device(handler->id_table, dev)))
|
|
||||||
if ((handle = handler->connect(handler, dev, id))) {
|
|
||||||
input_link_handle(handle);
|
|
||||||
if (handler->start)
|
|
||||||
handler->start(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
input_wakeup_procfs_readers();
|
input_wakeup_procfs_readers();
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1079,14 +1205,11 @@ EXPORT_SYMBOL(input_register_handler);
|
||||||
|
|
||||||
void input_unregister_handler(struct input_handler *handler)
|
void input_unregister_handler(struct input_handler *handler)
|
||||||
{
|
{
|
||||||
struct list_head *node, *next;
|
struct input_handle *handle, *next;
|
||||||
|
|
||||||
list_for_each_safe(node, next, &handler->h_list) {
|
list_for_each_entry_safe(handle, next, &handler->h_list, h_node)
|
||||||
struct input_handle * handle = to_handle_h(node);
|
|
||||||
list_del_init(&handle->h_node);
|
|
||||||
list_del_init(&handle->d_node);
|
|
||||||
handler->disconnect(handle);
|
handler->disconnect(handle);
|
||||||
}
|
WARN_ON(!list_empty(&handler->h_list));
|
||||||
|
|
||||||
list_del_init(&handler->node);
|
list_del_init(&handler->node);
|
||||||
|
|
||||||
|
@ -1097,6 +1220,27 @@ void input_unregister_handler(struct input_handler *handler)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(input_unregister_handler);
|
EXPORT_SYMBOL(input_unregister_handler);
|
||||||
|
|
||||||
|
int input_register_handle(struct input_handle *handle)
|
||||||
|
{
|
||||||
|
struct input_handler *handler = handle->handler;
|
||||||
|
|
||||||
|
list_add_tail(&handle->d_node, &handle->dev->h_list);
|
||||||
|
list_add_tail(&handle->h_node, &handler->h_list);
|
||||||
|
|
||||||
|
if (handler->start)
|
||||||
|
handler->start(handle);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(input_register_handle);
|
||||||
|
|
||||||
|
void input_unregister_handle(struct input_handle *handle)
|
||||||
|
{
|
||||||
|
list_del_init(&handle->h_node);
|
||||||
|
list_del_init(&handle->d_node);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(input_unregister_handle);
|
||||||
|
|
||||||
static int input_open_file(struct inode *inode, struct file *file)
|
static int input_open_file(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct input_handler *handler = input_table[iminor(inode) >> 5];
|
struct input_handler *handler = input_table[iminor(inode) >> 5];
|
||||||
|
|
|
@ -43,7 +43,7 @@ struct joydev {
|
||||||
char name[16];
|
char name[16];
|
||||||
struct input_handle handle;
|
struct input_handle handle;
|
||||||
wait_queue_head_t wait;
|
wait_queue_head_t wait;
|
||||||
struct list_head list;
|
struct list_head client_list;
|
||||||
struct js_corr corr[ABS_MAX + 1];
|
struct js_corr corr[ABS_MAX + 1];
|
||||||
struct JS_DATA_SAVE_TYPE glue;
|
struct JS_DATA_SAVE_TYPE glue;
|
||||||
int nabs;
|
int nabs;
|
||||||
|
@ -55,7 +55,7 @@ struct joydev {
|
||||||
__s16 abs[ABS_MAX + 1];
|
__s16 abs[ABS_MAX + 1];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct joydev_list {
|
struct joydev_client {
|
||||||
struct js_event buffer[JOYDEV_BUFFER_SIZE];
|
struct js_event buffer[JOYDEV_BUFFER_SIZE];
|
||||||
int head;
|
int head;
|
||||||
int tail;
|
int tail;
|
||||||
|
@ -87,7 +87,7 @@ static int joydev_correct(int value, struct js_corr *corr)
|
||||||
static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
|
static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
|
||||||
{
|
{
|
||||||
struct joydev *joydev = handle->private;
|
struct joydev *joydev = handle->private;
|
||||||
struct joydev_list *list;
|
struct joydev_client *client;
|
||||||
struct js_event event;
|
struct js_event event;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -115,15 +115,15 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne
|
||||||
|
|
||||||
event.time = jiffies_to_msecs(jiffies);
|
event.time = jiffies_to_msecs(jiffies);
|
||||||
|
|
||||||
list_for_each_entry(list, &joydev->list, node) {
|
list_for_each_entry(client, &joydev->client_list, node) {
|
||||||
|
|
||||||
memcpy(list->buffer + list->head, &event, sizeof(struct js_event));
|
memcpy(client->buffer + client->head, &event, sizeof(struct js_event));
|
||||||
|
|
||||||
if (list->startup == joydev->nabs + joydev->nkey)
|
if (client->startup == joydev->nabs + joydev->nkey)
|
||||||
if (list->tail == (list->head = (list->head + 1) & (JOYDEV_BUFFER_SIZE - 1)))
|
if (client->tail == (client->head = (client->head + 1) & (JOYDEV_BUFFER_SIZE - 1)))
|
||||||
list->startup = 0;
|
client->startup = 0;
|
||||||
|
|
||||||
kill_fasync(&list->fasync, SIGIO, POLL_IN);
|
kill_fasync(&client->fasync, SIGIO, POLL_IN);
|
||||||
}
|
}
|
||||||
|
|
||||||
wake_up_interruptible(&joydev->wait);
|
wake_up_interruptible(&joydev->wait);
|
||||||
|
@ -132,9 +132,9 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne
|
||||||
static int joydev_fasync(int fd, struct file *file, int on)
|
static int joydev_fasync(int fd, struct file *file, int on)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
struct joydev_list *list = file->private_data;
|
struct joydev_client *client = file->private_data;
|
||||||
|
|
||||||
retval = fasync_helper(fd, file, on, &list->fasync);
|
retval = fasync_helper(fd, file, on, &client->fasync);
|
||||||
|
|
||||||
return retval < 0 ? retval : 0;
|
return retval < 0 ? retval : 0;
|
||||||
}
|
}
|
||||||
|
@ -145,60 +145,73 @@ static void joydev_free(struct joydev *joydev)
|
||||||
kfree(joydev);
|
kfree(joydev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int joydev_release(struct inode * inode, struct file * file)
|
static int joydev_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct joydev_list *list = file->private_data;
|
struct joydev_client *client = file->private_data;
|
||||||
|
struct joydev *joydev = client->joydev;
|
||||||
|
|
||||||
joydev_fasync(-1, file, 0);
|
joydev_fasync(-1, file, 0);
|
||||||
|
|
||||||
list_del(&list->node);
|
list_del(&client->node);
|
||||||
|
kfree(client);
|
||||||
|
|
||||||
if (!--list->joydev->open) {
|
if (!--joydev->open) {
|
||||||
if (list->joydev->exist)
|
if (joydev->exist)
|
||||||
input_close_device(&list->joydev->handle);
|
input_close_device(&joydev->handle);
|
||||||
else
|
else
|
||||||
joydev_free(list->joydev);
|
joydev_free(joydev);
|
||||||
}
|
}
|
||||||
|
|
||||||
kfree(list);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int joydev_open(struct inode *inode, struct file *file)
|
static int joydev_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct joydev_list *list;
|
struct joydev_client *client;
|
||||||
|
struct joydev *joydev;
|
||||||
int i = iminor(inode) - JOYDEV_MINOR_BASE;
|
int i = iminor(inode) - JOYDEV_MINOR_BASE;
|
||||||
|
int error;
|
||||||
|
|
||||||
if (i >= JOYDEV_MINORS || !joydev_table[i])
|
if (i >= JOYDEV_MINORS)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if (!(list = kzalloc(sizeof(struct joydev_list), GFP_KERNEL)))
|
joydev = joydev_table[i];
|
||||||
|
if (!joydev || !joydev->exist)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL);
|
||||||
|
if (!client)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
list->joydev = joydev_table[i];
|
client->joydev = joydev;
|
||||||
list_add_tail(&list->node, &joydev_table[i]->list);
|
list_add_tail(&client->node, &joydev->client_list);
|
||||||
file->private_data = list;
|
|
||||||
|
|
||||||
if (!list->joydev->open++)
|
if (!joydev->open++ && joydev->exist) {
|
||||||
if (list->joydev->exist)
|
error = input_open_device(&joydev->handle);
|
||||||
input_open_device(&list->joydev->handle);
|
if (error) {
|
||||||
|
list_del(&client->node);
|
||||||
|
kfree(client);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file->private_data = client;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t joydev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
|
static ssize_t joydev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
|
||||||
{
|
{
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
|
static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
|
||||||
{
|
{
|
||||||
struct joydev_list *list = file->private_data;
|
struct joydev_client *client = file->private_data;
|
||||||
struct joydev *joydev = list->joydev;
|
struct joydev *joydev = client->joydev;
|
||||||
struct input_dev *input = joydev->handle.dev;
|
struct input_dev *input = joydev->handle.dev;
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
if (!list->joydev->exist)
|
if (!joydev->exist)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if (count < sizeof(struct js_event))
|
if (count < sizeof(struct js_event))
|
||||||
|
@ -217,56 +230,55 @@ static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, lo
|
||||||
if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))
|
if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
list->startup = 0;
|
client->startup = 0;
|
||||||
list->tail = list->head;
|
client->tail = client->head;
|
||||||
|
|
||||||
return sizeof(struct JS_DATA_TYPE);
|
return sizeof(struct JS_DATA_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (list->startup == joydev->nabs + joydev->nkey &&
|
if (client->startup == joydev->nabs + joydev->nkey &&
|
||||||
list->head == list->tail && (file->f_flags & O_NONBLOCK))
|
client->head == client->tail && (file->f_flags & O_NONBLOCK))
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
retval = wait_event_interruptible(list->joydev->wait,
|
retval = wait_event_interruptible(joydev->wait,
|
||||||
!list->joydev->exist ||
|
!joydev->exist ||
|
||||||
list->startup < joydev->nabs + joydev->nkey ||
|
client->startup < joydev->nabs + joydev->nkey ||
|
||||||
list->head != list->tail);
|
client->head != client->tail);
|
||||||
|
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
if (!list->joydev->exist)
|
if (!joydev->exist)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
while (list->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) {
|
while (client->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) {
|
||||||
|
|
||||||
struct js_event event;
|
struct js_event event;
|
||||||
|
|
||||||
event.time = jiffies_to_msecs(jiffies);
|
event.time = jiffies_to_msecs(jiffies);
|
||||||
|
|
||||||
if (list->startup < joydev->nkey) {
|
if (client->startup < joydev->nkey) {
|
||||||
event.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
|
event.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
|
||||||
event.number = list->startup;
|
event.number = client->startup;
|
||||||
event.value = !!test_bit(joydev->keypam[event.number], input->key);
|
event.value = !!test_bit(joydev->keypam[event.number], input->key);
|
||||||
} else {
|
} else {
|
||||||
event.type = JS_EVENT_AXIS | JS_EVENT_INIT;
|
event.type = JS_EVENT_AXIS | JS_EVENT_INIT;
|
||||||
event.number = list->startup - joydev->nkey;
|
event.number = client->startup - joydev->nkey;
|
||||||
event.value = joydev->abs[event.number];
|
event.value = joydev->abs[event.number];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
|
if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
list->startup++;
|
client->startup++;
|
||||||
retval += sizeof(struct js_event);
|
retval += sizeof(struct js_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (list->head != list->tail && retval + sizeof(struct js_event) <= count) {
|
while (client->head != client->tail && retval + sizeof(struct js_event) <= count) {
|
||||||
|
|
||||||
if (copy_to_user(buf + retval, list->buffer + list->tail, sizeof(struct js_event)))
|
if (copy_to_user(buf + retval, client->buffer + client->tail, sizeof(struct js_event)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
list->tail = (list->tail + 1) & (JOYDEV_BUFFER_SIZE - 1);
|
client->tail = (client->tail + 1) & (JOYDEV_BUFFER_SIZE - 1);
|
||||||
retval += sizeof(struct js_event);
|
retval += sizeof(struct js_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,11 +288,12 @@ static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, lo
|
||||||
/* No kernel lock - fine */
|
/* No kernel lock - fine */
|
||||||
static unsigned int joydev_poll(struct file *file, poll_table *wait)
|
static unsigned int joydev_poll(struct file *file, poll_table *wait)
|
||||||
{
|
{
|
||||||
struct joydev_list *list = file->private_data;
|
struct joydev_client *client = file->private_data;
|
||||||
|
struct joydev *joydev = client->joydev;
|
||||||
|
|
||||||
poll_wait(file, &list->joydev->wait, wait);
|
poll_wait(file, &joydev->wait, wait);
|
||||||
return ((list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey) ?
|
return ((client->head != client->tail || client->startup < joydev->nabs + joydev->nkey) ?
|
||||||
(POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR));
|
(POLLIN | POLLRDNORM) : 0) | (joydev->exist ? 0 : (POLLHUP | POLLERR));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp)
|
static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp)
|
||||||
|
@ -374,8 +387,8 @@ static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __u
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
struct joydev_list *list = file->private_data;
|
struct joydev_client *client = file->private_data;
|
||||||
struct joydev *joydev = list->joydev;
|
struct joydev *joydev = client->joydev;
|
||||||
void __user *argp = (void __user *)arg;
|
void __user *argp = (void __user *)arg;
|
||||||
s32 tmp32;
|
s32 tmp32;
|
||||||
struct JS_DATA_SAVE_TYPE_32 ds32;
|
struct JS_DATA_SAVE_TYPE_32 ds32;
|
||||||
|
@ -428,8 +441,8 @@ static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned lo
|
||||||
|
|
||||||
static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
|
static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
struct joydev_list *list = file->private_data;
|
struct joydev_client *client = file->private_data;
|
||||||
struct joydev *joydev = list->joydev;
|
struct joydev *joydev = client->joydev;
|
||||||
void __user *argp = (void __user *)arg;
|
void __user *argp = (void __user *)arg;
|
||||||
|
|
||||||
if (!joydev->exist)
|
if (!joydev->exist)
|
||||||
|
@ -465,23 +478,26 @@ static const 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,
|
static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
|
||||||
const struct input_device_id *id)
|
const struct input_device_id *id)
|
||||||
{
|
{
|
||||||
struct joydev *joydev;
|
struct joydev *joydev;
|
||||||
struct class_device *cdev;
|
struct class_device *cdev;
|
||||||
|
dev_t devt;
|
||||||
int i, j, t, minor;
|
int i, j, t, minor;
|
||||||
|
int error;
|
||||||
|
|
||||||
for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
|
for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
|
||||||
if (minor == JOYDEV_MINORS) {
|
if (minor == JOYDEV_MINORS) {
|
||||||
printk(KERN_ERR "joydev: no more free joydev devices\n");
|
printk(KERN_ERR "joydev: no more free joydev devices\n");
|
||||||
return NULL;
|
return -ENFILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL)))
|
joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL);
|
||||||
return NULL;
|
if (!joydev)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&joydev->list);
|
INIT_LIST_HEAD(&joydev->client_list);
|
||||||
init_waitqueue_head(&joydev->wait);
|
init_waitqueue_head(&joydev->wait);
|
||||||
|
|
||||||
joydev->minor = minor;
|
joydev->minor = minor;
|
||||||
|
@ -534,21 +550,44 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct
|
||||||
|
|
||||||
joydev_table[minor] = joydev;
|
joydev_table[minor] = joydev;
|
||||||
|
|
||||||
cdev = class_device_create(&input_class, &dev->cdev,
|
devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor),
|
||||||
MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor),
|
|
||||||
|
cdev = class_device_create(&input_class, &dev->cdev, devt,
|
||||||
dev->cdev.dev, joydev->name);
|
dev->cdev.dev, joydev->name);
|
||||||
|
if (IS_ERR(cdev)) {
|
||||||
|
error = PTR_ERR(cdev);
|
||||||
|
goto err_free_joydev;
|
||||||
|
}
|
||||||
|
|
||||||
/* temporary symlink to keep userspace happy */
|
/* temporary symlink to keep userspace happy */
|
||||||
sysfs_create_link(&input_class.subsys.kobj, &cdev->kobj,
|
error = sysfs_create_link(&input_class.subsys.kobj,
|
||||||
joydev->name);
|
&cdev->kobj, joydev->name);
|
||||||
|
if (error)
|
||||||
|
goto err_cdev_destroy;
|
||||||
|
|
||||||
return &joydev->handle;
|
error = input_register_handle(&joydev->handle);
|
||||||
|
if (error)
|
||||||
|
goto err_remove_link;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_remove_link:
|
||||||
|
sysfs_remove_link(&input_class.subsys.kobj, joydev->name);
|
||||||
|
err_cdev_destroy:
|
||||||
|
class_device_destroy(&input_class, devt);
|
||||||
|
err_free_joydev:
|
||||||
|
joydev_table[minor] = NULL;
|
||||||
|
kfree(joydev);
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void joydev_disconnect(struct input_handle *handle)
|
static void joydev_disconnect(struct input_handle *handle)
|
||||||
{
|
{
|
||||||
struct joydev *joydev = handle->private;
|
struct joydev *joydev = handle->private;
|
||||||
struct joydev_list *list;
|
struct joydev_client *client;
|
||||||
|
|
||||||
|
input_unregister_handle(handle);
|
||||||
|
|
||||||
sysfs_remove_link(&input_class.subsys.kobj, joydev->name);
|
sysfs_remove_link(&input_class.subsys.kobj, joydev->name);
|
||||||
class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor));
|
class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor));
|
||||||
|
@ -557,8 +596,8 @@ static void joydev_disconnect(struct input_handle *handle)
|
||||||
if (joydev->open) {
|
if (joydev->open) {
|
||||||
input_close_device(handle);
|
input_close_device(handle);
|
||||||
wake_up_interruptible(&joydev->wait);
|
wake_up_interruptible(&joydev->wait);
|
||||||
list_for_each_entry(list, &joydev->list, node)
|
list_for_each_entry(client, &joydev->client_list, node)
|
||||||
kill_fasync(&list->fasync, SIGIO, POLL_HUP);
|
kill_fasync(&client->fasync, SIGIO, POLL_HUP);
|
||||||
} else
|
} else
|
||||||
joydev_free(joydev);
|
joydev_free(joydev);
|
||||||
}
|
}
|
||||||
|
|
|
@ -241,7 +241,7 @@ static void a3d_adc_close(struct gameport *gameport)
|
||||||
|
|
||||||
static int a3d_open(struct input_dev *dev)
|
static int a3d_open(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct a3d *a3d = dev->private;
|
struct a3d *a3d = input_get_drvdata(dev);
|
||||||
|
|
||||||
gameport_start_polling(a3d->gameport);
|
gameport_start_polling(a3d->gameport);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -253,7 +253,7 @@ static int a3d_open(struct input_dev *dev)
|
||||||
|
|
||||||
static void a3d_close(struct input_dev *dev)
|
static void a3d_close(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct a3d *a3d = dev->private;
|
struct a3d *a3d = input_get_drvdata(dev);
|
||||||
|
|
||||||
gameport_stop_polling(a3d->gameport);
|
gameport_stop_polling(a3d->gameport);
|
||||||
}
|
}
|
||||||
|
@ -314,11 +314,12 @@ static int a3d_connect(struct gameport *gameport, struct gameport_driver *drv)
|
||||||
input_dev->id.vendor = GAMEPORT_ID_VENDOR_MADCATZ;
|
input_dev->id.vendor = GAMEPORT_ID_VENDOR_MADCATZ;
|
||||||
input_dev->id.product = a3d->mode;
|
input_dev->id.product = a3d->mode;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &gameport->dev;
|
input_dev->dev.parent = &gameport->dev;
|
||||||
input_dev->private = a3d;
|
|
||||||
input_dev->open = a3d_open;
|
input_dev->open = a3d_open;
|
||||||
input_dev->close = a3d_close;
|
input_dev->close = a3d_close;
|
||||||
|
|
||||||
|
input_set_drvdata(input_dev, a3d);
|
||||||
|
|
||||||
if (a3d->mode == A3D_MODE_PXL) {
|
if (a3d->mode == A3D_MODE_PXL) {
|
||||||
|
|
||||||
int axes[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER };
|
int axes[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER };
|
||||||
|
|
|
@ -290,7 +290,7 @@ static void adi_poll(struct gameport *gameport)
|
||||||
|
|
||||||
static int adi_open(struct input_dev *dev)
|
static int adi_open(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct adi_port *port = dev->private;
|
struct adi_port *port = input_get_drvdata(dev);
|
||||||
|
|
||||||
gameport_start_polling(port->gameport);
|
gameport_start_polling(port->gameport);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -302,7 +302,7 @@ static int adi_open(struct input_dev *dev)
|
||||||
|
|
||||||
static void adi_close(struct input_dev *dev)
|
static void adi_close(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct adi_port *port = dev->private;
|
struct adi_port *port = input_get_drvdata(dev);
|
||||||
|
|
||||||
gameport_stop_polling(port->gameport);
|
gameport_stop_polling(port->gameport);
|
||||||
}
|
}
|
||||||
|
@ -424,8 +424,9 @@ static int adi_init_input(struct adi *adi, struct adi_port *port, int half)
|
||||||
input_dev->id.vendor = GAMEPORT_ID_VENDOR_LOGITECH;
|
input_dev->id.vendor = GAMEPORT_ID_VENDOR_LOGITECH;
|
||||||
input_dev->id.product = adi->id;
|
input_dev->id.product = adi->id;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &port->gameport->dev;
|
input_dev->dev.parent = &port->gameport->dev;
|
||||||
input_dev->private = port;
|
|
||||||
|
input_set_drvdata(input_dev, port);
|
||||||
|
|
||||||
input_dev->open = adi_open;
|
input_dev->open = adi_open;
|
||||||
input_dev->close = adi_close;
|
input_dev->close = adi_close;
|
||||||
|
|
|
@ -343,7 +343,7 @@ static void analog_poll(struct gameport *gameport)
|
||||||
|
|
||||||
static int analog_open(struct input_dev *dev)
|
static int analog_open(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct analog_port *port = dev->private;
|
struct analog_port *port = input_get_drvdata(dev);
|
||||||
|
|
||||||
gameport_start_polling(port->gameport);
|
gameport_start_polling(port->gameport);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -355,7 +355,7 @@ static int analog_open(struct input_dev *dev)
|
||||||
|
|
||||||
static void analog_close(struct input_dev *dev)
|
static void analog_close(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct analog_port *port = dev->private;
|
struct analog_port *port = input_get_drvdata(dev);
|
||||||
|
|
||||||
gameport_stop_polling(port->gameport);
|
gameport_stop_polling(port->gameport);
|
||||||
}
|
}
|
||||||
|
@ -449,10 +449,13 @@ static int analog_init_device(struct analog_port *port, struct analog *analog, i
|
||||||
input_dev->id.vendor = GAMEPORT_ID_VENDOR_ANALOG;
|
input_dev->id.vendor = GAMEPORT_ID_VENDOR_ANALOG;
|
||||||
input_dev->id.product = analog->mask >> 4;
|
input_dev->id.product = analog->mask >> 4;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
|
input_dev->dev.parent = &port->gameport->dev;
|
||||||
|
|
||||||
|
input_set_drvdata(input_dev, port);
|
||||||
|
|
||||||
input_dev->open = analog_open;
|
input_dev->open = analog_open;
|
||||||
input_dev->close = analog_close;
|
input_dev->close = analog_close;
|
||||||
input_dev->private = port;
|
|
||||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||||
|
|
||||||
for (i = j = 0; i < 4; i++)
|
for (i = j = 0; i < 4; i++)
|
||||||
|
|
|
@ -142,7 +142,7 @@ static void cobra_poll(struct gameport *gameport)
|
||||||
|
|
||||||
static int cobra_open(struct input_dev *dev)
|
static int cobra_open(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct cobra *cobra = dev->private;
|
struct cobra *cobra = input_get_drvdata(dev);
|
||||||
|
|
||||||
gameport_start_polling(cobra->gameport);
|
gameport_start_polling(cobra->gameport);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -150,7 +150,7 @@ static int cobra_open(struct input_dev *dev)
|
||||||
|
|
||||||
static void cobra_close(struct input_dev *dev)
|
static void cobra_close(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct cobra *cobra = dev->private;
|
struct cobra *cobra = input_get_drvdata(dev);
|
||||||
|
|
||||||
gameport_stop_polling(cobra->gameport);
|
gameport_stop_polling(cobra->gameport);
|
||||||
}
|
}
|
||||||
|
@ -211,8 +211,9 @@ static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv)
|
||||||
input_dev->id.vendor = GAMEPORT_ID_VENDOR_CREATIVE;
|
input_dev->id.vendor = GAMEPORT_ID_VENDOR_CREATIVE;
|
||||||
input_dev->id.product = 0x0008;
|
input_dev->id.product = 0x0008;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &gameport->dev;
|
input_dev->dev.parent = &gameport->dev;
|
||||||
input_dev->private = cobra;
|
|
||||||
|
input_set_drvdata(input_dev, cobra);
|
||||||
|
|
||||||
input_dev->open = cobra_open;
|
input_dev->open = cobra_open;
|
||||||
input_dev->close = cobra_close;
|
input_dev->close = cobra_close;
|
||||||
|
|
|
@ -518,7 +518,7 @@ static void db9_timer(unsigned long private)
|
||||||
|
|
||||||
static int db9_open(struct input_dev *dev)
|
static int db9_open(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct db9 *db9 = dev->private;
|
struct db9 *db9 = input_get_drvdata(dev);
|
||||||
struct parport *port = db9->pd->port;
|
struct parport *port = db9->pd->port;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
@ -542,7 +542,7 @@ static int db9_open(struct input_dev *dev)
|
||||||
|
|
||||||
static void db9_close(struct input_dev *dev)
|
static void db9_close(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct db9 *db9 = dev->private;
|
struct db9 *db9 = input_get_drvdata(dev);
|
||||||
struct parport *port = db9->pd->port;
|
struct parport *port = db9->pd->port;
|
||||||
|
|
||||||
mutex_lock(&db9->mutex);
|
mutex_lock(&db9->mutex);
|
||||||
|
@ -625,7 +625,8 @@ static struct db9 __init *db9_probe(int parport, int mode)
|
||||||
input_dev->id.vendor = 0x0002;
|
input_dev->id.vendor = 0x0002;
|
||||||
input_dev->id.product = mode;
|
input_dev->id.product = mode;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->private = db9;
|
|
||||||
|
input_set_drvdata(input_dev, db9);
|
||||||
|
|
||||||
input_dev->open = db9_open;
|
input_dev->open = db9_open;
|
||||||
input_dev->close = db9_close;
|
input_dev->close = db9_close;
|
||||||
|
|
|
@ -591,7 +591,7 @@ static void gc_timer(unsigned long private)
|
||||||
|
|
||||||
static int gc_open(struct input_dev *dev)
|
static int gc_open(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct gc *gc = dev->private;
|
struct gc *gc = input_get_drvdata(dev);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = mutex_lock_interruptible(&gc->mutex);
|
err = mutex_lock_interruptible(&gc->mutex);
|
||||||
|
@ -610,7 +610,7 @@ static int gc_open(struct input_dev *dev)
|
||||||
|
|
||||||
static void gc_close(struct input_dev *dev)
|
static void gc_close(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct gc *gc = dev->private;
|
struct gc *gc = input_get_drvdata(dev);
|
||||||
|
|
||||||
mutex_lock(&gc->mutex);
|
mutex_lock(&gc->mutex);
|
||||||
if (!--gc->used) {
|
if (!--gc->used) {
|
||||||
|
@ -646,7 +646,8 @@ static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type)
|
||||||
input_dev->id.vendor = 0x0001;
|
input_dev->id.vendor = 0x0001;
|
||||||
input_dev->id.product = pad_type;
|
input_dev->id.product = pad_type;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->private = gc;
|
|
||||||
|
input_set_drvdata(input_dev, gc);
|
||||||
|
|
||||||
input_dev->open = gc_open;
|
input_dev->open = gc_open;
|
||||||
input_dev->close = gc_close;
|
input_dev->close = gc_close;
|
||||||
|
|
|
@ -220,7 +220,7 @@ static void gf2k_poll(struct gameport *gameport)
|
||||||
|
|
||||||
static int gf2k_open(struct input_dev *dev)
|
static int gf2k_open(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct gf2k *gf2k = dev->private;
|
struct gf2k *gf2k = input_get_drvdata(dev);
|
||||||
|
|
||||||
gameport_start_polling(gf2k->gameport);
|
gameport_start_polling(gf2k->gameport);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -228,7 +228,7 @@ static int gf2k_open(struct input_dev *dev)
|
||||||
|
|
||||||
static void gf2k_close(struct input_dev *dev)
|
static void gf2k_close(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct gf2k *gf2k = dev->private;
|
struct gf2k *gf2k = input_get_drvdata(dev);
|
||||||
|
|
||||||
gameport_stop_polling(gf2k->gameport);
|
gameport_stop_polling(gf2k->gameport);
|
||||||
}
|
}
|
||||||
|
@ -308,11 +308,13 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv)
|
||||||
input_dev->id.vendor = GAMEPORT_ID_VENDOR_GENIUS;
|
input_dev->id.vendor = GAMEPORT_ID_VENDOR_GENIUS;
|
||||||
input_dev->id.product = gf2k->id;
|
input_dev->id.product = gf2k->id;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &gameport->dev;
|
input_dev->dev.parent = &gameport->dev;
|
||||||
input_dev->private = gf2k;
|
|
||||||
|
input_set_drvdata(input_dev, gf2k);
|
||||||
|
|
||||||
input_dev->open = gf2k_open;
|
input_dev->open = gf2k_open;
|
||||||
input_dev->close = gf2k_close;
|
input_dev->close = gf2k_close;
|
||||||
|
|
||||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||||
|
|
||||||
for (i = 0; i < gf2k_axes[gf2k->id]; i++)
|
for (i = 0; i < gf2k_axes[gf2k->id]; i++)
|
||||||
|
|
|
@ -285,7 +285,7 @@ static void grip_poll(struct gameport *gameport)
|
||||||
|
|
||||||
static int grip_open(struct input_dev *dev)
|
static int grip_open(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct grip *grip = dev->private;
|
struct grip *grip = input_get_drvdata(dev);
|
||||||
|
|
||||||
gameport_start_polling(grip->gameport);
|
gameport_start_polling(grip->gameport);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -293,7 +293,7 @@ static int grip_open(struct input_dev *dev)
|
||||||
|
|
||||||
static void grip_close(struct input_dev *dev)
|
static void grip_close(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct grip *grip = dev->private;
|
struct grip *grip = input_get_drvdata(dev);
|
||||||
|
|
||||||
gameport_stop_polling(grip->gameport);
|
gameport_stop_polling(grip->gameport);
|
||||||
}
|
}
|
||||||
|
@ -363,8 +363,9 @@ static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
|
||||||
input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS;
|
input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS;
|
||||||
input_dev->id.product = grip->mode[i];
|
input_dev->id.product = grip->mode[i];
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &gameport->dev;
|
input_dev->dev.parent = &gameport->dev;
|
||||||
input_dev->private = grip;
|
|
||||||
|
input_set_drvdata(input_dev, grip);
|
||||||
|
|
||||||
input_dev->open = grip_open;
|
input_dev->open = grip_open;
|
||||||
input_dev->close = grip_close;
|
input_dev->close = grip_close;
|
||||||
|
|
|
@ -562,7 +562,7 @@ static void grip_poll(struct gameport *gameport)
|
||||||
|
|
||||||
static int grip_open(struct input_dev *dev)
|
static int grip_open(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct grip_mp *grip = dev->private;
|
struct grip_mp *grip = input_get_drvdata(dev);
|
||||||
|
|
||||||
gameport_start_polling(grip->gameport);
|
gameport_start_polling(grip->gameport);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -574,9 +574,9 @@ static int grip_open(struct input_dev *dev)
|
||||||
|
|
||||||
static void grip_close(struct input_dev *dev)
|
static void grip_close(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct grip_mp *grip = dev->private;
|
struct grip_mp *grip = input_get_drvdata(dev);
|
||||||
|
|
||||||
gameport_start_polling(grip->gameport);
|
gameport_stop_polling(grip->gameport);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -599,8 +599,9 @@ static int register_slot(int slot, struct grip_mp *grip)
|
||||||
input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS;
|
input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS;
|
||||||
input_dev->id.product = 0x0100 + port->mode;
|
input_dev->id.product = 0x0100 + port->mode;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &grip->gameport->dev;
|
input_dev->dev.parent = &grip->gameport->dev;
|
||||||
input_dev->private = grip;
|
|
||||||
|
input_set_drvdata(input_dev, grip);
|
||||||
|
|
||||||
input_dev->open = grip_open;
|
input_dev->open = grip_open;
|
||||||
input_dev->close = grip_close;
|
input_dev->close = grip_close;
|
||||||
|
|
|
@ -156,7 +156,7 @@ static void guillemot_poll(struct gameport *gameport)
|
||||||
|
|
||||||
static int guillemot_open(struct input_dev *dev)
|
static int guillemot_open(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct guillemot *guillemot = dev->private;
|
struct guillemot *guillemot = input_get_drvdata(dev);
|
||||||
|
|
||||||
gameport_start_polling(guillemot->gameport);
|
gameport_start_polling(guillemot->gameport);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -168,7 +168,7 @@ static int guillemot_open(struct input_dev *dev)
|
||||||
|
|
||||||
static void guillemot_close(struct input_dev *dev)
|
static void guillemot_close(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct guillemot *guillemot = dev->private;
|
struct guillemot *guillemot = input_get_drvdata(dev);
|
||||||
|
|
||||||
gameport_stop_polling(guillemot->gameport);
|
gameport_stop_polling(guillemot->gameport);
|
||||||
}
|
}
|
||||||
|
@ -231,8 +231,9 @@ static int guillemot_connect(struct gameport *gameport, struct gameport_driver *
|
||||||
input_dev->id.vendor = GAMEPORT_ID_VENDOR_GUILLEMOT;
|
input_dev->id.vendor = GAMEPORT_ID_VENDOR_GUILLEMOT;
|
||||||
input_dev->id.product = guillemot_type[i].id;
|
input_dev->id.product = guillemot_type[i].id;
|
||||||
input_dev->id.version = (int)data[14] << 8 | data[15];
|
input_dev->id.version = (int)data[14] << 8 | data[15];
|
||||||
input_dev->cdev.dev = &gameport->dev;
|
input_dev->dev.parent = &gameport->dev;
|
||||||
input_dev->private = guillemot;
|
|
||||||
|
input_set_drvdata(input_dev, guillemot);
|
||||||
|
|
||||||
input_dev->open = guillemot_open;
|
input_dev->open = guillemot_open;
|
||||||
input_dev->close = guillemot_close;
|
input_dev->close = guillemot_close;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* $Id: iforce-ff.c,v 1.9 2002/02/02 19:28:35 jdeneux Exp $
|
* $Id: iforce-ff.c,v 1.9 2002/02/02 19:28:35 jdeneux Exp $
|
||||||
*
|
*
|
||||||
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
|
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
|
||||||
* Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
|
* Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com>
|
||||||
*
|
*
|
||||||
* USB/RS232 I-Force joysticks and wheels.
|
* USB/RS232 I-Force joysticks and wheels.
|
||||||
*/
|
*/
|
||||||
|
@ -205,7 +205,7 @@ static int need_condition_modifier(struct ff_effect *old, struct ff_effect *new)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (new->type != FF_SPRING && new->type != FF_FRICTION) {
|
if (new->type != FF_SPRING && new->type != FF_FRICTION) {
|
||||||
printk(KERN_WARNING "iforce.c: bad effect type in need_condition_modifier\n");
|
warn("bad effect type in need_condition_modifier");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,7 +227,7 @@ static int need_condition_modifier(struct ff_effect *old, struct ff_effect *new)
|
||||||
static int need_magnitude_modifier(struct ff_effect *old, struct ff_effect *effect)
|
static int need_magnitude_modifier(struct ff_effect *old, struct ff_effect *effect)
|
||||||
{
|
{
|
||||||
if (effect->type != FF_CONSTANT) {
|
if (effect->type != FF_CONSTANT) {
|
||||||
printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n");
|
warn("bad effect type in need_envelope_modifier");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,7 +258,7 @@ static int need_envelope_modifier(struct ff_effect *old, struct ff_effect *effec
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n");
|
warn("bad effect type in need_envelope_modifier");
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -271,7 +271,7 @@ static int need_envelope_modifier(struct ff_effect *old, struct ff_effect *effec
|
||||||
static int need_period_modifier(struct ff_effect *old, struct ff_effect *new)
|
static int need_period_modifier(struct ff_effect *old, struct ff_effect *new)
|
||||||
{
|
{
|
||||||
if (new->type != FF_PERIODIC) {
|
if (new->type != FF_PERIODIC) {
|
||||||
printk(KERN_WARNING "iforce.c: bad effect type in need_period_modifier\n");
|
warn("bad effect type in need_period_modifier");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return (old->u.periodic.period != new->u.periodic.period
|
return (old->u.periodic.period != new->u.periodic.period
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* $Id: iforce-main.c,v 1.19 2002/07/07 10:22:50 jdeneux Exp $
|
* $Id: iforce-main.c,v 1.19 2002/07/07 10:22:50 jdeneux Exp $
|
||||||
*
|
*
|
||||||
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
|
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
|
||||||
* Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
|
* Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com>
|
||||||
*
|
*
|
||||||
* USB/RS232 I-Force joysticks and wheels.
|
* USB/RS232 I-Force joysticks and wheels.
|
||||||
*/
|
*/
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
#include "iforce.h"
|
#include "iforce.h"
|
||||||
|
|
||||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <deneux@ifrance.com>");
|
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>");
|
||||||
MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver");
|
MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
|
@ -220,7 +220,7 @@ static void iforce_release(struct input_dev *dev)
|
||||||
/* Check: no effects should be present in memory */
|
/* Check: no effects should be present in memory */
|
||||||
for (i = 0; i < dev->ff->max_effects; i++) {
|
for (i = 0; i < 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)) {
|
||||||
printk(KERN_WARNING "iforce_release: Device still owns effects\n");
|
warn("iforce_release: Device still owns effects");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,7 +232,7 @@ static void iforce_release(struct input_dev *dev)
|
||||||
switch (iforce->bus) {
|
switch (iforce->bus) {
|
||||||
#ifdef CONFIG_JOYSTICK_IFORCE_USB
|
#ifdef CONFIG_JOYSTICK_IFORCE_USB
|
||||||
case IFORCE_USB:
|
case IFORCE_USB:
|
||||||
usb_unlink_urb(iforce->irq);
|
usb_kill_urb(iforce->irq);
|
||||||
|
|
||||||
/* The device was unplugged before the file
|
/* The device was unplugged before the file
|
||||||
* was released */
|
* was released */
|
||||||
|
@ -287,13 +287,13 @@ int iforce_init_device(struct iforce *iforce)
|
||||||
#ifdef CONFIG_JOYSTICK_IFORCE_USB
|
#ifdef CONFIG_JOYSTICK_IFORCE_USB
|
||||||
case IFORCE_USB:
|
case IFORCE_USB:
|
||||||
input_dev->id.bustype = BUS_USB;
|
input_dev->id.bustype = BUS_USB;
|
||||||
input_dev->cdev.dev = &iforce->usbdev->dev;
|
input_dev->dev.parent = &iforce->usbdev->dev;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_JOYSTICK_IFORCE_232
|
#ifdef CONFIG_JOYSTICK_IFORCE_232
|
||||||
case IFORCE_232:
|
case IFORCE_232:
|
||||||
input_dev->id.bustype = BUS_RS232;
|
input_dev->id.bustype = BUS_RS232;
|
||||||
input_dev->cdev.dev = &iforce->serio->dev;
|
input_dev->dev.parent = &iforce->serio->dev;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -324,7 +324,7 @@ int iforce_init_device(struct iforce *iforce)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (i == 20) { /* 5 seconds */
|
if (i == 20) { /* 5 seconds */
|
||||||
printk(KERN_ERR "iforce-main.c: Timeout waiting for response from device.\n");
|
err("Timeout waiting for response from device.");
|
||||||
error = -ENODEV;
|
error = -ENODEV;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -336,26 +336,26 @@ int iforce_init_device(struct iforce *iforce)
|
||||||
if (!iforce_get_id_packet(iforce, "M"))
|
if (!iforce_get_id_packet(iforce, "M"))
|
||||||
input_dev->id.vendor = (iforce->edata[2] << 8) | iforce->edata[1];
|
input_dev->id.vendor = (iforce->edata[2] << 8) | iforce->edata[1];
|
||||||
else
|
else
|
||||||
printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet M\n");
|
warn("Device does not respond to id packet M");
|
||||||
|
|
||||||
if (!iforce_get_id_packet(iforce, "P"))
|
if (!iforce_get_id_packet(iforce, "P"))
|
||||||
input_dev->id.product = (iforce->edata[2] << 8) | iforce->edata[1];
|
input_dev->id.product = (iforce->edata[2] << 8) | iforce->edata[1];
|
||||||
else
|
else
|
||||||
printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet P\n");
|
warn("Device does not respond to id packet P");
|
||||||
|
|
||||||
if (!iforce_get_id_packet(iforce, "B"))
|
if (!iforce_get_id_packet(iforce, "B"))
|
||||||
iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1];
|
iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1];
|
||||||
else
|
else
|
||||||
printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet B\n");
|
warn("Device does not respond to id packet B");
|
||||||
|
|
||||||
if (!iforce_get_id_packet(iforce, "N"))
|
if (!iforce_get_id_packet(iforce, "N"))
|
||||||
ff_effects = 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");
|
warn("Device does not respond to id packet 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 (ff_effects > IFORCE_EFFECTS_MAX) {
|
if (ff_effects > IFORCE_EFFECTS_MAX) {
|
||||||
printk(KERN_WARNING "iforce: Limiting number of effects to %d (device reports %d)\n",
|
warn("Limiting number of effects to %d (device reports %d)",
|
||||||
IFORCE_EFFECTS_MAX, ff_effects);
|
IFORCE_EFFECTS_MAX, ff_effects);
|
||||||
ff_effects = IFORCE_EFFECTS_MAX;
|
ff_effects = IFORCE_EFFECTS_MAX;
|
||||||
}
|
}
|
||||||
|
@ -457,8 +457,6 @@ int iforce_init_device(struct iforce *iforce)
|
||||||
if (error)
|
if (error)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
printk(KERN_DEBUG "iforce->dev->open = %p\n", iforce->dev->open);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail: input_free_device(input_dev);
|
fail: input_free_device(input_dev);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* $Id: iforce-packets.c,v 1.16 2002/07/07 10:22:50 jdeneux Exp $
|
* $Id: iforce-packets.c,v 1.16 2002/07/07 10:22:50 jdeneux Exp $
|
||||||
*
|
*
|
||||||
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
|
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
|
||||||
* Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
|
* Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com>
|
||||||
*
|
*
|
||||||
* USB/RS232 I-Force joysticks and wheels.
|
* USB/RS232 I-Force joysticks and wheels.
|
||||||
*/
|
*/
|
||||||
|
@ -39,10 +39,10 @@ void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
printk(KERN_DEBUG "iforce.c: %s ( cmd = %04x, data = ", msg, cmd);
|
printk(KERN_DEBUG __FILE__ ": %s cmd = %04x, data = ", msg, cmd);
|
||||||
for (i = 0; i < LO(cmd); i++)
|
for (i = 0; i < LO(cmd); i++)
|
||||||
printk("%02x ", data[i]);
|
printk("%02x ", data[i]);
|
||||||
printk(")\n");
|
printk("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -65,8 +65,9 @@ int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data)
|
||||||
head = iforce->xmit.head;
|
head = iforce->xmit.head;
|
||||||
tail = iforce->xmit.tail;
|
tail = iforce->xmit.tail;
|
||||||
|
|
||||||
|
|
||||||
if (CIRC_SPACE(head, tail, XMIT_SIZE) < n+2) {
|
if (CIRC_SPACE(head, tail, XMIT_SIZE) < n+2) {
|
||||||
printk(KERN_WARNING "iforce.c: not enough space in xmit buffer to send new packet\n");
|
warn("not enough space in xmit buffer to send new packet");
|
||||||
spin_unlock_irqrestore(&iforce->xmit_lock, flags);
|
spin_unlock_irqrestore(&iforce->xmit_lock, flags);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -126,8 +127,6 @@ int iforce_control_playback(struct iforce* iforce, u16 id, unsigned int value)
|
||||||
{
|
{
|
||||||
unsigned char data[3];
|
unsigned char data[3];
|
||||||
|
|
||||||
printk(KERN_DEBUG "iforce-packets.c: control_playback %d %d\n", id, value);
|
|
||||||
|
|
||||||
data[0] = LO(id);
|
data[0] = LO(id);
|
||||||
data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0;
|
data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0;
|
||||||
data[2] = LO(value);
|
data[2] = LO(value);
|
||||||
|
@ -151,7 +150,7 @@ static int mark_core_as_ready(struct iforce *iforce, unsigned short addr)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printk(KERN_WARNING "iforce-packets.c: unused effect %04x updated !!!\n", addr);
|
warn("unused effect %04x updated !!!", addr);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +161,7 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data)
|
||||||
static int being_used = 0;
|
static int being_used = 0;
|
||||||
|
|
||||||
if (being_used)
|
if (being_used)
|
||||||
printk(KERN_WARNING "iforce-packets.c: re-entrant call to iforce_process %d\n", being_used);
|
warn("re-entrant call to iforce_process %d", being_used);
|
||||||
being_used++;
|
being_used++;
|
||||||
|
|
||||||
#ifdef CONFIG_JOYSTICK_IFORCE_232
|
#ifdef CONFIG_JOYSTICK_IFORCE_232
|
||||||
|
@ -266,7 +265,7 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
printk(KERN_ERR "iforce_get_id_packet: iforce->bus = USB!\n");
|
err("iforce_get_id_packet: iforce->bus = USB!");
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -284,13 +283,12 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
printk(KERN_ERR "iforce_get_id_packet: iforce->bus = SERIO!\n");
|
err("iforce_get_id_packet: iforce->bus = SERIO!");
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printk(KERN_ERR "iforce_get_id_packet: iforce->bus = %d\n",
|
err("iforce_get_id_packet: iforce->bus = %d", iforce->bus);
|
||||||
iforce->bus);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* $Id: iforce-serio.c,v 1.4 2002/01/28 22:45:00 jdeneux Exp $
|
* $Id: iforce-serio.c,v 1.4 2002/01/28 22:45:00 jdeneux Exp $
|
||||||
*
|
*
|
||||||
* Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz>
|
* Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz>
|
||||||
* Copyright (c) 2001 Johann Deneux <deneux@ifrance.com>
|
* Copyright (c) 2001, 2007 Johann Deneux <johann.deneux@gmail.com>
|
||||||
*
|
*
|
||||||
* USB/RS232 I-Force joysticks and wheels.
|
* USB/RS232 I-Force joysticks and wheels.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* $Id: iforce-usb.c,v 1.16 2002/06/09 11:08:04 jdeneux Exp $
|
* $Id: iforce-usb.c,v 1.16 2002/06/09 11:08:04 jdeneux Exp $
|
||||||
*
|
*
|
||||||
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
|
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
|
||||||
* Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
|
* Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com>
|
||||||
*
|
*
|
||||||
* USB/RS232 I-Force joysticks and wheels.
|
* USB/RS232 I-Force joysticks and wheels.
|
||||||
*/
|
*/
|
||||||
|
@ -65,7 +65,7 @@ void iforce_usb_xmit(struct iforce *iforce)
|
||||||
XMIT_INC(iforce->xmit.tail, n);
|
XMIT_INC(iforce->xmit.tail, n);
|
||||||
|
|
||||||
if ( (n=usb_submit_urb(iforce->out, GFP_ATOMIC)) ) {
|
if ( (n=usb_submit_urb(iforce->out, GFP_ATOMIC)) ) {
|
||||||
printk(KERN_WARNING "iforce-usb.c: iforce_usb_xmit: usb_submit_urb failed %d\n", n);
|
warn("usb_submit_urb failed %d\n", n);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended.
|
/* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended.
|
||||||
|
@ -110,7 +110,7 @@ static void iforce_usb_out(struct urb *urb)
|
||||||
struct iforce *iforce = urb->context;
|
struct iforce *iforce = urb->context;
|
||||||
|
|
||||||
if (urb->status) {
|
if (urb->status) {
|
||||||
printk(KERN_DEBUG "iforce_usb_out: urb->status %d, exiting", urb->status);
|
dbg("urb->status %d, exiting", urb->status);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,10 +190,9 @@ fail:
|
||||||
/* Called by iforce_delete() */
|
/* Called by iforce_delete() */
|
||||||
void iforce_usb_delete(struct iforce* iforce)
|
void iforce_usb_delete(struct iforce* iforce)
|
||||||
{
|
{
|
||||||
usb_unlink_urb(iforce->irq);
|
usb_kill_urb(iforce->irq);
|
||||||
/* Is it ok to unlink those ? */
|
usb_kill_urb(iforce->out);
|
||||||
usb_unlink_urb(iforce->out);
|
usb_kill_urb(iforce->ctrl);
|
||||||
usb_unlink_urb(iforce->ctrl);
|
|
||||||
|
|
||||||
usb_free_urb(iforce->irq);
|
usb_free_urb(iforce->irq);
|
||||||
usb_free_urb(iforce->out);
|
usb_free_urb(iforce->out);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* $Id: iforce.h,v 1.13 2002/07/07 10:22:50 jdeneux Exp $
|
* $Id: iforce.h,v 1.13 2002/07/07 10:22:50 jdeneux Exp $
|
||||||
*
|
*
|
||||||
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
|
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
|
||||||
* Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
|
* Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com>
|
||||||
*
|
*
|
||||||
* USB/RS232 I-Force joysticks and wheels.
|
* USB/RS232 I-Force joysticks and wheels.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -185,7 +185,7 @@ static void interact_poll(struct gameport *gameport)
|
||||||
|
|
||||||
static int interact_open(struct input_dev *dev)
|
static int interact_open(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct interact *interact = dev->private;
|
struct interact *interact = input_get_drvdata(dev);
|
||||||
|
|
||||||
gameport_start_polling(interact->gameport);
|
gameport_start_polling(interact->gameport);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -197,7 +197,7 @@ static int interact_open(struct input_dev *dev)
|
||||||
|
|
||||||
static void interact_close(struct input_dev *dev)
|
static void interact_close(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct interact *interact = dev->private;
|
struct interact *interact = input_get_drvdata(dev);
|
||||||
|
|
||||||
gameport_stop_polling(interact->gameport);
|
gameport_stop_polling(interact->gameport);
|
||||||
}
|
}
|
||||||
|
@ -262,7 +262,9 @@ static int interact_connect(struct gameport *gameport, struct gameport_driver *d
|
||||||
input_dev->id.vendor = GAMEPORT_ID_VENDOR_INTERACT;
|
input_dev->id.vendor = GAMEPORT_ID_VENDOR_INTERACT;
|
||||||
input_dev->id.product = interact_type[i].id;
|
input_dev->id.product = interact_type[i].id;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->private = interact;
|
input_dev->dev.parent = &gameport->dev;
|
||||||
|
|
||||||
|
input_set_drvdata(input_dev, interact);
|
||||||
|
|
||||||
input_dev->open = interact_open;
|
input_dev->open = interact_open;
|
||||||
input_dev->close = interact_close;
|
input_dev->close = interact_close;
|
||||||
|
|
|
@ -168,8 +168,7 @@ static int magellan_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
input_dev->id.vendor = SERIO_MAGELLAN;
|
input_dev->id.vendor = SERIO_MAGELLAN;
|
||||||
input_dev->id.product = 0x0001;
|
input_dev->id.product = 0x0001;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &serio->dev;
|
input_dev->dev.parent = &serio->dev;
|
||||||
input_dev->private = magellan;
|
|
||||||
|
|
||||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||||
|
|
||||||
|
|
|
@ -509,7 +509,7 @@ static void sw_poll(struct gameport *gameport)
|
||||||
|
|
||||||
static int sw_open(struct input_dev *dev)
|
static int sw_open(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct sw *sw = dev->private;
|
struct sw *sw = input_get_drvdata(dev);
|
||||||
|
|
||||||
gameport_start_polling(sw->gameport);
|
gameport_start_polling(sw->gameport);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -517,7 +517,7 @@ static int sw_open(struct input_dev *dev)
|
||||||
|
|
||||||
static void sw_close(struct input_dev *dev)
|
static void sw_close(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct sw *sw = dev->private;
|
struct sw *sw = input_get_drvdata(dev);
|
||||||
|
|
||||||
gameport_stop_polling(sw->gameport);
|
gameport_stop_polling(sw->gameport);
|
||||||
}
|
}
|
||||||
|
@ -751,8 +751,9 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
|
||||||
input_dev->id.vendor = GAMEPORT_ID_VENDOR_MICROSOFT;
|
input_dev->id.vendor = GAMEPORT_ID_VENDOR_MICROSOFT;
|
||||||
input_dev->id.product = sw->type;
|
input_dev->id.product = sw->type;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &gameport->dev;
|
input_dev->dev.parent = &gameport->dev;
|
||||||
input_dev->private = sw;
|
|
||||||
|
input_set_drvdata(input_dev, sw);
|
||||||
|
|
||||||
input_dev->open = sw_open;
|
input_dev->open = sw_open;
|
||||||
input_dev->close = sw_close;
|
input_dev->close = sw_close;
|
||||||
|
|
|
@ -226,8 +226,7 @@ static int spaceball_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
input_dev->id.vendor = SERIO_SPACEBALL;
|
input_dev->id.vendor = SERIO_SPACEBALL;
|
||||||
input_dev->id.product = id;
|
input_dev->id.product = id;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &serio->dev;
|
input_dev->dev.parent = &serio->dev;
|
||||||
input_dev->private = spaceball;
|
|
||||||
|
|
||||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||||
|
|
||||||
|
|
|
@ -183,8 +183,7 @@ static int spaceorb_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
input_dev->id.vendor = SERIO_SPACEORB;
|
input_dev->id.vendor = SERIO_SPACEORB;
|
||||||
input_dev->id.product = 0x0001;
|
input_dev->id.product = 0x0001;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &serio->dev;
|
input_dev->dev.parent = &serio->dev;
|
||||||
input_dev->private = spaceorb;
|
|
||||||
|
|
||||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||||
|
|
||||||
|
|
|
@ -154,8 +154,7 @@ static int stinger_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
input_dev->id.vendor = SERIO_STINGER;
|
input_dev->id.vendor = SERIO_STINGER;
|
||||||
input_dev->id.product = 0x0001;
|
input_dev->id.product = 0x0001;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &serio->dev;
|
input_dev->dev.parent = &serio->dev;
|
||||||
input_dev->private = stinger;
|
|
||||||
|
|
||||||
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_A)] = BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_X) |
|
input_dev->keybit[LONG(BTN_A)] = BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_X) |
|
||||||
|
|
|
@ -265,7 +265,7 @@ static void tmdc_poll(struct gameport *gameport)
|
||||||
|
|
||||||
static int tmdc_open(struct input_dev *dev)
|
static int tmdc_open(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct tmdc *tmdc = dev->private;
|
struct tmdc *tmdc = input_get_drvdata(dev);
|
||||||
|
|
||||||
gameport_start_polling(tmdc->gameport);
|
gameport_start_polling(tmdc->gameport);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -273,7 +273,7 @@ static int tmdc_open(struct input_dev *dev)
|
||||||
|
|
||||||
static void tmdc_close(struct input_dev *dev)
|
static void tmdc_close(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct tmdc *tmdc = dev->private;
|
struct tmdc *tmdc = input_get_drvdata(dev);
|
||||||
|
|
||||||
gameport_stop_polling(tmdc->gameport);
|
gameport_stop_polling(tmdc->gameport);
|
||||||
}
|
}
|
||||||
|
@ -326,8 +326,9 @@ static int tmdc_setup_port(struct tmdc *tmdc, int idx, unsigned char *data)
|
||||||
input_dev->id.vendor = GAMEPORT_ID_VENDOR_THRUSTMASTER;
|
input_dev->id.vendor = GAMEPORT_ID_VENDOR_THRUSTMASTER;
|
||||||
input_dev->id.product = model->id;
|
input_dev->id.product = model->id;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &tmdc->gameport->dev;
|
input_dev->dev.parent = &tmdc->gameport->dev;
|
||||||
input_dev->private = tmdc;
|
|
||||||
|
input_set_drvdata(input_dev, tmdc);
|
||||||
|
|
||||||
input_dev->open = tmdc_open;
|
input_dev->open = tmdc_open;
|
||||||
input_dev->close = tmdc_close;
|
input_dev->close = tmdc_close;
|
||||||
|
|
|
@ -122,7 +122,7 @@ static void tgfx_timer(unsigned long private)
|
||||||
|
|
||||||
static int tgfx_open(struct input_dev *dev)
|
static int tgfx_open(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct tgfx *tgfx = dev->private;
|
struct tgfx *tgfx = input_get_drvdata(dev);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = mutex_lock_interruptible(&tgfx->sem);
|
err = mutex_lock_interruptible(&tgfx->sem);
|
||||||
|
@ -141,7 +141,7 @@ static int tgfx_open(struct input_dev *dev)
|
||||||
|
|
||||||
static void tgfx_close(struct input_dev *dev)
|
static void tgfx_close(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct tgfx *tgfx = dev->private;
|
struct tgfx *tgfx = input_get_drvdata(dev);
|
||||||
|
|
||||||
mutex_lock(&tgfx->sem);
|
mutex_lock(&tgfx->sem);
|
||||||
if (!--tgfx->used) {
|
if (!--tgfx->used) {
|
||||||
|
@ -224,7 +224,8 @@ static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs)
|
||||||
input_dev->id.product = n_buttons[i];
|
input_dev->id.product = n_buttons[i];
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
|
|
||||||
input_dev->private = tgfx;
|
input_set_drvdata(input_dev, tgfx);
|
||||||
|
|
||||||
input_dev->open = tgfx_open;
|
input_dev->open = tgfx_open;
|
||||||
input_dev->close = tgfx_close;
|
input_dev->close = tgfx_close;
|
||||||
|
|
||||||
|
|
|
@ -205,11 +205,9 @@ static int twidjoy_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
input_dev->id.vendor = SERIO_TWIDJOY;
|
input_dev->id.vendor = SERIO_TWIDJOY;
|
||||||
input_dev->id.product = 0x0001;
|
input_dev->id.product = 0x0001;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &serio->dev;
|
input_dev->dev.parent = &serio->dev;
|
||||||
input_dev->private = twidjoy;
|
|
||||||
|
|
||||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||||
input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
|
|
||||||
input_set_abs_params(input_dev, ABS_X, -50, 50, 4, 4);
|
input_set_abs_params(input_dev, ABS_X, -50, 50, 4, 4);
|
||||||
input_set_abs_params(input_dev, ABS_Y, -50, 50, 4, 4);
|
input_set_abs_params(input_dev, ABS_Y, -50, 50, 4, 4);
|
||||||
|
|
||||||
|
|
|
@ -160,8 +160,7 @@ static int warrior_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
input_dev->id.vendor = SERIO_WARRIOR;
|
input_dev->id.vendor = SERIO_WARRIOR;
|
||||||
input_dev->id.product = 0x0001;
|
input_dev->id.product = 0x0001;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &serio->dev;
|
input_dev->dev.parent = &serio->dev;
|
||||||
input_dev->private = warrior;
|
|
||||||
|
|
||||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
|
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
|
||||||
input_dev->keybit[LONG(BTN_TRIGGER)] = BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_TOP2);
|
input_dev->keybit[LONG(BTN_TRIGGER)] = BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_TOP2);
|
||||||
|
|
|
@ -214,6 +214,15 @@ config KEYBOARD_OMAP
|
||||||
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 omap-keypad.
|
module will be called omap-keypad.
|
||||||
|
|
||||||
|
config KEYBOARD_PXA27x
|
||||||
|
tristate "PXA27x keyboard support"
|
||||||
|
depends on PXA27x
|
||||||
|
help
|
||||||
|
Enable support for PXA27x matrix keyboard controller
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the
|
||||||
|
module will be called pxa27x_keyboard.
|
||||||
|
|
||||||
config KEYBOARD_AAED2000
|
config KEYBOARD_AAED2000
|
||||||
tristate "AAED-2000 keyboard"
|
tristate "AAED-2000 keyboard"
|
||||||
depends on MACH_AAED2000
|
depends on MACH_AAED2000
|
||||||
|
|
|
@ -18,6 +18,7 @@ obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o
|
||||||
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
|
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
|
||||||
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
|
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
|
||||||
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
|
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
|
||||||
|
obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keyboard.o
|
||||||
obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o
|
obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o
|
||||||
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
|
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,7 @@ static void aaedkbd_work(void *data)
|
||||||
|
|
||||||
static int aaedkbd_open(struct input_dev *indev)
|
static int aaedkbd_open(struct input_dev *indev)
|
||||||
{
|
{
|
||||||
struct aaedkbd *aaedkbd = indev->private;
|
struct aaedkbd *aaedkbd = input_get_drvdata(indev);
|
||||||
|
|
||||||
schedule_delayed_work(&aaedkbd->workq, msecs_to_jiffies(SCAN_INTERVAL));
|
schedule_delayed_work(&aaedkbd->workq, msecs_to_jiffies(SCAN_INTERVAL));
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ static int aaedkbd_open(struct input_dev *indev)
|
||||||
|
|
||||||
static void aaedkbd_close(struct input_dev *indev)
|
static void aaedkbd_close(struct input_dev *indev)
|
||||||
{
|
{
|
||||||
struct aaedkbd *aaedkbd = indev->private;
|
struct aaedkbd *aaedkbd = input_get_drvdata(indev);
|
||||||
|
|
||||||
cancel_delayed_work(&aaedkbd->workq);
|
cancel_delayed_work(&aaedkbd->workq);
|
||||||
flush_scheduled_work();
|
flush_scheduled_work();
|
||||||
|
@ -141,8 +141,9 @@ static int __devinit aaedkbd_probe(struct platform_device *pdev)
|
||||||
input_dev->id.vendor = 0x0001;
|
input_dev->id.vendor = 0x0001;
|
||||||
input_dev->id.product = 0x0001;
|
input_dev->id.product = 0x0001;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &pdev->dev;
|
input_dev->dev.parent = &pdev->dev;
|
||||||
input_dev->private = aaedkbd;
|
|
||||||
|
input_set_drvdata(input_dev, aaedkbd);
|
||||||
|
|
||||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
||||||
input_dev->keycode = aaedkbd->keycode;
|
input_dev->keycode = aaedkbd->keycode;
|
||||||
|
|
|
@ -586,7 +586,7 @@ static void atkbd_event_work(struct work_struct *work)
|
||||||
|
|
||||||
static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
||||||
{
|
{
|
||||||
struct atkbd *atkbd = dev->private;
|
struct atkbd *atkbd = input_get_drvdata(dev);
|
||||||
|
|
||||||
if (!atkbd->write)
|
if (!atkbd->write)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -883,8 +883,9 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd)
|
||||||
input_dev->id.product = atkbd->translated ? 1 : atkbd->set;
|
input_dev->id.product = atkbd->translated ? 1 : atkbd->set;
|
||||||
input_dev->id.version = atkbd->id;
|
input_dev->id.version = atkbd->id;
|
||||||
input_dev->event = atkbd_event;
|
input_dev->event = atkbd_event;
|
||||||
input_dev->private = atkbd;
|
input_dev->dev.parent = &atkbd->ps2dev.serio->dev;
|
||||||
input_dev->cdev.dev = &atkbd->ps2dev.serio->dev;
|
|
||||||
|
input_set_drvdata(input_dev, atkbd);
|
||||||
|
|
||||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC);
|
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC);
|
||||||
|
|
||||||
|
|
|
@ -323,8 +323,7 @@ static int __init corgikbd_probe(struct platform_device *pdev)
|
||||||
input_dev->id.vendor = 0x0001;
|
input_dev->id.vendor = 0x0001;
|
||||||
input_dev->id.product = 0x0001;
|
input_dev->id.product = 0x0001;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &pdev->dev;
|
input_dev->dev.parent = &pdev->dev;
|
||||||
input_dev->private = corgikbd;
|
|
||||||
|
|
||||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW);
|
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW);
|
||||||
input_dev->keycode = corgikbd->keycode;
|
input_dev->keycode = corgikbd->keycode;
|
||||||
|
|
|
@ -35,11 +35,14 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
|
||||||
struct input_dev *input = platform_get_drvdata(pdev);
|
struct input_dev *input = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
for (i = 0; i < pdata->nbuttons; i++) {
|
for (i = 0; i < pdata->nbuttons; i++) {
|
||||||
int gpio = pdata->buttons[i].gpio;
|
struct gpio_keys_button *button = &pdata->buttons[i];
|
||||||
if (irq == gpio_to_irq(gpio)) {
|
int gpio = button->gpio;
|
||||||
int state = (gpio_get_value(gpio) ? 1 : 0) ^ (pdata->buttons[i].active_low);
|
|
||||||
|
|
||||||
input_report_key(input, pdata->buttons[i].keycode, state);
|
if (irq == gpio_to_irq(gpio)) {
|
||||||
|
unsigned int type = button->type ?: EV_KEY;
|
||||||
|
int state = (gpio_get_value(gpio) ? 1 : 0) ^ button->active_low;
|
||||||
|
|
||||||
|
input_event(input, type, button->code, !!state);
|
||||||
input_sync(input);
|
input_sync(input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,8 +66,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
input->name = pdev->name;
|
input->name = pdev->name;
|
||||||
input->phys = "gpio-keys/input0";
|
input->phys = "gpio-keys/input0";
|
||||||
input->cdev.dev = &pdev->dev;
|
input->dev.parent = &pdev->dev;
|
||||||
input->private = pdata;
|
|
||||||
|
|
||||||
input->id.bustype = BUS_HOST;
|
input->id.bustype = BUS_HOST;
|
||||||
input->id.vendor = 0x0001;
|
input->id.vendor = 0x0001;
|
||||||
|
@ -72,19 +74,21 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
|
||||||
input->id.version = 0x0100;
|
input->id.version = 0x0100;
|
||||||
|
|
||||||
for (i = 0; i < pdata->nbuttons; i++) {
|
for (i = 0; i < pdata->nbuttons; i++) {
|
||||||
int code = pdata->buttons[i].keycode;
|
struct gpio_keys_button *button = &pdata->buttons[i];
|
||||||
int irq = gpio_to_irq(pdata->buttons[i].gpio);
|
int irq = gpio_to_irq(button->gpio);
|
||||||
|
unsigned int type = button->type ?: EV_KEY;
|
||||||
|
|
||||||
set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
|
set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
|
||||||
error = request_irq(irq, gpio_keys_isr, IRQF_SAMPLE_RANDOM,
|
error = request_irq(irq, gpio_keys_isr, IRQF_SAMPLE_RANDOM,
|
||||||
pdata->buttons[i].desc ? pdata->buttons[i].desc : "gpio_keys",
|
button->desc ? button->desc : "gpio_keys",
|
||||||
pdev);
|
pdev);
|
||||||
if (error) {
|
if (error) {
|
||||||
printk(KERN_ERR "gpio-keys: unable to claim irq %d; error %d\n",
|
printk(KERN_ERR "gpio-keys: unable to claim irq %d; error %d\n",
|
||||||
irq, error);
|
irq, error);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
set_bit(code, input->keybit);
|
|
||||||
|
input_set_capability(input, type, button->code);
|
||||||
}
|
}
|
||||||
|
|
||||||
error = input_register_device(input);
|
error = input_register_device(input);
|
||||||
|
|
|
@ -51,7 +51,7 @@ MODULE_LICENSE("Dual BSD/GPL");
|
||||||
|
|
||||||
#define HIL_KBD_SET1_UPBIT 0x01
|
#define HIL_KBD_SET1_UPBIT 0x01
|
||||||
#define HIL_KBD_SET1_SHIFT 1
|
#define HIL_KBD_SET1_SHIFT 1
|
||||||
static unsigned int hil_kbd_set1[HIL_KEYCODES_SET1_TBLSIZE] =
|
static unsigned int hil_kbd_set1[HIL_KEYCODES_SET1_TBLSIZE] __read_mostly =
|
||||||
{ HIL_KEYCODES_SET1 };
|
{ HIL_KEYCODES_SET1 };
|
||||||
|
|
||||||
#define HIL_KBD_SET2_UPBIT 0x01
|
#define HIL_KBD_SET2_UPBIT 0x01
|
||||||
|
@ -60,10 +60,10 @@ static unsigned int hil_kbd_set1[HIL_KEYCODES_SET1_TBLSIZE] =
|
||||||
|
|
||||||
#define HIL_KBD_SET3_UPBIT 0x80
|
#define HIL_KBD_SET3_UPBIT 0x80
|
||||||
#define HIL_KBD_SET3_SHIFT 0
|
#define HIL_KBD_SET3_SHIFT 0
|
||||||
static unsigned int hil_kbd_set3[HIL_KEYCODES_SET3_TBLSIZE] =
|
static unsigned int hil_kbd_set3[HIL_KEYCODES_SET3_TBLSIZE] __read_mostly =
|
||||||
{ HIL_KEYCODES_SET3 };
|
{ HIL_KEYCODES_SET3 };
|
||||||
|
|
||||||
static char hil_language[][16] = { HIL_LOCALE_MAP };
|
static const char hil_language[][16] = { HIL_LOCALE_MAP };
|
||||||
|
|
||||||
struct hil_kbd {
|
struct hil_kbd {
|
||||||
struct input_dev *dev;
|
struct input_dev *dev;
|
||||||
|
@ -95,9 +95,11 @@ static void hil_kbd_process_record(struct hil_kbd *kbd)
|
||||||
p = data[idx - 1];
|
p = data[idx - 1];
|
||||||
|
|
||||||
if ((p & ~HIL_CMDCT_POL) ==
|
if ((p & ~HIL_CMDCT_POL) ==
|
||||||
(HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) goto report;
|
(HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
|
||||||
|
goto report;
|
||||||
if ((p & ~HIL_CMDCT_RPL) ==
|
if ((p & ~HIL_CMDCT_RPL) ==
|
||||||
(HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) goto report;
|
(HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL))
|
||||||
|
goto report;
|
||||||
|
|
||||||
/* Not a poll response. See if we are loading config records. */
|
/* Not a poll response. See if we are loading config records. */
|
||||||
switch (p & HIL_PKT_DATA_MASK) {
|
switch (p & HIL_PKT_DATA_MASK) {
|
||||||
|
@ -107,27 +109,32 @@ static void hil_kbd_process_record(struct hil_kbd *kbd)
|
||||||
for (; i < HIL_KBD_MAX_LENGTH; i++)
|
for (; i < HIL_KBD_MAX_LENGTH; i++)
|
||||||
kbd->idd[i] = 0;
|
kbd->idd[i] = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HIL_CMD_RSC:
|
case HIL_CMD_RSC:
|
||||||
for (i = 0; i < idx; i++)
|
for (i = 0; i < idx; i++)
|
||||||
kbd->rsc[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
|
kbd->rsc[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
|
||||||
for (; i < HIL_KBD_MAX_LENGTH; i++)
|
for (; i < HIL_KBD_MAX_LENGTH; i++)
|
||||||
kbd->rsc[i] = 0;
|
kbd->rsc[i] = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HIL_CMD_EXD:
|
case HIL_CMD_EXD:
|
||||||
for (i = 0; i < idx; i++)
|
for (i = 0; i < idx; i++)
|
||||||
kbd->exd[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
|
kbd->exd[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
|
||||||
for (; i < HIL_KBD_MAX_LENGTH; i++)
|
for (; i < HIL_KBD_MAX_LENGTH; i++)
|
||||||
kbd->exd[i] = 0;
|
kbd->exd[i] = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HIL_CMD_RNM:
|
case HIL_CMD_RNM:
|
||||||
for (i = 0; i < idx; i++)
|
for (i = 0; i < idx; i++)
|
||||||
kbd->rnm[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
|
kbd->rnm[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
|
||||||
for (; i < HIL_KBD_MAX_LENGTH + 1; i++)
|
for (; i < HIL_KBD_MAX_LENGTH + 1; i++)
|
||||||
kbd->rnm[i] = '\0';
|
kbd->rnm[i] = '\0';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* These occur when device isn't present */
|
/* These occur when device isn't present */
|
||||||
if (p == (HIL_ERR_INT | HIL_PKT_CMD)) break;
|
if (p == (HIL_ERR_INT | HIL_PKT_CMD))
|
||||||
|
break;
|
||||||
/* Anything else we'd like to know about. */
|
/* Anything else we'd like to know about. */
|
||||||
printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);
|
printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);
|
||||||
break;
|
break;
|
||||||
|
@ -139,16 +146,19 @@ static void hil_kbd_process_record(struct hil_kbd *kbd)
|
||||||
switch (kbd->data[0] & HIL_POL_CHARTYPE_MASK) {
|
switch (kbd->data[0] & HIL_POL_CHARTYPE_MASK) {
|
||||||
case HIL_POL_CHARTYPE_NONE:
|
case HIL_POL_CHARTYPE_NONE:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HIL_POL_CHARTYPE_ASCII:
|
case HIL_POL_CHARTYPE_ASCII:
|
||||||
while (cnt < idx - 1)
|
while (cnt < idx - 1)
|
||||||
input_report_key(dev, kbd->data[cnt++] & 0x7f, 1);
|
input_report_key(dev, kbd->data[cnt++] & 0x7f, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HIL_POL_CHARTYPE_RSVD1:
|
case HIL_POL_CHARTYPE_RSVD1:
|
||||||
case HIL_POL_CHARTYPE_RSVD2:
|
case HIL_POL_CHARTYPE_RSVD2:
|
||||||
case HIL_POL_CHARTYPE_BINARY:
|
case HIL_POL_CHARTYPE_BINARY:
|
||||||
while (cnt < idx - 1)
|
while (cnt < idx - 1)
|
||||||
input_report_key(dev, kbd->data[cnt++], 1);
|
input_report_key(dev, kbd->data[cnt++], 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HIL_POL_CHARTYPE_SET1:
|
case HIL_POL_CHARTYPE_SET1:
|
||||||
while (cnt < idx - 1) {
|
while (cnt < idx - 1) {
|
||||||
unsigned int key;
|
unsigned int key;
|
||||||
|
@ -161,6 +171,7 @@ static void hil_kbd_process_record(struct hil_kbd *kbd)
|
||||||
input_report_key(dev, key, !up);
|
input_report_key(dev, key, !up);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HIL_POL_CHARTYPE_SET2:
|
case HIL_POL_CHARTYPE_SET2:
|
||||||
while (cnt < idx - 1) {
|
while (cnt < idx - 1) {
|
||||||
unsigned int key;
|
unsigned int key;
|
||||||
|
@ -173,6 +184,7 @@ static void hil_kbd_process_record(struct hil_kbd *kbd)
|
||||||
input_report_key(dev, key, !up);
|
input_report_key(dev, key, !up);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HIL_POL_CHARTYPE_SET3:
|
case HIL_POL_CHARTYPE_SET3:
|
||||||
while (cnt < idx - 1) {
|
while (cnt < idx - 1) {
|
||||||
unsigned int key;
|
unsigned int key;
|
||||||
|
@ -191,7 +203,8 @@ static void hil_kbd_process_record(struct hil_kbd *kbd)
|
||||||
up(&kbd->sem);
|
up(&kbd->sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hil_kbd_process_err(struct hil_kbd *kbd) {
|
static void hil_kbd_process_err(struct hil_kbd *kbd)
|
||||||
|
{
|
||||||
printk(KERN_WARNING PREFIX "errored HIL packet\n");
|
printk(KERN_WARNING PREFIX "errored HIL packet\n");
|
||||||
kbd->idx4 = 0;
|
kbd->idx4 = 0;
|
||||||
up(&kbd->sem);
|
up(&kbd->sem);
|
||||||
|
@ -205,28 +218,28 @@ static irqreturn_t hil_kbd_interrupt(struct serio *serio,
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
kbd = serio_get_drvdata(serio);
|
kbd = serio_get_drvdata(serio);
|
||||||
if (kbd == NULL) {
|
BUG_ON(kbd == NULL);
|
||||||
BUG();
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kbd->idx4 >= (HIL_KBD_MAX_LENGTH * sizeof(hil_packet))) {
|
if (kbd->idx4 >= (HIL_KBD_MAX_LENGTH * sizeof(hil_packet))) {
|
||||||
hil_kbd_process_err(kbd);
|
hil_kbd_process_err(kbd);
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
idx = kbd->idx4/4;
|
idx = kbd->idx4/4;
|
||||||
if (!(kbd->idx4 % 4)) kbd->data[idx] = 0;
|
if (!(kbd->idx4 % 4))
|
||||||
|
kbd->data[idx] = 0;
|
||||||
packet = kbd->data[idx];
|
packet = kbd->data[idx];
|
||||||
packet |= ((hil_packet)data) << ((3 - (kbd->idx4 % 4)) * 8);
|
packet |= ((hil_packet)data) << ((3 - (kbd->idx4 % 4)) * 8);
|
||||||
kbd->data[idx] = packet;
|
kbd->data[idx] = packet;
|
||||||
|
|
||||||
/* Records of N 4-byte hil_packets must terminate with a command. */
|
/* Records of N 4-byte hil_packets must terminate with a command. */
|
||||||
if ((++(kbd->idx4)) % 4) return IRQ_HANDLED;
|
if ((++(kbd->idx4)) % 4)
|
||||||
|
return IRQ_HANDLED;
|
||||||
if ((packet & 0xffff0000) != HIL_ERR_INT) {
|
if ((packet & 0xffff0000) != HIL_ERR_INT) {
|
||||||
hil_kbd_process_err(kbd);
|
hil_kbd_process_err(kbd);
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
if (packet & HIL_PKT_CMD) hil_kbd_process_record(kbd);
|
if (packet & HIL_PKT_CMD)
|
||||||
|
hil_kbd_process_record(kbd);
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,10 +248,7 @@ static void hil_kbd_disconnect(struct serio *serio)
|
||||||
struct hil_kbd *kbd;
|
struct hil_kbd *kbd;
|
||||||
|
|
||||||
kbd = serio_get_drvdata(serio);
|
kbd = serio_get_drvdata(serio);
|
||||||
if (kbd == NULL) {
|
BUG_ON(kbd == NULL);
|
||||||
BUG();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
serio_close(serio);
|
serio_close(serio);
|
||||||
input_unregister_device(kbd->dev);
|
input_unregister_device(kbd->dev);
|
||||||
|
@ -259,42 +269,40 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
if (!kbd->dev)
|
if (!kbd->dev)
|
||||||
goto bail0;
|
goto bail0;
|
||||||
|
|
||||||
kbd->dev->private = kbd;
|
|
||||||
|
|
||||||
if (serio_open(serio, drv))
|
if (serio_open(serio, drv))
|
||||||
goto bail1;
|
goto bail1;
|
||||||
|
|
||||||
serio_set_drvdata(serio, kbd);
|
serio_set_drvdata(serio, kbd);
|
||||||
kbd->serio = serio;
|
kbd->serio = serio;
|
||||||
|
|
||||||
init_MUTEX_LOCKED(&(kbd->sem));
|
init_MUTEX_LOCKED(&kbd->sem);
|
||||||
|
|
||||||
/* Get device info. MLC driver supplies devid/status/etc. */
|
/* Get device info. MLC driver supplies devid/status/etc. */
|
||||||
serio->write(serio, 0);
|
serio->write(serio, 0);
|
||||||
serio->write(serio, 0);
|
serio->write(serio, 0);
|
||||||
serio->write(serio, HIL_PKT_CMD >> 8);
|
serio->write(serio, HIL_PKT_CMD >> 8);
|
||||||
serio->write(serio, HIL_CMD_IDD);
|
serio->write(serio, HIL_CMD_IDD);
|
||||||
down(&(kbd->sem));
|
down(&kbd->sem);
|
||||||
|
|
||||||
serio->write(serio, 0);
|
serio->write(serio, 0);
|
||||||
serio->write(serio, 0);
|
serio->write(serio, 0);
|
||||||
serio->write(serio, HIL_PKT_CMD >> 8);
|
serio->write(serio, HIL_PKT_CMD >> 8);
|
||||||
serio->write(serio, HIL_CMD_RSC);
|
serio->write(serio, HIL_CMD_RSC);
|
||||||
down(&(kbd->sem));
|
down(&kbd->sem);
|
||||||
|
|
||||||
serio->write(serio, 0);
|
serio->write(serio, 0);
|
||||||
serio->write(serio, 0);
|
serio->write(serio, 0);
|
||||||
serio->write(serio, HIL_PKT_CMD >> 8);
|
serio->write(serio, HIL_PKT_CMD >> 8);
|
||||||
serio->write(serio, HIL_CMD_RNM);
|
serio->write(serio, HIL_CMD_RNM);
|
||||||
down(&(kbd->sem));
|
down(&kbd->sem);
|
||||||
|
|
||||||
serio->write(serio, 0);
|
serio->write(serio, 0);
|
||||||
serio->write(serio, 0);
|
serio->write(serio, 0);
|
||||||
serio->write(serio, HIL_PKT_CMD >> 8);
|
serio->write(serio, HIL_PKT_CMD >> 8);
|
||||||
serio->write(serio, HIL_CMD_EXD);
|
serio->write(serio, HIL_CMD_EXD);
|
||||||
down(&(kbd->sem));
|
down(&kbd->sem);
|
||||||
|
|
||||||
up(&(kbd->sem));
|
up(&kbd->sem);
|
||||||
|
|
||||||
did = kbd->idd[0];
|
did = kbd->idd[0];
|
||||||
idd = kbd->idd + 1;
|
idd = kbd->idd + 1;
|
||||||
|
@ -310,12 +318,11 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
goto bail2;
|
goto bail2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(HIL_IDD_NUM_BUTTONS(idd) || HIL_IDD_NUM_AXES_PER_SET(*idd)) {
|
if (HIL_IDD_NUM_BUTTONS(idd) || HIL_IDD_NUM_AXES_PER_SET(*idd)) {
|
||||||
printk(KERN_INFO PREFIX "keyboards only, no combo devices supported.\n");
|
printk(KERN_INFO PREFIX "keyboards only, no combo devices supported.\n");
|
||||||
goto bail2;
|
goto bail2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
kbd->dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
kbd->dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
||||||
kbd->dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
|
kbd->dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
|
||||||
kbd->dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE;
|
kbd->dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE;
|
||||||
|
@ -328,7 +335,7 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
kbd->dev->id.vendor = PCI_VENDOR_ID_HP;
|
kbd->dev->id.vendor = PCI_VENDOR_ID_HP;
|
||||||
kbd->dev->id.product = 0x0001; /* TODO: get from kbd->rsc */
|
kbd->dev->id.product = 0x0001; /* TODO: get from kbd->rsc */
|
||||||
kbd->dev->id.version = 0x0100; /* TODO: get from kbd->rsc */
|
kbd->dev->id.version = 0x0100; /* TODO: get from kbd->rsc */
|
||||||
kbd->dev->cdev.dev = &serio->dev;
|
kbd->dev->dev.parent = &serio->dev;
|
||||||
|
|
||||||
for (i = 0; i < 128; i++) {
|
for (i = 0; i < 128; i++) {
|
||||||
set_bit(hil_kbd_set1[i], kbd->dev->keybit);
|
set_bit(hil_kbd_set1[i], kbd->dev->keybit);
|
||||||
|
@ -344,8 +351,8 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
serio->write(serio, 0);
|
serio->write(serio, 0);
|
||||||
serio->write(serio, HIL_PKT_CMD >> 8);
|
serio->write(serio, HIL_PKT_CMD >> 8);
|
||||||
serio->write(serio, HIL_CMD_EK1); /* Enable Keyswitch Autorepeat 1 */
|
serio->write(serio, HIL_CMD_EK1); /* Enable Keyswitch Autorepeat 1 */
|
||||||
down(&(kbd->sem));
|
down(&kbd->sem);
|
||||||
up(&(kbd->sem));
|
up(&kbd->sem);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
bail2:
|
bail2:
|
||||||
|
@ -368,7 +375,7 @@ static struct serio_device_id hil_kbd_ids[] = {
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct serio_driver hil_kbd_serio_drv = {
|
static struct serio_driver hil_kbd_serio_drv = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "hil_kbd",
|
.name = "hil_kbd",
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 Philip Blundell <philb@gnu.org>
|
* Copyright (C) 1998 Philip Blundell <philb@gnu.org>
|
||||||
* Copyright (C) 1999 Matthew Wilcox <willy@bofh.ai>
|
* Copyright (C) 1999 Matthew Wilcox <willy@bofh.ai>
|
||||||
* Copyright (C) 1999-2006 Helge Deller <deller@gmx.de>
|
* Copyright (C) 1999-2007 Helge Deller <deller@gmx.de>
|
||||||
*
|
*
|
||||||
* Very basic HP Human Interface Loop (HIL) driver.
|
* Very basic HP Human Interface Loop (HIL) driver.
|
||||||
* This driver handles the keyboard on HP300 (m68k) and on some
|
* This driver handles the keyboard on HP300 (m68k) and on some
|
||||||
|
@ -89,7 +89,7 @@ MODULE_LICENSE("GPL v2");
|
||||||
#define HIL_READKBDSADR 0xF9
|
#define HIL_READKBDSADR 0xF9
|
||||||
#define HIL_WRITEKBDSADR 0xE9
|
#define HIL_WRITEKBDSADR 0xE9
|
||||||
|
|
||||||
static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] =
|
static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] __read_mostly =
|
||||||
{ HIL_KEYCODES_SET1 };
|
{ HIL_KEYCODES_SET1 };
|
||||||
|
|
||||||
/* HIL structure */
|
/* HIL structure */
|
||||||
|
@ -211,10 +211,10 @@ hil_keyb_init(void)
|
||||||
return -ENODEV; /* already initialized */
|
return -ENODEV; /* already initialized */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_lock_init(&hil_dev.lock);
|
||||||
hil_dev.dev = input_allocate_device();
|
hil_dev.dev = input_allocate_device();
|
||||||
if (!hil_dev.dev)
|
if (!hil_dev.dev)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
hil_dev.dev->private = &hil_dev;
|
|
||||||
|
|
||||||
#if defined(CONFIG_HP300)
|
#if defined(CONFIG_HP300)
|
||||||
if (!hwreg_present((void *)(HILBASE + HIL_DATA))) {
|
if (!hwreg_present((void *)(HILBASE + HIL_DATA))) {
|
||||||
|
|
|
@ -515,7 +515,7 @@ static int
|
||||||
lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code,
|
lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code,
|
||||||
int value)
|
int value)
|
||||||
{
|
{
|
||||||
struct lkkbd *lk = dev->private;
|
struct lkkbd *lk = input_get_drvdata (dev);
|
||||||
unsigned char leds_on = 0;
|
unsigned char leds_on = 0;
|
||||||
unsigned char leds_off = 0;
|
unsigned char leds_off = 0;
|
||||||
|
|
||||||
|
@ -666,9 +666,10 @@ lkkbd_connect (struct serio *serio, struct serio_driver *drv)
|
||||||
input_dev->id.vendor = SERIO_LKKBD;
|
input_dev->id.vendor = SERIO_LKKBD;
|
||||||
input_dev->id.product = 0;
|
input_dev->id.product = 0;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &serio->dev;
|
input_dev->dev.parent = &serio->dev;
|
||||||
input_dev->event = lkkbd_event;
|
input_dev->event = lkkbd_event;
|
||||||
input_dev->private = lk;
|
|
||||||
|
input_set_drvdata (input_dev, lk);
|
||||||
|
|
||||||
set_bit (EV_KEY, input_dev->evbit);
|
set_bit (EV_KEY, input_dev->evbit);
|
||||||
set_bit (EV_LED, input_dev->evbit);
|
set_bit (EV_LED, input_dev->evbit);
|
||||||
|
|
|
@ -231,7 +231,7 @@ static int locomokbd_probe(struct locomo_dev *dev)
|
||||||
input_dev->id.vendor = 0x0001;
|
input_dev->id.vendor = 0x0001;
|
||||||
input_dev->id.product = 0x0001;
|
input_dev->id.product = 0x0001;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->private = locomokbd;
|
input_dev->dev.parent = &dev->dev;
|
||||||
|
|
||||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
||||||
input_dev->keycode = locomokbd->keycode;
|
input_dev->keycode = locomokbd->keycode;
|
||||||
|
|
|
@ -104,8 +104,7 @@ static int nkbd_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
input_dev->id.vendor = SERIO_NEWTON;
|
input_dev->id.vendor = SERIO_NEWTON;
|
||||||
input_dev->id.product = 0x0001;
|
input_dev->id.product = 0x0001;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &serio->dev;
|
input_dev->dev.parent = &serio->dev;
|
||||||
input_dev->private = nkbd;
|
|
||||||
|
|
||||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
||||||
input_dev->keycode = nkbd->keycode;
|
input_dev->keycode = nkbd->keycode;
|
||||||
|
|
|
@ -370,8 +370,7 @@ static int __init omap_kp_probe(struct platform_device *pdev)
|
||||||
set_bit(keymap[i] & KEY_MAX, input_dev->keybit);
|
set_bit(keymap[i] & KEY_MAX, input_dev->keybit);
|
||||||
input_dev->name = "omap-keypad";
|
input_dev->name = "omap-keypad";
|
||||||
input_dev->phys = "omap-keypad/input0";
|
input_dev->phys = "omap-keypad/input0";
|
||||||
input_dev->cdev.dev = &pdev->dev;
|
input_dev->dev.parent = &pdev->dev;
|
||||||
input_dev->private = omap_kp;
|
|
||||||
|
|
||||||
input_dev->id.bustype = BUS_HOST;
|
input_dev->id.bustype = BUS_HOST;
|
||||||
input_dev->id.vendor = 0x0001;
|
input_dev->id.vendor = 0x0001;
|
||||||
|
|
|
@ -0,0 +1,258 @@
|
||||||
|
/*
|
||||||
|
* linux/drivers/input/keyboard/pxa27x_keyboard.c
|
||||||
|
*
|
||||||
|
* Driver for the pxa27x matrix keyboard controller.
|
||||||
|
*
|
||||||
|
* Created: Feb 22, 2007
|
||||||
|
* Author: Rodolfo Giometti <giometti@linux.it>
|
||||||
|
*
|
||||||
|
* Based on a previous implementations by Kevin O'Connor
|
||||||
|
* <kevin_at_koconnor.net> and Alex Osborne <bobofdoom@gmail.com> and
|
||||||
|
* on some suggestions by Nicolas Pitre <nico@cam.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/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
|
#include <asm/mach-types.h>
|
||||||
|
#include <asm/mach/arch.h>
|
||||||
|
#include <asm/mach/map.h>
|
||||||
|
|
||||||
|
#include <asm/arch/hardware.h>
|
||||||
|
#include <asm/arch/pxa-regs.h>
|
||||||
|
#include <asm/arch/irqs.h>
|
||||||
|
#include <asm/arch/pxa27x_keyboard.h>
|
||||||
|
|
||||||
|
#define DRIVER_NAME "pxa27x-keyboard"
|
||||||
|
|
||||||
|
#define KPASMKP(col) (col/2 == 0 ? KPASMKP0 : \
|
||||||
|
col/2 == 1 ? KPASMKP1 : \
|
||||||
|
col/2 == 2 ? KPASMKP2 : KPASMKP3)
|
||||||
|
#define KPASMKPx_MKC(row, col) (1 << (row + 16 * (col % 2)))
|
||||||
|
|
||||||
|
static irqreturn_t pxakbd_irq_handler(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
struct platform_device *pdev = dev_id;
|
||||||
|
struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
|
||||||
|
struct input_dev *input_dev = platform_get_drvdata(pdev);
|
||||||
|
unsigned long kpc = KPC;
|
||||||
|
int p, row, col, rel;
|
||||||
|
|
||||||
|
if (kpc & KPC_DI) {
|
||||||
|
unsigned long kpdk = KPDK;
|
||||||
|
|
||||||
|
if (!(kpdk & KPDK_DKP)) {
|
||||||
|
/* better luck next time */
|
||||||
|
} else if (kpc & KPC_REE0) {
|
||||||
|
unsigned long kprec = KPREC;
|
||||||
|
KPREC = 0x7f;
|
||||||
|
|
||||||
|
if (kprec & KPREC_OF0)
|
||||||
|
rel = (kprec & 0xff) + 0x7f;
|
||||||
|
else if (kprec & KPREC_UF0)
|
||||||
|
rel = (kprec & 0xff) - 0x7f - 0xff;
|
||||||
|
else
|
||||||
|
rel = (kprec & 0xff) - 0x7f;
|
||||||
|
|
||||||
|
if (rel) {
|
||||||
|
input_report_rel(input_dev, REL_WHEEL, rel);
|
||||||
|
input_sync(input_dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kpc & KPC_MI) {
|
||||||
|
/* report the status of every button */
|
||||||
|
for (row = 0; row < pdata->nr_rows; row++) {
|
||||||
|
for (col = 0; col < pdata->nr_cols; col++) {
|
||||||
|
p = KPASMKP(col) & KPASMKPx_MKC(row, col) ?
|
||||||
|
1 : 0;
|
||||||
|
pr_debug("keycode %x - pressed %x\n",
|
||||||
|
pdata->keycodes[row][col], p);
|
||||||
|
input_report_key(input_dev,
|
||||||
|
pdata->keycodes[row][col], p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input_sync(input_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pxakbd_open(struct input_dev *dev)
|
||||||
|
{
|
||||||
|
/* Set keypad control register */
|
||||||
|
KPC |= (KPC_ASACT |
|
||||||
|
KPC_MS_ALL |
|
||||||
|
(2 << 6) | KPC_REE0 | KPC_DK_DEB_SEL |
|
||||||
|
KPC_ME | KPC_MIE | KPC_DE | KPC_DIE);
|
||||||
|
|
||||||
|
KPC &= ~KPC_AS; /* disable automatic scan */
|
||||||
|
KPC &= ~KPC_IMKP; /* do not ignore multiple keypresses */
|
||||||
|
|
||||||
|
/* Set rotary count to mid-point value */
|
||||||
|
KPREC = 0x7F;
|
||||||
|
|
||||||
|
/* Enable unit clock */
|
||||||
|
pxa_set_cken(CKEN19_KEYPAD, 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pxakbd_close(struct input_dev *dev)
|
||||||
|
{
|
||||||
|
/* Disable clock unit */
|
||||||
|
pxa_set_cken(CKEN19_KEYPAD, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
static int pxakbd_suspend(struct platform_device *pdev, pm_message_t state)
|
||||||
|
{
|
||||||
|
struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
|
||||||
|
|
||||||
|
/* Save controller status */
|
||||||
|
pdata->reg_kpc = KPC;
|
||||||
|
pdata->reg_kprec = KPREC;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pxakbd_resume(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
|
||||||
|
struct input_dev *input_dev = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
mutex_lock(&input_dev->mutex);
|
||||||
|
|
||||||
|
if (input_dev->users) {
|
||||||
|
/* Restore controller status */
|
||||||
|
KPC = pdata->reg_kpc;
|
||||||
|
KPREC = pdata->reg_kprec;
|
||||||
|
|
||||||
|
/* Enable unit clock */
|
||||||
|
pxa_set_cken(CKEN19_KEYPAD, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&input_dev->mutex);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define pxakbd_suspend NULL
|
||||||
|
#define pxakbd_resume NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int __devinit pxakbd_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
|
||||||
|
struct input_dev *input_dev;
|
||||||
|
int i, row, col, error;
|
||||||
|
|
||||||
|
/* Create and register the input driver. */
|
||||||
|
input_dev = input_allocate_device();
|
||||||
|
if (!input_dev) {
|
||||||
|
printk(KERN_ERR "Cannot request keypad device\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
input_dev->name = DRIVER_NAME;
|
||||||
|
input_dev->id.bustype = BUS_HOST;
|
||||||
|
input_dev->open = pxakbd_open;
|
||||||
|
input_dev->close = pxakbd_close;
|
||||||
|
input_dev->dev.parent = &pdev->dev;
|
||||||
|
|
||||||
|
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_REL);
|
||||||
|
input_dev->relbit[LONG(REL_WHEEL)] = BIT(REL_WHEEL);
|
||||||
|
for (row = 0; row < pdata->nr_rows; row++) {
|
||||||
|
for (col = 0; col < pdata->nr_cols; col++) {
|
||||||
|
int code = pdata->keycodes[row][col];
|
||||||
|
if (code > 0)
|
||||||
|
set_bit(code, input_dev->keybit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error = request_irq(IRQ_KEYPAD, pxakbd_irq_handler, IRQF_DISABLED,
|
||||||
|
DRIVER_NAME, pdev);
|
||||||
|
if (error) {
|
||||||
|
printk(KERN_ERR "Cannot request keypad IRQ\n");
|
||||||
|
pxa_set_cken(CKEN19_KEYPAD, 0);
|
||||||
|
goto err_free_dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, input_dev);
|
||||||
|
|
||||||
|
/* Register the input device */
|
||||||
|
error = input_register_device(input_dev);
|
||||||
|
if (error)
|
||||||
|
goto err_free_irq;
|
||||||
|
|
||||||
|
/* Setup GPIOs. */
|
||||||
|
for (i = 0; i < pdata->nr_rows + pdata->nr_cols; i++)
|
||||||
|
pxa_gpio_mode(pdata->gpio_modes[i]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Store rows/cols info into keyboard registers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
KPC |= (pdata->nr_rows - 1) << 26;
|
||||||
|
KPC |= (pdata->nr_cols - 1) << 23;
|
||||||
|
|
||||||
|
for (col = 0; col < pdata->nr_cols; col++)
|
||||||
|
KPC |= KPC_MS0 << col;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_free_irq:
|
||||||
|
platform_set_drvdata(pdev, NULL);
|
||||||
|
free_irq(IRQ_KEYPAD, pdev);
|
||||||
|
err_free_dev:
|
||||||
|
input_free_device(input_dev);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __devexit pxakbd_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct input_dev *input_dev = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
input_unregister_device(input_dev);
|
||||||
|
free_irq(IRQ_KEYPAD, pdev);
|
||||||
|
platform_set_drvdata(pdev, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver pxakbd_driver = {
|
||||||
|
.probe = pxakbd_probe,
|
||||||
|
.remove = __devexit_p(pxakbd_remove),
|
||||||
|
.suspend = pxakbd_suspend,
|
||||||
|
.resume = pxakbd_resume,
|
||||||
|
.driver = {
|
||||||
|
.name = DRIVER_NAME,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init pxakbd_init(void)
|
||||||
|
{
|
||||||
|
return platform_driver_register(&pxakbd_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit pxakbd_exit(void)
|
||||||
|
{
|
||||||
|
platform_driver_unregister(&pxakbd_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(pxakbd_init);
|
||||||
|
module_exit(pxakbd_exit);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("PXA27x Matrix Keyboard Driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -372,10 +372,9 @@ static int __init spitzkbd_probe(struct platform_device *dev)
|
||||||
|
|
||||||
spitzkbd->input = input_dev;
|
spitzkbd->input = input_dev;
|
||||||
|
|
||||||
input_dev->private = spitzkbd;
|
|
||||||
input_dev->name = "Spitz Keyboard";
|
input_dev->name = "Spitz Keyboard";
|
||||||
input_dev->phys = spitzkbd->phys;
|
input_dev->phys = spitzkbd->phys;
|
||||||
input_dev->cdev.dev = &dev->dev;
|
input_dev->dev.parent = &dev->dev;
|
||||||
|
|
||||||
input_dev->id.bustype = BUS_HOST;
|
input_dev->id.bustype = BUS_HOST;
|
||||||
input_dev->id.vendor = 0x0001;
|
input_dev->id.vendor = 0x0001;
|
||||||
|
|
|
@ -108,8 +108,7 @@ static int skbd_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
input_dev->id.vendor = SERIO_STOWAWAY;
|
input_dev->id.vendor = SERIO_STOWAWAY;
|
||||||
input_dev->id.product = 0x0001;
|
input_dev->id.product = 0x0001;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &serio->dev;
|
input_dev->dev.parent = &serio->dev;
|
||||||
input_dev->private = skbd;
|
|
||||||
|
|
||||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
||||||
input_dev->keycode = skbd->keycode;
|
input_dev->keycode = skbd->keycode;
|
||||||
|
|
|
@ -146,7 +146,7 @@ out:
|
||||||
|
|
||||||
static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
||||||
{
|
{
|
||||||
struct sunkbd *sunkbd = dev->private;
|
struct sunkbd *sunkbd = input_get_drvdata(dev);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|
||||||
|
@ -271,8 +271,10 @@ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
input_dev->id.vendor = SERIO_SUNKBD;
|
input_dev->id.vendor = SERIO_SUNKBD;
|
||||||
input_dev->id.product = sunkbd->type;
|
input_dev->id.product = sunkbd->type;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &serio->dev;
|
input_dev->dev.parent = &serio->dev;
|
||||||
input_dev->private = sunkbd;
|
|
||||||
|
input_set_drvdata(input_dev, sunkbd);
|
||||||
|
|
||||||
input_dev->event = sunkbd_event;
|
input_dev->event = sunkbd_event;
|
||||||
|
|
||||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_SND) | BIT(EV_REP);
|
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_SND) | BIT(EV_REP);
|
||||||
|
|
|
@ -108,8 +108,7 @@ static int xtkbd_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
input_dev->id.vendor = 0x0001;
|
input_dev->id.vendor = 0x0001;
|
||||||
input_dev->id.product = 0x0001;
|
input_dev->id.product = 0x0001;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &serio->dev;
|
input_dev->dev.parent = &serio->dev;
|
||||||
input_dev->private = xtkbd;
|
|
||||||
|
|
||||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
||||||
input_dev->keycode = xtkbd->keycode;
|
input_dev->keycode = xtkbd->keycode;
|
||||||
|
|
|
@ -40,6 +40,16 @@ config INPUT_M68K_BEEP
|
||||||
tristate "M68k Beeper support"
|
tristate "M68k Beeper support"
|
||||||
depends on M68K
|
depends on M68K
|
||||||
|
|
||||||
|
config INPUT_COBALT_BTNS
|
||||||
|
tristate "Cobalt button interface"
|
||||||
|
depends on MIPS_COBALT
|
||||||
|
select INPUT_POLLDEV
|
||||||
|
help
|
||||||
|
Say Y here if you want to support MIPS Cobalt button interface.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the
|
||||||
|
module will be called cobalt_btns.
|
||||||
|
|
||||||
config INPUT_WISTRON_BTNS
|
config INPUT_WISTRON_BTNS
|
||||||
tristate "x86 Wistron laptop button interface"
|
tristate "x86 Wistron laptop button interface"
|
||||||
depends on X86 && !X86_64
|
depends on X86 && !X86_64
|
||||||
|
@ -81,6 +91,17 @@ config INPUT_UINPUT
|
||||||
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 uinput.
|
module will be called uinput.
|
||||||
|
|
||||||
|
config INPUT_POLLDEV
|
||||||
|
tristate "Polled input device skeleton"
|
||||||
|
help
|
||||||
|
Say Y here if you are using a driver for an input
|
||||||
|
device that periodically polls hardware state. This
|
||||||
|
option is only useful for out-of-tree drivers since
|
||||||
|
in-tree drivers select it automatically.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the
|
||||||
|
module will be called input-polldev.
|
||||||
|
|
||||||
config HP_SDC_RTC
|
config HP_SDC_RTC
|
||||||
tristate "HP SDC Real Time Clock"
|
tristate "HP SDC Real Time Clock"
|
||||||
depends on GSC || HP300
|
depends on GSC || HP300
|
||||||
|
|
|
@ -4,10 +4,12 @@
|
||||||
|
|
||||||
# Each configuration option enables a list of files.
|
# Each configuration option enables a list of files.
|
||||||
|
|
||||||
|
obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o
|
||||||
obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o
|
obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o
|
||||||
obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o
|
obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o
|
||||||
obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
|
obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
|
||||||
obj-$(CONFIG_INPUT_UINPUT) += uinput.o
|
obj-$(CONFIG_INPUT_UINPUT) += uinput.o
|
||||||
|
obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o
|
||||||
obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o
|
obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o
|
||||||
obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o
|
obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o
|
||||||
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
|
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
|
||||||
|
|
|
@ -0,0 +1,172 @@
|
||||||
|
/*
|
||||||
|
* Cobalt button interface driver.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/input-polldev.h>
|
||||||
|
#include <linux/ioport.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
|
#define BUTTONS_POLL_INTERVAL 30 /* msec */
|
||||||
|
#define BUTTONS_COUNT_THRESHOLD 3
|
||||||
|
#define BUTTONS_STATUS_MASK 0xfe000000
|
||||||
|
|
||||||
|
struct buttons_dev {
|
||||||
|
struct input_polled_dev *poll_dev;
|
||||||
|
void __iomem *reg;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct buttons_map {
|
||||||
|
uint32_t mask;
|
||||||
|
int keycode;
|
||||||
|
int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct buttons_map buttons_map[] = {
|
||||||
|
{ 0x02000000, KEY_RESTART, },
|
||||||
|
{ 0x04000000, KEY_LEFT, },
|
||||||
|
{ 0x08000000, KEY_UP, },
|
||||||
|
{ 0x10000000, KEY_DOWN, },
|
||||||
|
{ 0x20000000, KEY_RIGHT, },
|
||||||
|
{ 0x40000000, KEY_ENTER, },
|
||||||
|
{ 0x80000000, KEY_SELECT, },
|
||||||
|
};
|
||||||
|
|
||||||
|
static void handle_buttons(struct input_polled_dev *dev)
|
||||||
|
{
|
||||||
|
struct buttons_map *button = buttons_map;
|
||||||
|
struct buttons_dev *bdev = dev->private;
|
||||||
|
struct input_dev *input = dev->input;
|
||||||
|
uint32_t status;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
status = readl(bdev->reg);
|
||||||
|
status = ~status & BUTTONS_STATUS_MASK;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(buttons_map); i++) {
|
||||||
|
if (status & button->mask) {
|
||||||
|
button->count++;
|
||||||
|
} else {
|
||||||
|
if (button->count >= BUTTONS_COUNT_THRESHOLD) {
|
||||||
|
input_report_key(input, button->keycode, 0);
|
||||||
|
input_sync(input);
|
||||||
|
}
|
||||||
|
button->count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (button->count == BUTTONS_COUNT_THRESHOLD) {
|
||||||
|
input_report_key(input, button->keycode, 1);
|
||||||
|
input_sync(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
button++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __devinit cobalt_buttons_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct buttons_dev *bdev;
|
||||||
|
struct input_polled_dev *poll_dev;
|
||||||
|
struct input_dev *input;
|
||||||
|
struct resource *res;
|
||||||
|
int error, i;
|
||||||
|
|
||||||
|
bdev = kzalloc(sizeof(struct buttons_dev), GFP_KERNEL);
|
||||||
|
poll_dev = input_allocate_polled_device();
|
||||||
|
if (!bdev || !poll_dev) {
|
||||||
|
error = -ENOMEM;
|
||||||
|
goto err_free_mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
poll_dev->private = bdev;
|
||||||
|
poll_dev->poll = handle_buttons;
|
||||||
|
poll_dev->poll_interval = BUTTONS_POLL_INTERVAL;
|
||||||
|
|
||||||
|
input = poll_dev->input;
|
||||||
|
input->name = "Cobalt buttons";
|
||||||
|
input->phys = "cobalt/input0";
|
||||||
|
input->id.bustype = BUS_HOST;
|
||||||
|
input->cdev.dev = &pdev->dev;
|
||||||
|
|
||||||
|
input->evbit[0] = BIT(EV_KEY);
|
||||||
|
for (i = 0; i < ARRAY_SIZE(buttons_map); i++) {
|
||||||
|
set_bit(buttons_map[i].keycode, input->keybit);
|
||||||
|
buttons_map[i].count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
if (!res) {
|
||||||
|
error = -EBUSY;
|
||||||
|
goto err_free_mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
bdev->poll_dev = poll_dev;
|
||||||
|
bdev->reg = ioremap(res->start, res->end - res->start + 1);
|
||||||
|
dev_set_drvdata(&pdev->dev, bdev);
|
||||||
|
|
||||||
|
error = input_register_polled_device(poll_dev);
|
||||||
|
if (error)
|
||||||
|
goto err_iounmap;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_iounmap:
|
||||||
|
iounmap(bdev->reg);
|
||||||
|
err_free_mem:
|
||||||
|
input_free_polled_device(poll_dev);
|
||||||
|
kfree(bdev);
|
||||||
|
dev_set_drvdata(&pdev->dev, NULL);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __devexit cobalt_buttons_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct buttons_dev *bdev = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
input_unregister_polled_device(bdev->poll_dev);
|
||||||
|
input_free_polled_device(bdev->poll_dev);
|
||||||
|
iounmap(bdev->reg);
|
||||||
|
kfree(bdev);
|
||||||
|
dev_set_drvdata(dev, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver cobalt_buttons_driver = {
|
||||||
|
.probe = cobalt_buttons_probe,
|
||||||
|
.remove = __devexit_p(cobalt_buttons_remove),
|
||||||
|
.driver = {
|
||||||
|
.name = "Cobalt buttons",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init cobalt_buttons_init(void)
|
||||||
|
{
|
||||||
|
return platform_driver_register(&cobalt_buttons_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit cobalt_buttons_exit(void)
|
||||||
|
{
|
||||||
|
platform_driver_unregister(&cobalt_buttons_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(cobalt_buttons_init);
|
||||||
|
module_exit(cobalt_buttons_exit);
|
|
@ -0,0 +1,171 @@
|
||||||
|
/*
|
||||||
|
* Generic implementation of a polled input device
|
||||||
|
|
||||||
|
* Copyright (c) 2007 Dmitry Torokhov
|
||||||
|
*
|
||||||
|
* 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/jiffies.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/input-polldev.h>
|
||||||
|
|
||||||
|
static DEFINE_MUTEX(polldev_mutex);
|
||||||
|
static int polldev_users;
|
||||||
|
static struct workqueue_struct *polldev_wq;
|
||||||
|
|
||||||
|
static int input_polldev_start_workqueue(void)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
retval = mutex_lock_interruptible(&polldev_mutex);
|
||||||
|
if (retval)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
if (!polldev_users) {
|
||||||
|
polldev_wq = create_singlethread_workqueue("ipolldevd");
|
||||||
|
if (!polldev_wq) {
|
||||||
|
printk(KERN_ERR "input-polldev: failed to create "
|
||||||
|
"ipolldevd workqueue\n");
|
||||||
|
retval = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
polldev_users++;
|
||||||
|
|
||||||
|
out:
|
||||||
|
mutex_unlock(&polldev_mutex);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void input_polldev_stop_workqueue(void)
|
||||||
|
{
|
||||||
|
mutex_lock(&polldev_mutex);
|
||||||
|
|
||||||
|
if (!--polldev_users)
|
||||||
|
destroy_workqueue(polldev_wq);
|
||||||
|
|
||||||
|
mutex_unlock(&polldev_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void input_polled_device_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct input_polled_dev *dev =
|
||||||
|
container_of(work, struct input_polled_dev, work.work);
|
||||||
|
|
||||||
|
dev->poll(dev);
|
||||||
|
queue_delayed_work(polldev_wq, &dev->work,
|
||||||
|
msecs_to_jiffies(dev->poll_interval));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int input_open_polled_device(struct input_dev *input)
|
||||||
|
{
|
||||||
|
struct input_polled_dev *dev = input->private;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = input_polldev_start_workqueue();
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
if (dev->flush)
|
||||||
|
dev->flush(dev);
|
||||||
|
|
||||||
|
queue_delayed_work(polldev_wq, &dev->work,
|
||||||
|
msecs_to_jiffies(dev->poll_interval));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void input_close_polled_device(struct input_dev *input)
|
||||||
|
{
|
||||||
|
struct input_polled_dev *dev = input->private;
|
||||||
|
|
||||||
|
cancel_rearming_delayed_workqueue(polldev_wq, &dev->work);
|
||||||
|
input_polldev_stop_workqueue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* input_allocate_polled_device - allocated memory polled device
|
||||||
|
*
|
||||||
|
* The function allocates memory for a polled device and also
|
||||||
|
* for an input device associated with this polled device.
|
||||||
|
*/
|
||||||
|
struct input_polled_dev *input_allocate_polled_device(void)
|
||||||
|
{
|
||||||
|
struct input_polled_dev *dev;
|
||||||
|
|
||||||
|
dev = kzalloc(sizeof(struct input_polled_dev), GFP_KERNEL);
|
||||||
|
if (!dev)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
dev->input = input_allocate_device();
|
||||||
|
if (!dev->input) {
|
||||||
|
kfree(dev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(input_allocate_polled_device);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* input_free_polled_device - free memory allocated for polled device
|
||||||
|
* @dev: device to free
|
||||||
|
*
|
||||||
|
* The function frees memory allocated for polling device and drops
|
||||||
|
* reference to the associated input device (if present).
|
||||||
|
*/
|
||||||
|
void input_free_polled_device(struct input_polled_dev *dev)
|
||||||
|
{
|
||||||
|
if (dev) {
|
||||||
|
input_free_device(dev->input);
|
||||||
|
kfree(dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(input_free_polled_device);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* input_register_polled_device - register polled device
|
||||||
|
* @dev: device to register
|
||||||
|
*
|
||||||
|
* The function registers previously initialized polled input device
|
||||||
|
* with input layer. The device should be allocated with call to
|
||||||
|
* input_allocate_polled_device(). Callers should also set up poll()
|
||||||
|
* method and set up capabilities (id, name, phys, bits) of the
|
||||||
|
* corresponing input_dev structure.
|
||||||
|
*/
|
||||||
|
int input_register_polled_device(struct input_polled_dev *dev)
|
||||||
|
{
|
||||||
|
struct input_dev *input = dev->input;
|
||||||
|
|
||||||
|
INIT_DELAYED_WORK(&dev->work, input_polled_device_work);
|
||||||
|
if (!dev->poll_interval)
|
||||||
|
dev->poll_interval = 500;
|
||||||
|
input->private = dev;
|
||||||
|
input->open = input_open_polled_device;
|
||||||
|
input->close = input_close_polled_device;
|
||||||
|
|
||||||
|
return input_register_device(input);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(input_register_polled_device);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* input_unregister_polled_device - unregister polled device
|
||||||
|
* @dev: device to unregister
|
||||||
|
*
|
||||||
|
* The function unregisters previously registered polled input
|
||||||
|
* device from input layer. Polling is stopped and device is
|
||||||
|
* ready to be freed with call to input_free_polled_device().
|
||||||
|
* Callers should not attempt to access dev->input pointer
|
||||||
|
* after calling this function.
|
||||||
|
*/
|
||||||
|
void input_unregister_polled_device(struct input_polled_dev *dev)
|
||||||
|
{
|
||||||
|
input_unregister_device(dev->input);
|
||||||
|
dev->input = NULL;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(input_unregister_polled_device);
|
||||||
|
|
|
@ -51,7 +51,7 @@ static void ixp4xx_spkr_control(unsigned int pin, unsigned int count)
|
||||||
|
|
||||||
static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
||||||
{
|
{
|
||||||
unsigned int pin = (unsigned int) dev->private;
|
unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
|
||||||
unsigned int count = 0;
|
unsigned int count = 0;
|
||||||
|
|
||||||
if (type != EV_SND)
|
if (type != EV_SND)
|
||||||
|
@ -99,14 +99,15 @@ static int __devinit ixp4xx_spkr_probe(struct platform_device *dev)
|
||||||
if (!input_dev)
|
if (!input_dev)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
input_dev->private = (void *) dev->id;
|
input_set_drvdata(input_dev, (void *) dev->id);
|
||||||
|
|
||||||
input_dev->name = "ixp4xx beeper",
|
input_dev->name = "ixp4xx beeper",
|
||||||
input_dev->phys = "ixp4xx/gpio";
|
input_dev->phys = "ixp4xx/gpio";
|
||||||
input_dev->id.bustype = BUS_HOST;
|
input_dev->id.bustype = BUS_HOST;
|
||||||
input_dev->id.vendor = 0x001f;
|
input_dev->id.vendor = 0x001f;
|
||||||
input_dev->id.product = 0x0001;
|
input_dev->id.product = 0x0001;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &dev->dev;
|
input_dev->dev.parent = &dev->dev;
|
||||||
|
|
||||||
input_dev->evbit[0] = BIT(EV_SND);
|
input_dev->evbit[0] = BIT(EV_SND);
|
||||||
input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
|
input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
|
||||||
|
@ -136,7 +137,7 @@ static int __devinit ixp4xx_spkr_probe(struct platform_device *dev)
|
||||||
static int __devexit ixp4xx_spkr_remove(struct platform_device *dev)
|
static int __devexit ixp4xx_spkr_remove(struct platform_device *dev)
|
||||||
{
|
{
|
||||||
struct input_dev *input_dev = platform_get_drvdata(dev);
|
struct input_dev *input_dev = platform_get_drvdata(dev);
|
||||||
unsigned int pin = (unsigned int) input_dev->private;
|
unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
|
||||||
|
|
||||||
input_unregister_device(input_dev);
|
input_unregister_device(input_dev);
|
||||||
platform_set_drvdata(dev, NULL);
|
platform_set_drvdata(dev, NULL);
|
||||||
|
@ -153,7 +154,7 @@ static int __devexit ixp4xx_spkr_remove(struct platform_device *dev)
|
||||||
static void ixp4xx_spkr_shutdown(struct platform_device *dev)
|
static void ixp4xx_spkr_shutdown(struct platform_device *dev)
|
||||||
{
|
{
|
||||||
struct input_dev *input_dev = platform_get_drvdata(dev);
|
struct input_dev *input_dev = platform_get_drvdata(dev);
|
||||||
unsigned int pin = (unsigned int) input_dev->private;
|
unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
|
||||||
|
|
||||||
/* turn off the speaker */
|
/* turn off the speaker */
|
||||||
disable_irq(IRQ_IXP4XX_TIMER2);
|
disable_irq(IRQ_IXP4XX_TIMER2);
|
||||||
|
|
|
@ -63,7 +63,7 @@ static int __devinit m68kspkr_probe(struct platform_device *dev)
|
||||||
input_dev->id.vendor = 0x001f;
|
input_dev->id.vendor = 0x001f;
|
||||||
input_dev->id.product = 0x0001;
|
input_dev->id.product = 0x0001;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &dev->dev;
|
input_dev->dev.parent = &dev->dev;
|
||||||
|
|
||||||
input_dev->evbit[0] = BIT(EV_SND);
|
input_dev->evbit[0] = BIT(EV_SND);
|
||||||
input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
|
input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
|
||||||
|
|
|
@ -78,7 +78,7 @@ static int __devinit pcspkr_probe(struct platform_device *dev)
|
||||||
pcspkr_dev->id.vendor = 0x001f;
|
pcspkr_dev->id.vendor = 0x001f;
|
||||||
pcspkr_dev->id.product = 0x0001;
|
pcspkr_dev->id.product = 0x0001;
|
||||||
pcspkr_dev->id.version = 0x0100;
|
pcspkr_dev->id.version = 0x0100;
|
||||||
pcspkr_dev->cdev.dev = &dev->dev;
|
pcspkr_dev->dev.parent = &dev->dev;
|
||||||
|
|
||||||
pcspkr_dev->evbit[0] = BIT(EV_SND);
|
pcspkr_dev->evbit[0] = BIT(EV_SND);
|
||||||
pcspkr_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
|
pcspkr_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
|
||||||
|
|
|
@ -28,7 +28,7 @@ struct sparcspkr_state {
|
||||||
|
|
||||||
static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
||||||
{
|
{
|
||||||
struct sparcspkr_state *state = dev_get_drvdata(dev->cdev.dev);
|
struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
|
||||||
unsigned int count = 0;
|
unsigned int count = 0;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned in
|
||||||
|
|
||||||
static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
||||||
{
|
{
|
||||||
struct sparcspkr_state *state = dev_get_drvdata(dev->cdev.dev);
|
struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
|
||||||
unsigned int count = 0;
|
unsigned int count = 0;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ static int __devinit sparcspkr_probe(struct device *dev)
|
||||||
input_dev->id.vendor = 0x001f;
|
input_dev->id.vendor = 0x001f;
|
||||||
input_dev->id.product = 0x0001;
|
input_dev->id.product = 0x0001;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = dev;
|
input_dev->dev.parent = dev;
|
||||||
|
|
||||||
input_dev->evbit[0] = BIT(EV_SND);
|
input_dev->evbit[0] = BIT(EV_SND);
|
||||||
input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
|
input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
|
||||||
|
|
|
@ -41,9 +41,7 @@
|
||||||
|
|
||||||
static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
||||||
{
|
{
|
||||||
struct uinput_device *udev;
|
struct uinput_device *udev = input_get_drvdata(dev);
|
||||||
|
|
||||||
udev = dev->private;
|
|
||||||
|
|
||||||
udev->buff[udev->head].type = type;
|
udev->buff[udev->head].type = type;
|
||||||
udev->buff[udev->head].code = code;
|
udev->buff[udev->head].code = code;
|
||||||
|
@ -136,7 +134,7 @@ static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *eff
|
||||||
request.u.upload.effect = effect;
|
request.u.upload.effect = effect;
|
||||||
request.u.upload.old = old;
|
request.u.upload.old = old;
|
||||||
|
|
||||||
retval = uinput_request_reserve_slot(dev->private, &request);
|
retval = uinput_request_reserve_slot(input_get_drvdata(dev), &request);
|
||||||
if (!retval)
|
if (!retval)
|
||||||
retval = uinput_request_submit(dev, &request);
|
retval = uinput_request_submit(dev, &request);
|
||||||
|
|
||||||
|
@ -156,7 +154,7 @@ static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
|
||||||
request.code = UI_FF_ERASE;
|
request.code = UI_FF_ERASE;
|
||||||
request.u.effect_id = effect_id;
|
request.u.effect_id = effect_id;
|
||||||
|
|
||||||
retval = uinput_request_reserve_slot(dev->private, &request);
|
retval = uinput_request_reserve_slot(input_get_drvdata(dev), &request);
|
||||||
if (!retval)
|
if (!retval)
|
||||||
retval = uinput_request_submit(dev, &request);
|
retval = uinput_request_submit(dev, &request);
|
||||||
|
|
||||||
|
@ -274,7 +272,7 @@ 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->private = udev;
|
input_set_drvdata(udev->dev, udev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
MODULE_AUTHOR("Miloslav Trmac <mitr@volny.cz>");
|
MODULE_AUTHOR("Miloslav Trmac <mitr@volny.cz>");
|
||||||
MODULE_DESCRIPTION("Wistron laptop button driver");
|
MODULE_DESCRIPTION("Wistron laptop button driver");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
MODULE_VERSION("0.1");
|
MODULE_VERSION("0.2");
|
||||||
|
|
||||||
static int force; /* = 0; */
|
static int force; /* = 0; */
|
||||||
module_param(force, bool, 0);
|
module_param(force, bool, 0);
|
||||||
|
@ -58,7 +58,7 @@ MODULE_PARM_DESC(force, "Load even if computer is not in database");
|
||||||
|
|
||||||
static char *keymap_name; /* = NULL; */
|
static char *keymap_name; /* = NULL; */
|
||||||
module_param_named(keymap, keymap_name, charp, 0);
|
module_param_named(keymap, keymap_name, charp, 0);
|
||||||
MODULE_PARM_DESC(keymap, "Keymap name, if it can't be autodetected");
|
MODULE_PARM_DESC(keymap, "Keymap name, if it can't be autodetected [generic, 1557/MS2141]");
|
||||||
|
|
||||||
static struct platform_device *wistron_device;
|
static struct platform_device *wistron_device;
|
||||||
|
|
||||||
|
@ -233,10 +233,20 @@ static void bios_set_state(u8 subsys, int enable)
|
||||||
struct key_entry {
|
struct key_entry {
|
||||||
char type; /* See KE_* below */
|
char type; /* See KE_* below */
|
||||||
u8 code;
|
u8 code;
|
||||||
unsigned keycode; /* For KE_KEY */
|
union {
|
||||||
|
u16 keycode; /* For KE_KEY */
|
||||||
|
struct { /* For KE_SW */
|
||||||
|
u8 code;
|
||||||
|
u8 value;
|
||||||
|
} sw;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
enum { KE_END, KE_KEY, KE_WIFI, KE_BLUETOOTH };
|
enum { KE_END, KE_KEY, KE_SW, KE_WIFI, KE_BLUETOOTH };
|
||||||
|
|
||||||
|
#define FE_MAIL_LED 0x01
|
||||||
|
#define FE_WIFI_LED 0x02
|
||||||
|
#define FE_UNTESTED 0x80
|
||||||
|
|
||||||
static const struct key_entry *keymap; /* = NULL; Current key map */
|
static const struct key_entry *keymap; /* = NULL; Current key map */
|
||||||
static int have_wifi;
|
static int have_wifi;
|
||||||
|
@ -256,93 +266,341 @@ static int __init dmi_matched(struct dmi_system_id *dmi)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct key_entry keymap_empty[] = {
|
static struct key_entry keymap_empty[] __initdata = {
|
||||||
{ KE_END, 0 }
|
{ KE_END, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct key_entry keymap_fs_amilo_pro_v2000[] = {
|
static struct key_entry keymap_fs_amilo_pro_v2000[] __initdata = {
|
||||||
{ KE_KEY, 0x01, KEY_HELP },
|
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||||
{ KE_KEY, 0x11, KEY_PROG1 },
|
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||||
{ KE_KEY, 0x12, KEY_PROG2 },
|
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||||
{ KE_WIFI, 0x30, 0 },
|
{ KE_WIFI, 0x30 },
|
||||||
{ KE_KEY, 0x31, KEY_MAIL },
|
{ KE_KEY, 0x31, {KEY_MAIL} },
|
||||||
{ KE_KEY, 0x36, KEY_WWW },
|
{ KE_KEY, 0x36, {KEY_WWW} },
|
||||||
{ KE_END, 0 }
|
{ KE_END, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct key_entry keymap_fujitsu_n3510[] = {
|
static struct key_entry keymap_fujitsu_n3510[] __initdata = {
|
||||||
{ KE_KEY, 0x11, KEY_PROG1 },
|
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||||
{ KE_KEY, 0x12, KEY_PROG2 },
|
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||||
{ KE_KEY, 0x36, KEY_WWW },
|
{ KE_KEY, 0x36, {KEY_WWW} },
|
||||||
{ KE_KEY, 0x31, KEY_MAIL },
|
{ KE_KEY, 0x31, {KEY_MAIL} },
|
||||||
{ KE_KEY, 0x71, KEY_STOPCD },
|
{ KE_KEY, 0x71, {KEY_STOPCD} },
|
||||||
{ KE_KEY, 0x72, KEY_PLAYPAUSE },
|
{ KE_KEY, 0x72, {KEY_PLAYPAUSE} },
|
||||||
{ KE_KEY, 0x74, KEY_REWIND },
|
{ KE_KEY, 0x74, {KEY_REWIND} },
|
||||||
{ KE_KEY, 0x78, KEY_FORWARD },
|
{ KE_KEY, 0x78, {KEY_FORWARD} },
|
||||||
{ KE_END, 0 }
|
{ KE_END, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct key_entry keymap_wistron_ms2111[] = {
|
static struct key_entry keymap_wistron_ms2111[] __initdata = {
|
||||||
{ KE_KEY, 0x11, KEY_PROG1 },
|
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||||
{ KE_KEY, 0x12, KEY_PROG2 },
|
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||||
{ KE_KEY, 0x13, KEY_PROG3 },
|
{ KE_KEY, 0x13, {KEY_PROG3} },
|
||||||
{ KE_KEY, 0x31, KEY_MAIL },
|
{ KE_KEY, 0x31, {KEY_MAIL} },
|
||||||
{ KE_KEY, 0x36, KEY_WWW },
|
{ KE_KEY, 0x36, {KEY_WWW} },
|
||||||
|
{ KE_END, FE_MAIL_LED }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct key_entry keymap_wistron_md40100[] __initdata = {
|
||||||
|
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||||
|
{ KE_KEY, 0x02, {KEY_CONFIG} },
|
||||||
|
{ KE_KEY, 0x31, {KEY_MAIL} },
|
||||||
|
{ KE_KEY, 0x36, {KEY_WWW} },
|
||||||
|
{ KE_KEY, 0x37, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
|
||||||
|
{ KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct key_entry keymap_wistron_ms2141[] __initdata = {
|
||||||
|
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||||
|
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||||
|
{ KE_WIFI, 0x30 },
|
||||||
|
{ KE_KEY, 0x22, {KEY_REWIND} },
|
||||||
|
{ KE_KEY, 0x23, {KEY_FORWARD} },
|
||||||
|
{ KE_KEY, 0x24, {KEY_PLAYPAUSE} },
|
||||||
|
{ KE_KEY, 0x25, {KEY_STOPCD} },
|
||||||
|
{ KE_KEY, 0x31, {KEY_MAIL} },
|
||||||
|
{ KE_KEY, 0x36, {KEY_WWW} },
|
||||||
{ KE_END, 0 }
|
{ KE_END, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct key_entry keymap_wistron_ms2141[] = {
|
static struct key_entry keymap_acer_aspire_1500[] __initdata = {
|
||||||
{ KE_KEY, 0x11, KEY_PROG1 },
|
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||||
{ KE_KEY, 0x12, KEY_PROG2 },
|
{ KE_KEY, 0x03, {KEY_POWER} },
|
||||||
{ KE_WIFI, 0x30, 0 },
|
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||||
{ KE_KEY, 0x22, KEY_REWIND },
|
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||||
{ KE_KEY, 0x23, KEY_FORWARD },
|
{ KE_WIFI, 0x30 },
|
||||||
{ KE_KEY, 0x24, KEY_PLAYPAUSE },
|
{ KE_KEY, 0x31, {KEY_MAIL} },
|
||||||
{ KE_KEY, 0x25, KEY_STOPCD },
|
{ KE_KEY, 0x36, {KEY_WWW} },
|
||||||
{ KE_KEY, 0x31, KEY_MAIL },
|
{ KE_KEY, 0x49, {KEY_CONFIG} },
|
||||||
{ KE_KEY, 0x36, KEY_WWW },
|
{ KE_BLUETOOTH, 0x44 },
|
||||||
{ KE_END, 0 }
|
{ KE_END, FE_UNTESTED }
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct key_entry keymap_acer_aspire_1500[] = {
|
static struct key_entry keymap_acer_aspire_1600[] __initdata = {
|
||||||
{ KE_KEY, 0x11, KEY_PROG1 },
|
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||||
{ KE_KEY, 0x12, KEY_PROG2 },
|
{ KE_KEY, 0x03, {KEY_POWER} },
|
||||||
{ KE_WIFI, 0x30, 0 },
|
{ KE_KEY, 0x08, {KEY_MUTE} },
|
||||||
{ KE_KEY, 0x31, KEY_MAIL },
|
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||||
{ KE_KEY, 0x36, KEY_WWW },
|
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||||
{ KE_BLUETOOTH, 0x44, 0 },
|
{ KE_KEY, 0x13, {KEY_PROG3} },
|
||||||
{ KE_END, 0 }
|
{ KE_KEY, 0x31, {KEY_MAIL} },
|
||||||
|
{ KE_KEY, 0x36, {KEY_WWW} },
|
||||||
|
{ KE_KEY, 0x49, {KEY_CONFIG} },
|
||||||
|
{ KE_WIFI, 0x30 },
|
||||||
|
{ KE_BLUETOOTH, 0x44 },
|
||||||
|
{ KE_END, FE_MAIL_LED | FE_UNTESTED }
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct key_entry keymap_acer_travelmate_240[] = {
|
/* 3020 has been tested */
|
||||||
{ KE_KEY, 0x31, KEY_MAIL },
|
static struct key_entry keymap_acer_aspire_5020[] __initdata = {
|
||||||
{ KE_KEY, 0x36, KEY_WWW },
|
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||||
{ KE_KEY, 0x11, KEY_PROG1 },
|
{ KE_KEY, 0x03, {KEY_POWER} },
|
||||||
{ KE_KEY, 0x12, KEY_PROG2 },
|
{ KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */
|
||||||
{ KE_BLUETOOTH, 0x44, 0 },
|
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||||
{ KE_WIFI, 0x30, 0 },
|
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||||
{ KE_END, 0 }
|
{ KE_KEY, 0x31, {KEY_MAIL} },
|
||||||
|
{ KE_KEY, 0x36, {KEY_WWW} },
|
||||||
|
{ KE_KEY, 0x6a, {KEY_CONFIG} },
|
||||||
|
{ KE_WIFI, 0x30 },
|
||||||
|
{ KE_BLUETOOTH, 0x44 },
|
||||||
|
{ KE_END, FE_MAIL_LED | FE_UNTESTED }
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct key_entry keymap_aopen_1559as[] = {
|
static struct key_entry keymap_acer_travelmate_2410[] __initdata = {
|
||||||
{ KE_KEY, 0x01, KEY_HELP },
|
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||||
{ KE_KEY, 0x06, KEY_PROG3 },
|
{ KE_KEY, 0x6d, {KEY_POWER} },
|
||||||
{ KE_KEY, 0x11, KEY_PROG1 },
|
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||||
{ KE_KEY, 0x12, KEY_PROG2 },
|
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||||
{ KE_WIFI, 0x30, 0 },
|
{ KE_KEY, 0x31, {KEY_MAIL} },
|
||||||
{ KE_KEY, 0x31, KEY_MAIL },
|
{ KE_KEY, 0x36, {KEY_WWW} },
|
||||||
{ KE_KEY, 0x36, KEY_WWW },
|
{ KE_KEY, 0x6a, {KEY_CONFIG} },
|
||||||
|
{ KE_WIFI, 0x30 },
|
||||||
|
{ KE_BLUETOOTH, 0x44 },
|
||||||
|
{ KE_END, FE_MAIL_LED | FE_UNTESTED }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct key_entry keymap_acer_travelmate_110[] __initdata = {
|
||||||
|
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||||
|
{ KE_KEY, 0x02, {KEY_CONFIG} },
|
||||||
|
{ KE_KEY, 0x03, {KEY_POWER} },
|
||||||
|
{ KE_KEY, 0x08, {KEY_MUTE} },
|
||||||
|
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||||
|
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||||
|
{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
|
||||||
|
{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
|
||||||
|
{ KE_KEY, 0x31, {KEY_MAIL} },
|
||||||
|
{ KE_KEY, 0x36, {KEY_WWW} },
|
||||||
|
{ KE_SW, 0x4a, {.sw = {SW_LID, 1}} }, /* lid close */
|
||||||
|
{ KE_SW, 0x4b, {.sw = {SW_LID, 0}} }, /* lid open */
|
||||||
|
{ KE_WIFI, 0x30 },
|
||||||
|
{ KE_END, FE_MAIL_LED | FE_UNTESTED }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct key_entry keymap_acer_travelmate_300[] __initdata = {
|
||||||
|
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||||
|
{ KE_KEY, 0x02, {KEY_CONFIG} },
|
||||||
|
{ KE_KEY, 0x03, {KEY_POWER} },
|
||||||
|
{ KE_KEY, 0x08, {KEY_MUTE} },
|
||||||
|
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||||
|
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||||
|
{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
|
||||||
|
{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
|
||||||
|
{ KE_KEY, 0x31, {KEY_MAIL} },
|
||||||
|
{ KE_KEY, 0x36, {KEY_WWW} },
|
||||||
|
{ KE_WIFI, 0x30 },
|
||||||
|
{ KE_BLUETOOTH, 0x44 },
|
||||||
|
{ KE_END, FE_MAIL_LED | FE_UNTESTED }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct key_entry keymap_acer_travelmate_380[] __initdata = {
|
||||||
|
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||||
|
{ KE_KEY, 0x02, {KEY_CONFIG} },
|
||||||
|
{ KE_KEY, 0x03, {KEY_POWER} }, /* not 370 */
|
||||||
|
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||||
|
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||||
|
{ KE_KEY, 0x13, {KEY_PROG3} },
|
||||||
|
{ KE_KEY, 0x31, {KEY_MAIL} },
|
||||||
|
{ KE_KEY, 0x36, {KEY_WWW} },
|
||||||
|
{ KE_WIFI, 0x30 },
|
||||||
|
{ KE_END, FE_MAIL_LED | FE_UNTESTED }
|
||||||
|
};
|
||||||
|
|
||||||
|
/* unusual map */
|
||||||
|
static struct key_entry keymap_acer_travelmate_220[] __initdata = {
|
||||||
|
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||||
|
{ KE_KEY, 0x02, {KEY_CONFIG} },
|
||||||
|
{ KE_KEY, 0x11, {KEY_MAIL} },
|
||||||
|
{ KE_KEY, 0x12, {KEY_WWW} },
|
||||||
|
{ KE_KEY, 0x13, {KEY_PROG2} },
|
||||||
|
{ KE_KEY, 0x31, {KEY_PROG1} },
|
||||||
|
{ KE_END, FE_WIFI_LED | FE_UNTESTED }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct key_entry keymap_acer_travelmate_230[] __initdata = {
|
||||||
|
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||||
|
{ KE_KEY, 0x02, {KEY_CONFIG} },
|
||||||
|
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||||
|
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||||
|
{ KE_KEY, 0x31, {KEY_MAIL} },
|
||||||
|
{ KE_KEY, 0x36, {KEY_WWW} },
|
||||||
|
{ KE_END, FE_WIFI_LED | FE_UNTESTED }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct key_entry keymap_acer_travelmate_240[] __initdata = {
|
||||||
|
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||||
|
{ KE_KEY, 0x02, {KEY_CONFIG} },
|
||||||
|
{ KE_KEY, 0x03, {KEY_POWER} },
|
||||||
|
{ KE_KEY, 0x08, {KEY_MUTE} },
|
||||||
|
{ KE_KEY, 0x31, {KEY_MAIL} },
|
||||||
|
{ KE_KEY, 0x36, {KEY_WWW} },
|
||||||
|
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||||
|
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||||
|
{ KE_BLUETOOTH, 0x44 },
|
||||||
|
{ KE_WIFI, 0x30 },
|
||||||
|
{ KE_END, FE_UNTESTED }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct key_entry keymap_acer_travelmate_350[] __initdata = {
|
||||||
|
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||||
|
{ KE_KEY, 0x02, {KEY_CONFIG} },
|
||||||
|
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||||
|
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||||
|
{ KE_KEY, 0x13, {KEY_MAIL} },
|
||||||
|
{ KE_KEY, 0x14, {KEY_PROG3} },
|
||||||
|
{ KE_KEY, 0x15, {KEY_WWW} },
|
||||||
|
{ KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct key_entry keymap_acer_travelmate_360[] __initdata = {
|
||||||
|
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||||
|
{ KE_KEY, 0x02, {KEY_CONFIG} },
|
||||||
|
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||||
|
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||||
|
{ KE_KEY, 0x13, {KEY_MAIL} },
|
||||||
|
{ KE_KEY, 0x14, {KEY_PROG3} },
|
||||||
|
{ KE_KEY, 0x15, {KEY_WWW} },
|
||||||
|
{ KE_KEY, 0x40, {KEY_WLAN} },
|
||||||
|
{ KE_END, FE_WIFI_LED | FE_UNTESTED } /* no mail led */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Wifi subsystem only activates the led. Therefore we need to pass
|
||||||
|
* wifi event as a normal key, then userspace can really change the wifi state.
|
||||||
|
* TODO we need to export led state to userspace (wifi and mail) */
|
||||||
|
static struct key_entry keymap_acer_travelmate_610[] __initdata = {
|
||||||
|
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||||
|
{ KE_KEY, 0x02, {KEY_CONFIG} },
|
||||||
|
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||||
|
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||||
|
{ KE_KEY, 0x13, {KEY_PROG3} },
|
||||||
|
{ KE_KEY, 0x14, {KEY_MAIL} },
|
||||||
|
{ KE_KEY, 0x15, {KEY_WWW} },
|
||||||
|
{ KE_KEY, 0x40, {KEY_WLAN} },
|
||||||
|
{ KE_END, FE_MAIL_LED | FE_WIFI_LED }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct key_entry keymap_acer_travelmate_630[] __initdata = {
|
||||||
|
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||||
|
{ KE_KEY, 0x02, {KEY_CONFIG} },
|
||||||
|
{ KE_KEY, 0x03, {KEY_POWER} },
|
||||||
|
{ KE_KEY, 0x08, {KEY_MUTE} }, /* not 620 */
|
||||||
|
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||||
|
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||||
|
{ KE_KEY, 0x13, {KEY_PROG3} },
|
||||||
|
{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
|
||||||
|
{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
|
||||||
|
{ KE_KEY, 0x31, {KEY_MAIL} },
|
||||||
|
{ KE_KEY, 0x36, {KEY_WWW} },
|
||||||
|
{ KE_WIFI, 0x30 },
|
||||||
|
{ KE_END, FE_MAIL_LED | FE_UNTESTED }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct key_entry keymap_aopen_1559as[] __initdata = {
|
||||||
|
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||||
|
{ KE_KEY, 0x06, {KEY_PROG3} },
|
||||||
|
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||||
|
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||||
|
{ KE_WIFI, 0x30 },
|
||||||
|
{ KE_KEY, 0x31, {KEY_MAIL} },
|
||||||
|
{ KE_KEY, 0x36, {KEY_WWW} },
|
||||||
{ KE_END, 0 },
|
{ KE_END, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct key_entry keymap_fs_amilo_d88x0[] = {
|
static struct key_entry keymap_fs_amilo_d88x0[] __initdata = {
|
||||||
{ KE_KEY, 0x01, KEY_HELP },
|
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||||
{ KE_KEY, 0x08, KEY_MUTE },
|
{ KE_KEY, 0x08, {KEY_MUTE} },
|
||||||
{ KE_KEY, 0x31, KEY_MAIL },
|
{ KE_KEY, 0x31, {KEY_MAIL} },
|
||||||
{ KE_KEY, 0x36, KEY_WWW },
|
{ KE_KEY, 0x36, {KEY_WWW} },
|
||||||
{ KE_KEY, 0x11, KEY_PROG1 },
|
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||||
{ KE_KEY, 0x12, KEY_PROG2 },
|
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||||
{ KE_KEY, 0x13, KEY_PROG3 },
|
{ KE_KEY, 0x13, {KEY_PROG3} },
|
||||||
|
{ KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct key_entry keymap_wistron_md2900[] __initdata = {
|
||||||
|
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||||
|
{ KE_KEY, 0x02, {KEY_CONFIG} },
|
||||||
|
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||||
|
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||||
|
{ KE_KEY, 0x31, {KEY_MAIL} },
|
||||||
|
{ KE_KEY, 0x36, {KEY_WWW} },
|
||||||
|
{ KE_WIFI, 0x30 },
|
||||||
|
{ KE_END, FE_MAIL_LED | FE_UNTESTED }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct key_entry keymap_wistron_md96500[] __initdata = {
|
||||||
|
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||||
|
{ KE_KEY, 0x02, {KEY_CONFIG} },
|
||||||
|
{ KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */
|
||||||
|
{ KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
|
||||||
|
{ KE_KEY, 0x08, {KEY_MUTE} },
|
||||||
|
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||||
|
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||||
|
{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
|
||||||
|
{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
|
||||||
|
{ KE_KEY, 0x22, {KEY_REWIND} },
|
||||||
|
{ KE_KEY, 0x23, {KEY_FORWARD} },
|
||||||
|
{ KE_KEY, 0x24, {KEY_PLAYPAUSE} },
|
||||||
|
{ KE_KEY, 0x25, {KEY_STOPCD} },
|
||||||
|
{ KE_KEY, 0x31, {KEY_MAIL} },
|
||||||
|
{ KE_KEY, 0x36, {KEY_WWW} },
|
||||||
|
{ KE_WIFI, 0x30 },
|
||||||
|
{ KE_BLUETOOTH, 0x44 },
|
||||||
|
{ KE_END, FE_UNTESTED }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct key_entry keymap_wistron_generic[] __initdata = {
|
||||||
|
{ KE_KEY, 0x01, {KEY_HELP} },
|
||||||
|
{ KE_KEY, 0x02, {KEY_CONFIG} },
|
||||||
|
{ KE_KEY, 0x03, {KEY_POWER} },
|
||||||
|
{ KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */
|
||||||
|
{ KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
|
||||||
|
{ KE_KEY, 0x08, {KEY_MUTE} },
|
||||||
|
{ KE_KEY, 0x11, {KEY_PROG1} },
|
||||||
|
{ KE_KEY, 0x12, {KEY_PROG2} },
|
||||||
|
{ KE_KEY, 0x13, {KEY_PROG3} },
|
||||||
|
{ KE_KEY, 0x14, {KEY_MAIL} },
|
||||||
|
{ KE_KEY, 0x15, {KEY_WWW} },
|
||||||
|
{ KE_KEY, 0x20, {KEY_VOLUMEUP} },
|
||||||
|
{ KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
|
||||||
|
{ KE_KEY, 0x22, {KEY_REWIND} },
|
||||||
|
{ KE_KEY, 0x23, {KEY_FORWARD} },
|
||||||
|
{ KE_KEY, 0x24, {KEY_PLAYPAUSE} },
|
||||||
|
{ KE_KEY, 0x25, {KEY_STOPCD} },
|
||||||
|
{ KE_KEY, 0x31, {KEY_MAIL} },
|
||||||
|
{ KE_KEY, 0x36, {KEY_WWW} },
|
||||||
|
{ KE_KEY, 0x37, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
|
||||||
|
{ KE_KEY, 0x40, {KEY_WLAN} },
|
||||||
|
{ KE_KEY, 0x49, {KEY_CONFIG} },
|
||||||
|
{ KE_SW, 0x4a, {.sw = {SW_LID, 1}} }, /* lid close */
|
||||||
|
{ KE_SW, 0x4b, {.sw = {SW_LID, 0}} }, /* lid open */
|
||||||
|
{ KE_KEY, 0x6a, {KEY_CONFIG} },
|
||||||
|
{ KE_KEY, 0x6d, {KEY_POWER} },
|
||||||
|
{ KE_KEY, 0x71, {KEY_STOPCD} },
|
||||||
|
{ KE_KEY, 0x72, {KEY_PLAYPAUSE} },
|
||||||
|
{ KE_KEY, 0x74, {KEY_REWIND} },
|
||||||
|
{ KE_KEY, 0x78, {KEY_FORWARD} },
|
||||||
|
{ KE_WIFI, 0x30 },
|
||||||
|
{ KE_BLUETOOTH, 0x44 },
|
||||||
{ KE_END, 0 }
|
{ KE_END, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -388,6 +646,133 @@ static struct dmi_system_id dmi_ids[] __initdata = {
|
||||||
},
|
},
|
||||||
.driver_data = keymap_acer_aspire_1500
|
.driver_data = keymap_acer_aspire_1500
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Acer Aspire 1600",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1600"),
|
||||||
|
},
|
||||||
|
.driver_data = keymap_acer_aspire_1600
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Acer Aspire 3020",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3020"),
|
||||||
|
},
|
||||||
|
.driver_data = keymap_acer_aspire_5020
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Acer Aspire 5020",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5020"),
|
||||||
|
},
|
||||||
|
.driver_data = keymap_acer_aspire_5020
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Acer TravelMate 2100",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2100"),
|
||||||
|
},
|
||||||
|
.driver_data = keymap_acer_aspire_5020
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Acer TravelMate 2410",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2410"),
|
||||||
|
},
|
||||||
|
.driver_data = keymap_acer_travelmate_2410
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Acer TravelMate C300",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C300"),
|
||||||
|
},
|
||||||
|
.driver_data = keymap_acer_travelmate_300
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Acer TravelMate C100",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C100"),
|
||||||
|
},
|
||||||
|
.driver_data = keymap_acer_travelmate_300
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Acer TravelMate C110",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C110"),
|
||||||
|
},
|
||||||
|
.driver_data = keymap_acer_travelmate_110
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Acer TravelMate 380",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 380"),
|
||||||
|
},
|
||||||
|
.driver_data = keymap_acer_travelmate_380
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Acer TravelMate 370",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 370"),
|
||||||
|
},
|
||||||
|
.driver_data = keymap_acer_travelmate_380 /* keyboard minus 1 key */
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Acer TravelMate 220",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 220"),
|
||||||
|
},
|
||||||
|
.driver_data = keymap_acer_travelmate_220
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Acer TravelMate 260",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 260"),
|
||||||
|
},
|
||||||
|
.driver_data = keymap_acer_travelmate_220
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Acer TravelMate 230",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 230"),
|
||||||
|
/* acerhk looks for "TravelMate F4..." ?! */
|
||||||
|
},
|
||||||
|
.driver_data = keymap_acer_travelmate_230
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Acer TravelMate 280",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 280"),
|
||||||
|
},
|
||||||
|
.driver_data = keymap_acer_travelmate_230
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.callback = dmi_matched,
|
.callback = dmi_matched,
|
||||||
.ident = "Acer TravelMate 240",
|
.ident = "Acer TravelMate 240",
|
||||||
|
@ -397,6 +782,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 250",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 250"),
|
||||||
|
},
|
||||||
|
.driver_data = keymap_acer_travelmate_240
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.callback = dmi_matched,
|
.callback = dmi_matched,
|
||||||
.ident = "Acer TravelMate 2424NWXCi",
|
.ident = "Acer TravelMate 2424NWXCi",
|
||||||
|
@ -406,6 +800,51 @@ 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 350",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 350"),
|
||||||
|
},
|
||||||
|
.driver_data = keymap_acer_travelmate_350
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Acer TravelMate 360",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
|
||||||
|
},
|
||||||
|
.driver_data = keymap_acer_travelmate_360
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Acer TravelMate 610",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "ACER"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 610"),
|
||||||
|
},
|
||||||
|
.driver_data = keymap_acer_travelmate_610
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Acer TravelMate 620",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 620"),
|
||||||
|
},
|
||||||
|
.driver_data = keymap_acer_travelmate_630
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Acer TravelMate 630",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 630"),
|
||||||
|
},
|
||||||
|
.driver_data = keymap_acer_travelmate_630
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.callback = dmi_matched,
|
.callback = dmi_matched,
|
||||||
.ident = "AOpen 1559AS",
|
.ident = "AOpen 1559AS",
|
||||||
|
@ -424,6 +863,51 @@ static struct dmi_system_id dmi_ids[] __initdata = {
|
||||||
},
|
},
|
||||||
.driver_data = keymap_wistron_ms2111
|
.driver_data = keymap_wistron_ms2111
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Medion MD 40100",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "WID2000"),
|
||||||
|
},
|
||||||
|
.driver_data = keymap_wistron_md40100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Medion MD 2900",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2000"),
|
||||||
|
},
|
||||||
|
.driver_data = keymap_wistron_md2900
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Medion MD 96500",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2040"),
|
||||||
|
},
|
||||||
|
.driver_data = keymap_wistron_md96500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Medion MD 95400",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2050"),
|
||||||
|
},
|
||||||
|
.driver_data = keymap_wistron_md96500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Fujitsu Siemens Amilo D7820",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), /* not sure */
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "Amilo D"),
|
||||||
|
},
|
||||||
|
.driver_data = keymap_fs_amilo_d88x0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.callback = dmi_matched,
|
.callback = dmi_matched,
|
||||||
.ident = "Fujitsu Siemens Amilo D88x0",
|
.ident = "Fujitsu Siemens Amilo D88x0",
|
||||||
|
@ -436,17 +920,39 @@ static struct dmi_system_id dmi_ids[] __initdata = {
|
||||||
{ NULL, }
|
{ NULL, }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Copy the good keymap, as the original ones are free'd */
|
||||||
|
static int __init copy_keymap(void)
|
||||||
|
{
|
||||||
|
const struct key_entry *key;
|
||||||
|
struct key_entry *new_keymap;
|
||||||
|
unsigned int length = 1;
|
||||||
|
|
||||||
|
for (key = keymap; key->type != KE_END; key++)
|
||||||
|
length++;
|
||||||
|
|
||||||
|
new_keymap = kmalloc(length * sizeof(struct key_entry), GFP_KERNEL);
|
||||||
|
if (!new_keymap)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
memcpy(new_keymap, keymap, length * sizeof(struct key_entry));
|
||||||
|
keymap = new_keymap;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int __init select_keymap(void)
|
static int __init select_keymap(void)
|
||||||
{
|
{
|
||||||
|
dmi_check_system(dmi_ids);
|
||||||
if (keymap_name != NULL) {
|
if (keymap_name != NULL) {
|
||||||
if (strcmp (keymap_name, "1557/MS2141") == 0)
|
if (strcmp (keymap_name, "1557/MS2141") == 0)
|
||||||
keymap = keymap_wistron_ms2141;
|
keymap = keymap_wistron_ms2141;
|
||||||
|
else if (strcmp (keymap_name, "generic") == 0)
|
||||||
|
keymap = keymap_wistron_generic;
|
||||||
else {
|
else {
|
||||||
printk(KERN_ERR "wistron_btns: Keymap unknown\n");
|
printk(KERN_ERR "wistron_btns: Keymap unknown\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dmi_check_system(dmi_ids);
|
|
||||||
if (keymap == NULL) {
|
if (keymap == NULL) {
|
||||||
if (!force) {
|
if (!force) {
|
||||||
printk(KERN_ERR "wistron_btns: System unknown\n");
|
printk(KERN_ERR "wistron_btns: System unknown\n");
|
||||||
|
@ -454,7 +960,8 @@ static int __init select_keymap(void)
|
||||||
}
|
}
|
||||||
keymap = keymap_empty;
|
keymap = keymap_empty;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
return copy_keymap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Input layer interface */
|
/* Input layer interface */
|
||||||
|
@ -476,12 +983,28 @@ static int __devinit setup_input_dev(void)
|
||||||
input_dev->cdev.dev = &wistron_device->dev;
|
input_dev->cdev.dev = &wistron_device->dev;
|
||||||
|
|
||||||
for (key = keymap; key->type != KE_END; key++) {
|
for (key = keymap; key->type != KE_END; key++) {
|
||||||
if (key->type == KE_KEY) {
|
switch (key->type) {
|
||||||
input_dev->evbit[LONG(EV_KEY)] = BIT(EV_KEY);
|
case KE_KEY:
|
||||||
|
set_bit(EV_KEY, input_dev->evbit);
|
||||||
set_bit(key->keycode, input_dev->keybit);
|
set_bit(key->keycode, input_dev->keybit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KE_SW:
|
||||||
|
set_bit(EV_SW, input_dev->evbit);
|
||||||
|
set_bit(key->sw.code, input_dev->swbit);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* reads information flags on KE_END */
|
||||||
|
if (key->code & FE_UNTESTED)
|
||||||
|
printk(KERN_WARNING "Untested laptop multimedia keys, "
|
||||||
|
"please report success or failure to eric.piel"
|
||||||
|
"@tremplin-utc.net\n");
|
||||||
|
|
||||||
error = input_register_device(input_dev);
|
error = input_register_device(input_dev);
|
||||||
if (error) {
|
if (error) {
|
||||||
input_free_device(input_dev);
|
input_free_device(input_dev);
|
||||||
|
@ -499,6 +1022,12 @@ static void report_key(unsigned keycode)
|
||||||
input_sync(input_dev);
|
input_sync(input_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void report_switch(unsigned code, int value)
|
||||||
|
{
|
||||||
|
input_report_switch(input_dev, code, value);
|
||||||
|
input_sync(input_dev);
|
||||||
|
}
|
||||||
|
|
||||||
/* Driver core */
|
/* Driver core */
|
||||||
|
|
||||||
static int wifi_enabled;
|
static int wifi_enabled;
|
||||||
|
@ -519,6 +1048,10 @@ static void handle_key(u8 code)
|
||||||
report_key(key->keycode);
|
report_key(key->keycode);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case KE_SW:
|
||||||
|
report_switch(key->sw.code, key->sw.value);
|
||||||
|
break;
|
||||||
|
|
||||||
case KE_WIFI:
|
case KE_WIFI:
|
||||||
if (have_wifi) {
|
if (have_wifi) {
|
||||||
wifi_enabled = !wifi_enabled;
|
wifi_enabled = !wifi_enabled;
|
||||||
|
@ -534,6 +1067,7 @@ static void handle_key(u8 code)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KE_END:
|
case KE_END:
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
@ -690,6 +1224,7 @@ static void __exit wb_module_exit(void)
|
||||||
platform_device_unregister(wistron_device);
|
platform_device_unregister(wistron_device);
|
||||||
platform_driver_unregister(&wistron_driver);
|
platform_driver_unregister(&wistron_driver);
|
||||||
unmap_bios();
|
unmap_bios();
|
||||||
|
kfree(keymap);
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(wb_module_init);
|
module_init(wb_module_init);
|
||||||
|
|
|
@ -37,6 +37,65 @@ config MOUSE_PS2
|
||||||
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 psmouse.
|
module will be called psmouse.
|
||||||
|
|
||||||
|
config MOUSE_PS2_ALPS
|
||||||
|
bool "ALPS PS/2 mouse protocol extension" if EMBEDDED
|
||||||
|
default y
|
||||||
|
depends on MOUSE_PS2
|
||||||
|
---help---
|
||||||
|
Say Y here if you have an ALPS PS/2 touchpad connected to
|
||||||
|
your system.
|
||||||
|
|
||||||
|
If unsure, say Y.
|
||||||
|
|
||||||
|
config MOUSE_PS2_LOGIPS2PP
|
||||||
|
bool "Logictech PS/2++ mouse protocol extension" if EMBEDDED
|
||||||
|
default y
|
||||||
|
depends on MOUSE_PS2
|
||||||
|
---help---
|
||||||
|
Say Y here if you have a Logictech PS/2++ mouse connected to
|
||||||
|
your system.
|
||||||
|
|
||||||
|
If unsure, say Y.
|
||||||
|
|
||||||
|
config MOUSE_PS2_SYNAPTICS
|
||||||
|
bool "Synaptics PS/2 mouse protocol extension" if EMBEDDED
|
||||||
|
default y
|
||||||
|
depends on MOUSE_PS2
|
||||||
|
---help---
|
||||||
|
Say Y here if you have a Synaptics PS/2 TouchPad connected to
|
||||||
|
your system.
|
||||||
|
|
||||||
|
If unsure, say Y.
|
||||||
|
|
||||||
|
config MOUSE_PS2_LIFEBOOK
|
||||||
|
bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EMBEDDED
|
||||||
|
default y
|
||||||
|
depends on MOUSE_PS2
|
||||||
|
---help---
|
||||||
|
Say Y here if you have a Fujitsu B-series Lifebook PS/2
|
||||||
|
TouchScreen connected to your system.
|
||||||
|
|
||||||
|
If unsure, say Y.
|
||||||
|
|
||||||
|
config MOUSE_PS2_TRACKPOINT
|
||||||
|
bool "IBM Trackpoint PS/2 mouse protocol extension" if EMBEDDED
|
||||||
|
default y
|
||||||
|
depends on MOUSE_PS2
|
||||||
|
---help---
|
||||||
|
Say Y here if you have an IBM Trackpoint PS/2 mouse connected
|
||||||
|
to your system.
|
||||||
|
|
||||||
|
If unsure, say Y.
|
||||||
|
|
||||||
|
config MOUSE_PS2_TOUCHKIT
|
||||||
|
bool "eGalax TouchKit PS/2 protocol extension"
|
||||||
|
depends on MOUSE_PS2
|
||||||
|
---help---
|
||||||
|
Say Y here if you have an eGalax TouchKit PS/2 touchscreen
|
||||||
|
connected to your system.
|
||||||
|
|
||||||
|
If unsure, say N.
|
||||||
|
|
||||||
config MOUSE_SERIAL
|
config MOUSE_SERIAL
|
||||||
tristate "Serial mouse"
|
tristate "Serial mouse"
|
||||||
select SERIO
|
select SERIO
|
||||||
|
|
|
@ -15,4 +15,10 @@ obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o
|
||||||
obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o
|
obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o
|
||||||
obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o
|
obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o
|
||||||
|
|
||||||
psmouse-objs := psmouse-base.o alps.o logips2pp.o synaptics.o lifebook.o trackpoint.o
|
psmouse-objs := psmouse-base.o synaptics.o
|
||||||
|
|
||||||
|
psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o
|
||||||
|
psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) += logips2pp.o
|
||||||
|
psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o
|
||||||
|
psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o
|
||||||
|
psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o
|
||||||
|
|
|
@ -424,14 +424,15 @@ int alps_init(struct psmouse *psmouse)
|
||||||
struct input_dev *dev1 = psmouse->dev, *dev2;
|
struct input_dev *dev1 = psmouse->dev, *dev2;
|
||||||
int version;
|
int version;
|
||||||
|
|
||||||
psmouse->private = priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL);
|
priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL);
|
||||||
dev2 = input_allocate_device();
|
dev2 = input_allocate_device();
|
||||||
if (!priv || !dev2)
|
if (!priv || !dev2)
|
||||||
goto init_fail;
|
goto init_fail;
|
||||||
|
|
||||||
priv->dev2 = dev2;
|
priv->dev2 = dev2;
|
||||||
|
|
||||||
if (!(priv->i = alps_get_model(psmouse, &version)))
|
priv->i = alps_get_model(psmouse, &version);
|
||||||
|
if (!priv->i)
|
||||||
goto init_fail;
|
goto init_fail;
|
||||||
|
|
||||||
if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 1))
|
if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 1))
|
||||||
|
@ -480,7 +481,8 @@ int alps_init(struct psmouse *psmouse)
|
||||||
dev2->relbit[LONG(REL_X)] |= BIT(REL_X) | BIT(REL_Y);
|
dev2->relbit[LONG(REL_X)] |= BIT(REL_X) | BIT(REL_Y);
|
||||||
dev2->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
|
dev2->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
|
||||||
|
|
||||||
input_register_device(priv->dev2);
|
if (input_register_device(priv->dev2))
|
||||||
|
goto init_fail;
|
||||||
|
|
||||||
psmouse->protocol_handler = alps_process_byte;
|
psmouse->protocol_handler = alps_process_byte;
|
||||||
psmouse->poll = alps_poll;
|
psmouse->poll = alps_poll;
|
||||||
|
@ -491,9 +493,11 @@ int alps_init(struct psmouse *psmouse)
|
||||||
/* We are having trouble resyncing ALPS touchpads so disable it for now */
|
/* We are having trouble resyncing ALPS touchpads so disable it for now */
|
||||||
psmouse->resync_time = 0;
|
psmouse->resync_time = 0;
|
||||||
|
|
||||||
|
psmouse->private = priv;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
init_fail:
|
init_fail:
|
||||||
|
psmouse_reset(psmouse);
|
||||||
input_free_device(dev2);
|
input_free_device(dev2);
|
||||||
kfree(priv);
|
kfree(priv);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -504,7 +508,8 @@ int alps_detect(struct psmouse *psmouse, int set_properties)
|
||||||
int version;
|
int version;
|
||||||
const struct alps_model_info *model;
|
const struct alps_model_info *model;
|
||||||
|
|
||||||
if (!(model = alps_get_model(psmouse, &version)))
|
model = alps_get_model(psmouse, &version);
|
||||||
|
if (!model)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (set_properties) {
|
if (set_properties) {
|
||||||
|
|
|
@ -12,9 +12,6 @@
|
||||||
#ifndef _ALPS_H
|
#ifndef _ALPS_H
|
||||||
#define _ALPS_H
|
#define _ALPS_H
|
||||||
|
|
||||||
int alps_detect(struct psmouse *psmouse, int set_properties);
|
|
||||||
int alps_init(struct psmouse *psmouse);
|
|
||||||
|
|
||||||
struct alps_model_info {
|
struct alps_model_info {
|
||||||
unsigned char signature[3];
|
unsigned char signature[3];
|
||||||
unsigned char byte0, mask0;
|
unsigned char byte0, mask0;
|
||||||
|
@ -23,10 +20,23 @@ struct alps_model_info {
|
||||||
|
|
||||||
struct alps_data {
|
struct alps_data {
|
||||||
struct input_dev *dev2; /* Relative device */
|
struct input_dev *dev2; /* Relative device */
|
||||||
char name[32]; /* Name */
|
|
||||||
char phys[32]; /* Phys */
|
char phys[32]; /* Phys */
|
||||||
const 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 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_MOUSE_PS2_ALPS
|
||||||
|
int alps_detect(struct psmouse *psmouse, int set_properties);
|
||||||
|
int alps_init(struct psmouse *psmouse);
|
||||||
|
#else
|
||||||
|
inline int alps_detect(struct psmouse *psmouse, int set_properties)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
inline int alps_init(struct psmouse *psmouse)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_MOUSE_PS2_ALPS */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -89,9 +89,11 @@ static void hil_ptr_process_record(struct hil_ptr *ptr)
|
||||||
p = data[idx - 1];
|
p = data[idx - 1];
|
||||||
|
|
||||||
if ((p & ~HIL_CMDCT_POL) ==
|
if ((p & ~HIL_CMDCT_POL) ==
|
||||||
(HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) goto report;
|
(HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
|
||||||
|
goto report;
|
||||||
if ((p & ~HIL_CMDCT_RPL) ==
|
if ((p & ~HIL_CMDCT_RPL) ==
|
||||||
(HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) goto report;
|
(HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL))
|
||||||
|
goto report;
|
||||||
|
|
||||||
/* Not a poll response. See if we are loading config records. */
|
/* Not a poll response. See if we are loading config records. */
|
||||||
switch (p & HIL_PKT_DATA_MASK) {
|
switch (p & HIL_PKT_DATA_MASK) {
|
||||||
|
@ -101,27 +103,32 @@ static void hil_ptr_process_record(struct hil_ptr *ptr)
|
||||||
for (; i < HIL_PTR_MAX_LENGTH; i++)
|
for (; i < HIL_PTR_MAX_LENGTH; i++)
|
||||||
ptr->idd[i] = 0;
|
ptr->idd[i] = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HIL_CMD_RSC:
|
case HIL_CMD_RSC:
|
||||||
for (i = 0; i < idx; i++)
|
for (i = 0; i < idx; i++)
|
||||||
ptr->rsc[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
|
ptr->rsc[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
|
||||||
for (; i < HIL_PTR_MAX_LENGTH; i++)
|
for (; i < HIL_PTR_MAX_LENGTH; i++)
|
||||||
ptr->rsc[i] = 0;
|
ptr->rsc[i] = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HIL_CMD_EXD:
|
case HIL_CMD_EXD:
|
||||||
for (i = 0; i < idx; i++)
|
for (i = 0; i < idx; i++)
|
||||||
ptr->exd[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
|
ptr->exd[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
|
||||||
for (; i < HIL_PTR_MAX_LENGTH; i++)
|
for (; i < HIL_PTR_MAX_LENGTH; i++)
|
||||||
ptr->exd[i] = 0;
|
ptr->exd[i] = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HIL_CMD_RNM:
|
case HIL_CMD_RNM:
|
||||||
for (i = 0; i < idx; i++)
|
for (i = 0; i < idx; i++)
|
||||||
ptr->rnm[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
|
ptr->rnm[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
|
||||||
for (; i < HIL_PTR_MAX_LENGTH + 1; i++)
|
for (; i < HIL_PTR_MAX_LENGTH + 1; i++)
|
||||||
ptr->rnm[i] = '\0';
|
ptr->rnm[i] = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* These occur when device isn't present */
|
/* These occur when device isn't present */
|
||||||
if (p == (HIL_ERR_INT | HIL_PKT_CMD)) break;
|
if (p == (HIL_ERR_INT | HIL_PKT_CMD))
|
||||||
|
break;
|
||||||
/* Anything else we'd like to know about. */
|
/* Anything else we'd like to know about. */
|
||||||
printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);
|
printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);
|
||||||
break;
|
break;
|
||||||
|
@ -130,7 +137,8 @@ static void hil_ptr_process_record(struct hil_ptr *ptr)
|
||||||
|
|
||||||
report:
|
report:
|
||||||
if ((p & HIL_CMDCT_POL) != idx - 1) {
|
if ((p & HIL_CMDCT_POL) != idx - 1) {
|
||||||
printk(KERN_WARNING PREFIX "Malformed poll packet %x (idx = %i)\n", p, idx);
|
printk(KERN_WARNING PREFIX
|
||||||
|
"Malformed poll packet %x (idx = %i)\n", p, idx);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +165,8 @@ static void hil_ptr_process_record(struct hil_ptr *ptr)
|
||||||
input_report_abs(dev, ABS_X + i, val);
|
input_report_abs(dev, ABS_X + i, val);
|
||||||
} else {
|
} else {
|
||||||
val = (int) (((int8_t)lo) | ((int8_t)hi<<8));
|
val = (int) (((int8_t)lo) | ((int8_t)hi<<8));
|
||||||
if (i%3) val *= -1;
|
if (i%3)
|
||||||
|
val *= -1;
|
||||||
input_report_rel(dev, REL_X + i, val);
|
input_report_rel(dev, REL_X + i, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,10 +177,11 @@ static void hil_ptr_process_record(struct hil_ptr *ptr)
|
||||||
btn = ptr->data[cnt++];
|
btn = ptr->data[cnt++];
|
||||||
up = btn & 1;
|
up = btn & 1;
|
||||||
btn &= 0xfe;
|
btn &= 0xfe;
|
||||||
if (btn == 0x8e) {
|
if (btn == 0x8e)
|
||||||
continue; /* TODO: proximity == touch? */
|
continue; /* TODO: proximity == touch? */
|
||||||
}
|
else
|
||||||
else if ((btn > 0x8c) || (btn < 0x80)) continue;
|
if ((btn > 0x8c) || (btn < 0x80))
|
||||||
|
continue;
|
||||||
btn = (btn - 0x80) >> 1;
|
btn = (btn - 0x80) >> 1;
|
||||||
btn = ptr->btnmap[btn];
|
btn = ptr->btnmap[btn];
|
||||||
input_report_key(dev, btn, !up);
|
input_report_key(dev, btn, !up);
|
||||||
|
@ -182,11 +192,11 @@ static void hil_ptr_process_record(struct hil_ptr *ptr)
|
||||||
up(&ptr->sem);
|
up(&ptr->sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hil_ptr_process_err(struct hil_ptr *ptr) {
|
static void hil_ptr_process_err(struct hil_ptr *ptr)
|
||||||
|
{
|
||||||
printk(KERN_WARNING PREFIX "errored HIL packet\n");
|
printk(KERN_WARNING PREFIX "errored HIL packet\n");
|
||||||
ptr->idx4 = 0;
|
ptr->idx4 = 0;
|
||||||
up(&ptr->sem);
|
up(&ptr->sem);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static irqreturn_t hil_ptr_interrupt(struct serio *serio,
|
static irqreturn_t hil_ptr_interrupt(struct serio *serio,
|
||||||
|
@ -197,29 +207,29 @@ static irqreturn_t hil_ptr_interrupt(struct serio *serio,
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
ptr = serio_get_drvdata(serio);
|
ptr = serio_get_drvdata(serio);
|
||||||
if (ptr == NULL) {
|
BUG_ON(ptr == NULL);
|
||||||
BUG();
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ptr->idx4 >= (HIL_PTR_MAX_LENGTH * sizeof(hil_packet))) {
|
if (ptr->idx4 >= (HIL_PTR_MAX_LENGTH * sizeof(hil_packet))) {
|
||||||
hil_ptr_process_err(ptr);
|
hil_ptr_process_err(ptr);
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
idx = ptr->idx4/4;
|
idx = ptr->idx4/4;
|
||||||
if (!(ptr->idx4 % 4)) ptr->data[idx] = 0;
|
if (!(ptr->idx4 % 4))
|
||||||
|
ptr->data[idx] = 0;
|
||||||
packet = ptr->data[idx];
|
packet = ptr->data[idx];
|
||||||
packet |= ((hil_packet)data) << ((3 - (ptr->idx4 % 4)) * 8);
|
packet |= ((hil_packet)data) << ((3 - (ptr->idx4 % 4)) * 8);
|
||||||
ptr->data[idx] = packet;
|
ptr->data[idx] = packet;
|
||||||
|
|
||||||
/* Records of N 4-byte hil_packets must terminate with a command. */
|
/* Records of N 4-byte hil_packets must terminate with a command. */
|
||||||
if ((++(ptr->idx4)) % 4) return IRQ_HANDLED;
|
if ((++(ptr->idx4)) % 4)
|
||||||
|
return IRQ_HANDLED;
|
||||||
if ((packet & 0xffff0000) != HIL_ERR_INT) {
|
if ((packet & 0xffff0000) != HIL_ERR_INT) {
|
||||||
hil_ptr_process_err(ptr);
|
hil_ptr_process_err(ptr);
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
if (packet & HIL_PKT_CMD)
|
if (packet & HIL_PKT_CMD)
|
||||||
hil_ptr_process_record(ptr);
|
hil_ptr_process_record(ptr);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,10 +238,7 @@ static void hil_ptr_disconnect(struct serio *serio)
|
||||||
struct hil_ptr *ptr;
|
struct hil_ptr *ptr;
|
||||||
|
|
||||||
ptr = serio_get_drvdata(serio);
|
ptr = serio_get_drvdata(serio);
|
||||||
if (ptr == NULL) {
|
BUG_ON(ptr == NULL);
|
||||||
BUG();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
serio_close(serio);
|
serio_close(serio);
|
||||||
input_unregister_device(ptr->dev);
|
input_unregister_device(ptr->dev);
|
||||||
|
@ -241,7 +248,7 @@ static void hil_ptr_disconnect(struct serio *serio)
|
||||||
static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
|
static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
|
||||||
{
|
{
|
||||||
struct hil_ptr *ptr;
|
struct hil_ptr *ptr;
|
||||||
char *txt;
|
const char *txt;
|
||||||
unsigned int i, naxsets, btntype;
|
unsigned int i, naxsets, btntype;
|
||||||
uint8_t did, *idd;
|
uint8_t did, *idd;
|
||||||
|
|
||||||
|
@ -252,42 +259,40 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
|
||||||
if (!ptr->dev)
|
if (!ptr->dev)
|
||||||
goto bail0;
|
goto bail0;
|
||||||
|
|
||||||
ptr->dev->private = ptr;
|
|
||||||
|
|
||||||
if (serio_open(serio, driver))
|
if (serio_open(serio, driver))
|
||||||
goto bail1;
|
goto bail1;
|
||||||
|
|
||||||
serio_set_drvdata(serio, ptr);
|
serio_set_drvdata(serio, ptr);
|
||||||
ptr->serio = serio;
|
ptr->serio = serio;
|
||||||
|
|
||||||
init_MUTEX_LOCKED(&(ptr->sem));
|
init_MUTEX_LOCKED(&ptr->sem);
|
||||||
|
|
||||||
/* Get device info. MLC driver supplies devid/status/etc. */
|
/* Get device info. MLC driver supplies devid/status/etc. */
|
||||||
serio->write(serio, 0);
|
serio->write(serio, 0);
|
||||||
serio->write(serio, 0);
|
serio->write(serio, 0);
|
||||||
serio->write(serio, HIL_PKT_CMD >> 8);
|
serio->write(serio, HIL_PKT_CMD >> 8);
|
||||||
serio->write(serio, HIL_CMD_IDD);
|
serio->write(serio, HIL_CMD_IDD);
|
||||||
down(&(ptr->sem));
|
down(&ptr->sem);
|
||||||
|
|
||||||
serio->write(serio, 0);
|
serio->write(serio, 0);
|
||||||
serio->write(serio, 0);
|
serio->write(serio, 0);
|
||||||
serio->write(serio, HIL_PKT_CMD >> 8);
|
serio->write(serio, HIL_PKT_CMD >> 8);
|
||||||
serio->write(serio, HIL_CMD_RSC);
|
serio->write(serio, HIL_CMD_RSC);
|
||||||
down(&(ptr->sem));
|
down(&ptr->sem);
|
||||||
|
|
||||||
serio->write(serio, 0);
|
serio->write(serio, 0);
|
||||||
serio->write(serio, 0);
|
serio->write(serio, 0);
|
||||||
serio->write(serio, HIL_PKT_CMD >> 8);
|
serio->write(serio, HIL_PKT_CMD >> 8);
|
||||||
serio->write(serio, HIL_CMD_RNM);
|
serio->write(serio, HIL_CMD_RNM);
|
||||||
down(&(ptr->sem));
|
down(&ptr->sem);
|
||||||
|
|
||||||
serio->write(serio, 0);
|
serio->write(serio, 0);
|
||||||
serio->write(serio, 0);
|
serio->write(serio, 0);
|
||||||
serio->write(serio, HIL_PKT_CMD >> 8);
|
serio->write(serio, HIL_PKT_CMD >> 8);
|
||||||
serio->write(serio, HIL_CMD_EXD);
|
serio->write(serio, HIL_CMD_EXD);
|
||||||
down(&(ptr->sem));
|
down(&ptr->sem);
|
||||||
|
|
||||||
up(&(ptr->sem));
|
up(&ptr->sem);
|
||||||
|
|
||||||
did = ptr->idd[0];
|
did = ptr->idd[0];
|
||||||
idd = ptr->idd + 1;
|
idd = ptr->idd + 1;
|
||||||
|
@ -301,12 +306,12 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
|
||||||
ptr->dev->evbit[0] = BIT(EV_ABS);
|
ptr->dev->evbit[0] = BIT(EV_ABS);
|
||||||
txt = "absolute";
|
txt = "absolute";
|
||||||
}
|
}
|
||||||
if (!ptr->dev->evbit[0]) {
|
if (!ptr->dev->evbit[0])
|
||||||
goto bail2;
|
goto bail2;
|
||||||
}
|
|
||||||
|
|
||||||
ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd);
|
ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd);
|
||||||
if (ptr->nbtn) ptr->dev->evbit[0] |= BIT(EV_KEY);
|
if (ptr->nbtn)
|
||||||
|
ptr->dev->evbit[0] |= BIT(EV_KEY);
|
||||||
|
|
||||||
naxsets = HIL_IDD_NUM_AXSETS(*idd);
|
naxsets = HIL_IDD_NUM_AXSETS(*idd);
|
||||||
ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd);
|
ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd);
|
||||||
|
@ -341,12 +346,10 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) {
|
if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) {
|
||||||
for (i = 0; i < ptr->naxes; i++) {
|
for (i = 0; i < ptr->naxes; i++)
|
||||||
set_bit(REL_X + i, ptr->dev->relbit);
|
set_bit(REL_X + i, ptr->dev->relbit);
|
||||||
}
|
for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++)
|
||||||
for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) {
|
|
||||||
set_bit(REL_X + i, ptr->dev->relbit);
|
set_bit(REL_X + i, ptr->dev->relbit);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < ptr->naxes; i++) {
|
for (i = 0; i < ptr->naxes; i++) {
|
||||||
set_bit(ABS_X + i, ptr->dev->absbit);
|
set_bit(ABS_X + i, ptr->dev->absbit);
|
||||||
|
@ -375,7 +378,7 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
|
||||||
ptr->dev->id.vendor = PCI_VENDOR_ID_HP;
|
ptr->dev->id.vendor = PCI_VENDOR_ID_HP;
|
||||||
ptr->dev->id.product = 0x0001; /* TODO: get from ptr->rsc */
|
ptr->dev->id.product = 0x0001; /* TODO: get from ptr->rsc */
|
||||||
ptr->dev->id.version = 0x0100; /* TODO: get from ptr->rsc */
|
ptr->dev->id.version = 0x0100; /* TODO: get from ptr->rsc */
|
||||||
ptr->dev->cdev.dev = &serio->dev;
|
ptr->dev->dev.parent = &serio->dev;
|
||||||
|
|
||||||
input_register_device(ptr->dev);
|
input_register_device(ptr->dev);
|
||||||
printk(KERN_INFO "input: %s (%s), ID: %d\n",
|
printk(KERN_INFO "input: %s (%s), ID: %d\n",
|
||||||
|
|
|
@ -20,6 +20,27 @@
|
||||||
#include "psmouse.h"
|
#include "psmouse.h"
|
||||||
#include "lifebook.h"
|
#include "lifebook.h"
|
||||||
|
|
||||||
|
struct lifebook_data {
|
||||||
|
struct input_dev *dev2; /* Relative device */
|
||||||
|
char phys[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *desired_serio_phys;
|
||||||
|
|
||||||
|
static int lifebook_set_serio_phys(struct dmi_system_id *d)
|
||||||
|
{
|
||||||
|
desired_serio_phys = d->driver_data;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char lifebook_use_6byte_proto;
|
||||||
|
|
||||||
|
static int lifebook_set_6byte_proto(struct dmi_system_id *d)
|
||||||
|
{
|
||||||
|
lifebook_use_6byte_proto = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct dmi_system_id lifebook_dmi_table[] = {
|
static struct dmi_system_id lifebook_dmi_table[] = {
|
||||||
{
|
{
|
||||||
.ident = "FLORA-ie 55mi",
|
.ident = "FLORA-ie 55mi",
|
||||||
|
@ -56,6 +77,24 @@ static struct dmi_system_id lifebook_dmi_table[] = {
|
||||||
.matches = {
|
.matches = {
|
||||||
DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"),
|
DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"),
|
||||||
},
|
},
|
||||||
|
.callback = lifebook_set_serio_phys,
|
||||||
|
.driver_data = "isa0060/serio3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ident = "Panasonic CF-28",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "CF-28"),
|
||||||
|
},
|
||||||
|
.callback = lifebook_set_6byte_proto,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ident = "Panasonic CF-29",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"),
|
||||||
|
},
|
||||||
|
.callback = lifebook_set_6byte_proto,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.ident = "Lifebook B142",
|
.ident = "Lifebook B142",
|
||||||
|
@ -68,30 +107,70 @@ static struct dmi_system_id lifebook_dmi_table[] = {
|
||||||
|
|
||||||
static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
|
static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
|
||||||
{
|
{
|
||||||
|
struct lifebook_data *priv = psmouse->private;
|
||||||
|
struct input_dev *dev1 = psmouse->dev;
|
||||||
|
struct input_dev *dev2 = priv->dev2;
|
||||||
unsigned char *packet = psmouse->packet;
|
unsigned char *packet = psmouse->packet;
|
||||||
struct input_dev *dev = psmouse->dev;
|
int relative_packet = packet[0] & 0x08;
|
||||||
|
|
||||||
|
if (relative_packet || !lifebook_use_6byte_proto) {
|
||||||
if (psmouse->pktcnt != 3)
|
if (psmouse->pktcnt != 3)
|
||||||
return PSMOUSE_GOOD_DATA;
|
return PSMOUSE_GOOD_DATA;
|
||||||
|
|
||||||
/* calculate X and Y */
|
|
||||||
if ((packet[0] & 0x08) == 0x00) {
|
|
||||||
input_report_abs(dev, ABS_X,
|
|
||||||
(packet[1] | ((packet[0] & 0x30) << 4)));
|
|
||||||
input_report_abs(dev, ABS_Y,
|
|
||||||
1024 - (packet[2] | ((packet[0] & 0xC0) << 2)));
|
|
||||||
} else {
|
} else {
|
||||||
input_report_rel(dev, REL_X,
|
switch (psmouse->pktcnt) {
|
||||||
((packet[0] & 0x10) ? packet[1] - 256 : packet[1]));
|
case 1:
|
||||||
input_report_rel(dev, REL_Y,
|
return (packet[0] & 0xf8) == 0x00 ?
|
||||||
-(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2]));
|
PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
|
||||||
|
case 2:
|
||||||
|
return PSMOUSE_GOOD_DATA;
|
||||||
|
case 3:
|
||||||
|
return ((packet[2] & 0x30) << 2) == (packet[2] & 0xc0) ?
|
||||||
|
PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
|
||||||
|
case 4:
|
||||||
|
return (packet[3] & 0xf8) == 0xc0 ?
|
||||||
|
PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
|
||||||
|
case 5:
|
||||||
|
return (packet[4] & 0xc0) == (packet[2] & 0xc0) ?
|
||||||
|
PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
|
||||||
|
case 6:
|
||||||
|
if (((packet[5] & 0x30) << 2) != (packet[5] & 0xc0))
|
||||||
|
return PSMOUSE_BAD_DATA;
|
||||||
|
if ((packet[5] & 0xc0) != (packet[1] & 0xc0))
|
||||||
|
return PSMOUSE_BAD_DATA;
|
||||||
|
break; /* report data */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
|
if (relative_packet) {
|
||||||
input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
|
if (!dev2)
|
||||||
input_report_key(dev, BTN_TOUCH, packet[0] & 0x04);
|
printk(KERN_WARNING "lifebook.c: got relative packet "
|
||||||
|
"but no relative device set up\n");
|
||||||
|
} else if (lifebook_use_6byte_proto) {
|
||||||
|
input_report_abs(dev1, ABS_X,
|
||||||
|
((packet[1] & 0x3f) << 6) | (packet[2] & 0x3f));
|
||||||
|
input_report_abs(dev1, ABS_Y,
|
||||||
|
4096 - (((packet[4] & 0x3f) << 6) | (packet[5] & 0x3f)));
|
||||||
|
} else {
|
||||||
|
input_report_abs(dev1, ABS_X,
|
||||||
|
(packet[1] | ((packet[0] & 0x30) << 4)));
|
||||||
|
input_report_abs(dev1, ABS_Y,
|
||||||
|
1024 - (packet[2] | ((packet[0] & 0xC0) << 2)));
|
||||||
|
}
|
||||||
|
|
||||||
input_sync(dev);
|
input_report_key(dev1, BTN_TOUCH, packet[0] & 0x04);
|
||||||
|
input_sync(dev1);
|
||||||
|
|
||||||
|
if (dev2) {
|
||||||
|
if (relative_packet) {
|
||||||
|
input_report_rel(dev2, REL_X,
|
||||||
|
((packet[0] & 0x10) ? packet[1] - 256 : packet[1]));
|
||||||
|
input_report_rel(dev2, REL_Y,
|
||||||
|
-(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2]));
|
||||||
|
}
|
||||||
|
input_report_key(dev2, BTN_LEFT, packet[0] & 0x01);
|
||||||
|
input_report_key(dev2, BTN_RIGHT, packet[0] & 0x02);
|
||||||
|
input_sync(dev2);
|
||||||
|
}
|
||||||
|
|
||||||
return PSMOUSE_FULL_PACKET;
|
return PSMOUSE_FULL_PACKET;
|
||||||
}
|
}
|
||||||
|
@ -109,12 +188,20 @@ static int lifebook_absolute_mode(struct psmouse *psmouse)
|
||||||
you leave this call out the touchsreen will never send
|
you leave this call out the touchsreen will never send
|
||||||
absolute coordinates
|
absolute coordinates
|
||||||
*/
|
*/
|
||||||
param = 0x07;
|
param = lifebook_use_6byte_proto ? 0x08 : 0x07;
|
||||||
ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES);
|
ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void lifebook_relative_mode(struct psmouse *psmouse)
|
||||||
|
{
|
||||||
|
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||||
|
unsigned char param = 0x06;
|
||||||
|
|
||||||
|
ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES);
|
||||||
|
}
|
||||||
|
|
||||||
static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution)
|
static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution)
|
||||||
{
|
{
|
||||||
static const unsigned char params[] = { 0, 1, 2, 2, 3 };
|
static const unsigned char params[] = { 0, 1, 2, 2, 3 };
|
||||||
|
@ -131,6 +218,8 @@ static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolu
|
||||||
static void lifebook_disconnect(struct psmouse *psmouse)
|
static void lifebook_disconnect(struct psmouse *psmouse)
|
||||||
{
|
{
|
||||||
psmouse_reset(psmouse);
|
psmouse_reset(psmouse);
|
||||||
|
kfree(psmouse->private);
|
||||||
|
psmouse->private = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lifebook_detect(struct psmouse *psmouse, int set_properties)
|
int lifebook_detect(struct psmouse *psmouse, int set_properties)
|
||||||
|
@ -138,6 +227,10 @@ int lifebook_detect(struct psmouse *psmouse, int set_properties)
|
||||||
if (!dmi_check_system(lifebook_dmi_table))
|
if (!dmi_check_system(lifebook_dmi_table))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (desired_serio_phys &&
|
||||||
|
strcmp(psmouse->ps2dev.serio->phys, desired_serio_phys))
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (set_properties) {
|
if (set_properties) {
|
||||||
psmouse->vendor = "Fujitsu";
|
psmouse->vendor = "Fujitsu";
|
||||||
psmouse->name = "Lifebook TouchScreen";
|
psmouse->name = "Lifebook TouchScreen";
|
||||||
|
@ -146,24 +239,78 @@ int lifebook_detect(struct psmouse *psmouse, int set_properties)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int lifebook_create_relative_device(struct psmouse *psmouse)
|
||||||
|
{
|
||||||
|
struct input_dev *dev2;
|
||||||
|
struct lifebook_data *priv;
|
||||||
|
int error = -ENOMEM;
|
||||||
|
|
||||||
|
priv = kzalloc(sizeof(struct lifebook_data), GFP_KERNEL);
|
||||||
|
dev2 = input_allocate_device();
|
||||||
|
if (!priv || !dev2)
|
||||||
|
goto err_out;
|
||||||
|
|
||||||
|
priv->dev2 = dev2;
|
||||||
|
snprintf(priv->phys, sizeof(priv->phys),
|
||||||
|
"%s/input1", psmouse->ps2dev.serio->phys);
|
||||||
|
|
||||||
|
dev2->phys = priv->phys;
|
||||||
|
dev2->name = "PS/2 Touchpad";
|
||||||
|
dev2->id.bustype = BUS_I8042;
|
||||||
|
dev2->id.vendor = 0x0002;
|
||||||
|
dev2->id.product = PSMOUSE_LIFEBOOK;
|
||||||
|
dev2->id.version = 0x0000;
|
||||||
|
dev2->dev.parent = &psmouse->ps2dev.serio->dev;
|
||||||
|
|
||||||
|
dev2->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
|
||||||
|
dev2->relbit[LONG(REL_X)] = BIT(REL_X) | BIT(REL_Y);
|
||||||
|
dev2->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
|
||||||
|
|
||||||
|
error = input_register_device(priv->dev2);
|
||||||
|
if (error)
|
||||||
|
goto err_out;
|
||||||
|
|
||||||
|
psmouse->private = priv;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_out:
|
||||||
|
input_free_device(dev2);
|
||||||
|
kfree(priv);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
int lifebook_init(struct psmouse *psmouse)
|
int lifebook_init(struct psmouse *psmouse)
|
||||||
{
|
{
|
||||||
struct input_dev *input_dev = psmouse->dev;
|
struct input_dev *dev1 = psmouse->dev;
|
||||||
|
int max_coord = lifebook_use_6byte_proto ? 1024 : 4096;
|
||||||
|
|
||||||
if (lifebook_absolute_mode(psmouse))
|
if (lifebook_absolute_mode(psmouse))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL);
|
dev1->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
|
||||||
input_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
|
dev1->relbit[0] = 0;
|
||||||
input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
|
dev1->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
|
||||||
input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
|
input_set_abs_params(dev1, ABS_X, 0, max_coord, 0, 0);
|
||||||
input_set_abs_params(input_dev, ABS_X, 0, 1024, 0, 0);
|
input_set_abs_params(dev1, ABS_Y, 0, max_coord, 0, 0);
|
||||||
input_set_abs_params(input_dev, ABS_Y, 0, 1024, 0, 0);
|
|
||||||
|
if (!desired_serio_phys) {
|
||||||
|
if (lifebook_create_relative_device(psmouse)) {
|
||||||
|
lifebook_relative_mode(psmouse);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
psmouse->protocol_handler = lifebook_process_byte;
|
psmouse->protocol_handler = lifebook_process_byte;
|
||||||
psmouse->set_resolution = lifebook_set_resolution;
|
psmouse->set_resolution = lifebook_set_resolution;
|
||||||
psmouse->disconnect = lifebook_disconnect;
|
psmouse->disconnect = lifebook_disconnect;
|
||||||
psmouse->reconnect = lifebook_absolute_mode;
|
psmouse->reconnect = lifebook_absolute_mode;
|
||||||
|
|
||||||
|
psmouse->model = lifebook_use_6byte_proto ? 6 : 3;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use packet size = 3 even when using 6-byte protocol because
|
||||||
|
* that's what POLL will return on Lifebooks (according to spec).
|
||||||
|
*/
|
||||||
psmouse->pktsize = 3;
|
psmouse->pktsize = 3;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -11,7 +11,18 @@
|
||||||
#ifndef _LIFEBOOK_H
|
#ifndef _LIFEBOOK_H
|
||||||
#define _LIFEBOOK_H
|
#define _LIFEBOOK_H
|
||||||
|
|
||||||
|
#ifdef CONFIG_MOUSE_PS2_LIFEBOOK
|
||||||
int lifebook_detect(struct psmouse *psmouse, int set_properties);
|
int lifebook_detect(struct psmouse *psmouse, int set_properties);
|
||||||
int lifebook_init(struct psmouse *psmouse);
|
int lifebook_init(struct psmouse *psmouse);
|
||||||
|
#else
|
||||||
|
inline int lifebook_detect(struct psmouse *psmouse, int set_properties)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
inline int lifebook_init(struct psmouse *psmouse)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -200,6 +200,7 @@ static void ps2pp_disconnect(struct psmouse *psmouse)
|
||||||
static const struct ps2pp_info *get_model_info(unsigned char model)
|
static const struct ps2pp_info *get_model_info(unsigned char model)
|
||||||
{
|
{
|
||||||
static const struct ps2pp_info ps2pp_list[] = {
|
static const struct ps2pp_info ps2pp_list[] = {
|
||||||
|
{ 1, 0, 0 }, /* Simple 2-button mouse */
|
||||||
{ 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 */
|
||||||
|
@ -338,12 +339,12 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
|
||||||
param[1] = 0;
|
param[1] = 0;
|
||||||
ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
|
ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
|
||||||
|
|
||||||
if (!param[1])
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
|
model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
|
||||||
buttons = param[1];
|
buttons = param[1];
|
||||||
|
|
||||||
|
if (!model || !buttons)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if ((model_info = get_model_info(model)) != NULL) {
|
if ((model_info = get_model_info(model)) != NULL) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -11,6 +11,13 @@
|
||||||
#ifndef _LOGIPS2PP_H
|
#ifndef _LOGIPS2PP_H
|
||||||
#define _LOGIPS2PP_H
|
#define _LOGIPS2PP_H
|
||||||
|
|
||||||
|
#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
|
||||||
int ps2pp_init(struct psmouse *psmouse, int set_properties);
|
int ps2pp_init(struct psmouse *psmouse, int set_properties);
|
||||||
|
#else
|
||||||
|
inline int ps2pp_init(struct psmouse *psmouse, int set_properties)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_MOUSE_PS2_LOGIPS2PP */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "alps.h"
|
#include "alps.h"
|
||||||
#include "lifebook.h"
|
#include "lifebook.h"
|
||||||
#include "trackpoint.h"
|
#include "trackpoint.h"
|
||||||
|
#include "touchkit_ps2.h"
|
||||||
|
|
||||||
#define DRIVER_DESC "PS/2 mouse driver"
|
#define DRIVER_DESC "PS/2 mouse driver"
|
||||||
|
|
||||||
|
@ -569,7 +570,9 @@ static int psmouse_extensions(struct psmouse *psmouse,
|
||||||
return PSMOUSE_THINKPS;
|
return PSMOUSE_THINKPS;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try Synaptics TouchPad
|
* Try Synaptics TouchPad. Note that probing is done even if Synaptics protocol
|
||||||
|
* support is disabled in config - we need to know if it is synaptics so we
|
||||||
|
* can reset it properly after probing for intellimouse.
|
||||||
*/
|
*/
|
||||||
if (max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse, set_properties) == 0) {
|
if (max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse, set_properties) == 0) {
|
||||||
synaptics_hardware = 1;
|
synaptics_hardware = 1;
|
||||||
|
@ -605,15 +608,21 @@ static int psmouse_extensions(struct psmouse *psmouse,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max_proto > PSMOUSE_IMEX && genius_detect(psmouse, set_properties) == 0)
|
if (max_proto > PSMOUSE_IMEX) {
|
||||||
|
|
||||||
|
if (genius_detect(psmouse, set_properties) == 0)
|
||||||
return PSMOUSE_GENPS;
|
return PSMOUSE_GENPS;
|
||||||
|
|
||||||
if (max_proto > PSMOUSE_IMEX && ps2pp_init(psmouse, set_properties) == 0)
|
if (ps2pp_init(psmouse, set_properties) == 0)
|
||||||
return PSMOUSE_PS2PP;
|
return PSMOUSE_PS2PP;
|
||||||
|
|
||||||
if (max_proto > PSMOUSE_IMEX && trackpoint_detect(psmouse, set_properties) == 0)
|
if (trackpoint_detect(psmouse, set_properties) == 0)
|
||||||
return PSMOUSE_TRACKPOINT;
|
return PSMOUSE_TRACKPOINT;
|
||||||
|
|
||||||
|
if (touchkit_ps2_detect(psmouse, set_properties) == 0)
|
||||||
|
return PSMOUSE_TOUCHKIT_PS2;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reset to defaults in case the device got confused by extended
|
* Reset to defaults in case the device got confused by extended
|
||||||
* protocol probes. Note that we do full reset becuase some mice
|
* protocol probes. Note that we do full reset becuase some mice
|
||||||
|
@ -654,12 +663,14 @@ static const struct psmouse_protocol psmouse_protocols[] = {
|
||||||
.maxproto = 1,
|
.maxproto = 1,
|
||||||
.detect = ps2bare_detect,
|
.detect = ps2bare_detect,
|
||||||
},
|
},
|
||||||
|
#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
|
||||||
{
|
{
|
||||||
.type = PSMOUSE_PS2PP,
|
.type = PSMOUSE_PS2PP,
|
||||||
.name = "PS2++",
|
.name = "PS2++",
|
||||||
.alias = "logitech",
|
.alias = "logitech",
|
||||||
.detect = ps2pp_init,
|
.detect = ps2pp_init,
|
||||||
},
|
},
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
.type = PSMOUSE_THINKPS,
|
.type = PSMOUSE_THINKPS,
|
||||||
.name = "ThinkPS/2",
|
.name = "ThinkPS/2",
|
||||||
|
@ -686,6 +697,7 @@ static const struct psmouse_protocol psmouse_protocols[] = {
|
||||||
.maxproto = 1,
|
.maxproto = 1,
|
||||||
.detect = im_explorer_detect,
|
.detect = im_explorer_detect,
|
||||||
},
|
},
|
||||||
|
#ifdef CONFIG_MOUSE_PS2_SYNAPTICS
|
||||||
{
|
{
|
||||||
.type = PSMOUSE_SYNAPTICS,
|
.type = PSMOUSE_SYNAPTICS,
|
||||||
.name = "SynPS/2",
|
.name = "SynPS/2",
|
||||||
|
@ -693,6 +705,8 @@ static const struct psmouse_protocol psmouse_protocols[] = {
|
||||||
.detect = synaptics_detect,
|
.detect = synaptics_detect,
|
||||||
.init = synaptics_init,
|
.init = synaptics_init,
|
||||||
},
|
},
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_MOUSE_PS2_ALPS
|
||||||
{
|
{
|
||||||
.type = PSMOUSE_ALPS,
|
.type = PSMOUSE_ALPS,
|
||||||
.name = "AlpsPS/2",
|
.name = "AlpsPS/2",
|
||||||
|
@ -700,18 +714,31 @@ static const struct psmouse_protocol psmouse_protocols[] = {
|
||||||
.detect = alps_detect,
|
.detect = alps_detect,
|
||||||
.init = alps_init,
|
.init = alps_init,
|
||||||
},
|
},
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_MOUSE_PS2_LIFEBOOK
|
||||||
{
|
{
|
||||||
.type = PSMOUSE_LIFEBOOK,
|
.type = PSMOUSE_LIFEBOOK,
|
||||||
.name = "LBPS/2",
|
.name = "LBPS/2",
|
||||||
.alias = "lifebook",
|
.alias = "lifebook",
|
||||||
.init = lifebook_init,
|
.init = lifebook_init,
|
||||||
},
|
},
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_MOUSE_PS2_TRACKPOINT
|
||||||
{
|
{
|
||||||
.type = PSMOUSE_TRACKPOINT,
|
.type = PSMOUSE_TRACKPOINT,
|
||||||
.name = "TPPS/2",
|
.name = "TPPS/2",
|
||||||
.alias = "trackpoint",
|
.alias = "trackpoint",
|
||||||
.detect = trackpoint_detect,
|
.detect = trackpoint_detect,
|
||||||
},
|
},
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_MOUSE_PS2_TOUCHKIT
|
||||||
|
{
|
||||||
|
.type = PSMOUSE_TOUCHKIT_PS2,
|
||||||
|
.name = "touchkitPS/2",
|
||||||
|
.alias = "touchkit",
|
||||||
|
.detect = touchkit_ps2_detect,
|
||||||
|
},
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
.type = PSMOUSE_AUTO,
|
.type = PSMOUSE_AUTO,
|
||||||
.name = "auto",
|
.name = "auto",
|
||||||
|
@ -822,12 +849,6 @@ static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate)
|
||||||
|
|
||||||
static void psmouse_initialize(struct psmouse *psmouse)
|
static void psmouse_initialize(struct psmouse *psmouse)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* We set the mouse into streaming mode.
|
|
||||||
*/
|
|
||||||
|
|
||||||
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSTREAM);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We set the mouse report rate, resolution and scaling.
|
* We set the mouse report rate, resolution and scaling.
|
||||||
*/
|
*/
|
||||||
|
@ -1062,8 +1083,7 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse
|
||||||
{
|
{
|
||||||
struct input_dev *input_dev = psmouse->dev;
|
struct input_dev *input_dev = psmouse->dev;
|
||||||
|
|
||||||
input_dev->private = psmouse;
|
input_dev->dev.parent = &psmouse->ps2dev.serio->dev;
|
||||||
input_dev->cdev.dev = &psmouse->ps2dev.serio->dev;
|
|
||||||
|
|
||||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
|
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
|
||||||
input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
|
input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
|
||||||
|
|
|
@ -87,6 +87,7 @@ enum psmouse_type {
|
||||||
PSMOUSE_ALPS,
|
PSMOUSE_ALPS,
|
||||||
PSMOUSE_LIFEBOOK,
|
PSMOUSE_LIFEBOOK,
|
||||||
PSMOUSE_TRACKPOINT,
|
PSMOUSE_TRACKPOINT,
|
||||||
|
PSMOUSE_TOUCHKIT_PS2,
|
||||||
PSMOUSE_AUTO /* This one should always be last */
|
PSMOUSE_AUTO /* This one should always be last */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,8 @@ static void sermouse_process_msc(struct sermouse *sermouse, signed char data)
|
||||||
switch (sermouse->count) {
|
switch (sermouse->count) {
|
||||||
|
|
||||||
case 0:
|
case 0:
|
||||||
if ((data & 0xf8) != 0x80) return;
|
if ((data & 0xf8) != 0x80)
|
||||||
|
return;
|
||||||
input_report_key(dev, BTN_LEFT, !(data & 4));
|
input_report_key(dev, BTN_LEFT, !(data & 4));
|
||||||
input_report_key(dev, BTN_RIGHT, !(data & 1));
|
input_report_key(dev, BTN_RIGHT, !(data & 1));
|
||||||
input_report_key(dev, BTN_MIDDLE, !(data & 2));
|
input_report_key(dev, BTN_MIDDLE, !(data & 2));
|
||||||
|
@ -107,7 +108,10 @@ static void sermouse_process_ms(struct sermouse *sermouse, signed char data)
|
||||||
struct input_dev *dev = sermouse->dev;
|
struct input_dev *dev = sermouse->dev;
|
||||||
signed char *buf = sermouse->buf;
|
signed char *buf = sermouse->buf;
|
||||||
|
|
||||||
if (data & 0x40) sermouse->count = 0;
|
if (data & 0x40)
|
||||||
|
sermouse->count = 0;
|
||||||
|
else if (sermouse->count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
switch (sermouse->count) {
|
switch (sermouse->count) {
|
||||||
|
|
||||||
|
@ -169,7 +173,8 @@ static void sermouse_process_ms(struct sermouse *sermouse, signed char data)
|
||||||
|
|
||||||
case 5:
|
case 5:
|
||||||
case 7: /* Ignore anything besides MZ++ */
|
case 7: /* Ignore anything besides MZ++ */
|
||||||
if (sermouse->type != SERIO_MZPP) break;
|
if (sermouse->type != SERIO_MZPP)
|
||||||
|
break;
|
||||||
|
|
||||||
switch (buf[1]) {
|
switch (buf[1]) {
|
||||||
|
|
||||||
|
@ -206,13 +211,16 @@ static irqreturn_t sermouse_interrupt(struct serio *serio,
|
||||||
{
|
{
|
||||||
struct sermouse *sermouse = serio_get_drvdata(serio);
|
struct sermouse *sermouse = serio_get_drvdata(serio);
|
||||||
|
|
||||||
if (time_after(jiffies, sermouse->last + HZ/10)) sermouse->count = 0;
|
if (time_after(jiffies, sermouse->last + HZ/10))
|
||||||
|
sermouse->count = 0;
|
||||||
|
|
||||||
sermouse->last = jiffies;
|
sermouse->last = jiffies;
|
||||||
|
|
||||||
if (sermouse->type > SERIO_SUN)
|
if (sermouse->type > SERIO_SUN)
|
||||||
sermouse_process_ms(sermouse, data);
|
sermouse_process_ms(sermouse, data);
|
||||||
else
|
else
|
||||||
sermouse_process_msc(sermouse, data);
|
sermouse_process_msc(sermouse, data);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,12 +266,11 @@ static int sermouse_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
input_dev->id.vendor = sermouse->type;
|
input_dev->id.vendor = sermouse->type;
|
||||||
input_dev->id.product = c;
|
input_dev->id.product = c;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &serio->dev;
|
input_dev->dev.parent = &serio->dev;
|
||||||
|
|
||||||
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
|
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
|
||||||
input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
|
input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
|
||||||
input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
|
input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
|
||||||
input_dev->private = sermouse;
|
|
||||||
|
|
||||||
if (c & 0x01) set_bit(BTN_MIDDLE, input_dev->keybit);
|
if (c & 0x01) set_bit(BTN_MIDDLE, input_dev->keybit);
|
||||||
if (c & 0x02) set_bit(BTN_SIDE, input_dev->keybit);
|
if (c & 0x02) set_bit(BTN_SIDE, input_dev->keybit);
|
||||||
|
|
|
@ -40,21 +40,10 @@
|
||||||
#define YMIN_NOMINAL 1408
|
#define YMIN_NOMINAL 1408
|
||||||
#define YMAX_NOMINAL 4448
|
#define YMAX_NOMINAL 4448
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
* Synaptics communications functions
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
/*
|
/*****************************************************************************
|
||||||
* Send a command to the synpatics touchpad by special commands
|
* Stuff we need even when we do not want native Synaptics support
|
||||||
*/
|
****************************************************************************/
|
||||||
static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param)
|
|
||||||
{
|
|
||||||
if (psmouse_sliced_command(psmouse, c))
|
|
||||||
return -1;
|
|
||||||
if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO))
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the synaptics touchpad mode byte by special commands
|
* Set the synaptics touchpad mode byte by special commands
|
||||||
|
@ -71,6 +60,54 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int synaptics_detect(struct psmouse *psmouse, int set_properties)
|
||||||
|
{
|
||||||
|
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||||
|
unsigned char param[4];
|
||||||
|
|
||||||
|
param[0] = 0;
|
||||||
|
|
||||||
|
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
|
||||||
|
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
|
||||||
|
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
|
||||||
|
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
|
||||||
|
ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
|
||||||
|
|
||||||
|
if (param[1] != 0x47)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (set_properties) {
|
||||||
|
psmouse->vendor = "Synaptics";
|
||||||
|
psmouse->name = "TouchPad";
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void synaptics_reset(struct psmouse *psmouse)
|
||||||
|
{
|
||||||
|
/* reset touchpad back to relative mode, gestures enabled */
|
||||||
|
synaptics_mode_cmd(psmouse, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_MOUSE_PS2_SYNAPTICS
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Synaptics communications functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send a command to the synpatics touchpad by special commands
|
||||||
|
*/
|
||||||
|
static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param)
|
||||||
|
{
|
||||||
|
if (psmouse_sliced_command(psmouse, c))
|
||||||
|
return -1;
|
||||||
|
if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO))
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read the model-id bytes from the touchpad
|
* Read the model-id bytes from the touchpad
|
||||||
* see also SYN_MODEL_* macros
|
* see also SYN_MODEL_* macros
|
||||||
|
@ -529,12 +566,6 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
|
||||||
clear_bit(REL_Y, dev->relbit);
|
clear_bit(REL_Y, dev->relbit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void synaptics_reset(struct psmouse *psmouse)
|
|
||||||
{
|
|
||||||
/* reset touchpad back to relative mode, gestures enabled */
|
|
||||||
synaptics_mode_cmd(psmouse, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void synaptics_disconnect(struct psmouse *psmouse)
|
static void synaptics_disconnect(struct psmouse *psmouse)
|
||||||
{
|
{
|
||||||
synaptics_reset(psmouse);
|
synaptics_reset(psmouse);
|
||||||
|
@ -569,30 +600,6 @@ static int synaptics_reconnect(struct psmouse *psmouse)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int synaptics_detect(struct psmouse *psmouse, int set_properties)
|
|
||||||
{
|
|
||||||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
|
||||||
unsigned char param[4];
|
|
||||||
|
|
||||||
param[0] = 0;
|
|
||||||
|
|
||||||
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
|
|
||||||
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
|
|
||||||
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
|
|
||||||
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
|
|
||||||
ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
|
|
||||||
|
|
||||||
if (param[1] != 0x47)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (set_properties) {
|
|
||||||
psmouse->vendor = "Synaptics";
|
|
||||||
psmouse->name = "TouchPad";
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__i386__)
|
#if defined(__i386__)
|
||||||
#include <linux/dmi.h>
|
#include <linux/dmi.h>
|
||||||
static struct dmi_system_id toshiba_dmi_table[] = {
|
static struct dmi_system_id toshiba_dmi_table[] = {
|
||||||
|
@ -648,6 +655,16 @@ int synaptics_init(struct psmouse *psmouse)
|
||||||
|
|
||||||
set_input_params(psmouse->dev, priv);
|
set_input_params(psmouse->dev, priv);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Encode touchpad model so that it can be used to set
|
||||||
|
* input device->id.version and be visible to userspace.
|
||||||
|
* Because version is __u16 we have to drop something.
|
||||||
|
* Hardware info bits seem to be good candidates as they
|
||||||
|
* are documented to be for Synaptics corp. internal use.
|
||||||
|
*/
|
||||||
|
psmouse->model = ((priv->model_id & 0x00ff0000) >> 8) |
|
||||||
|
(priv->model_id & 0x000000ff);
|
||||||
|
|
||||||
psmouse->protocol_handler = synaptics_process_byte;
|
psmouse->protocol_handler = synaptics_process_byte;
|
||||||
psmouse->set_rate = synaptics_set_rate;
|
psmouse->set_rate = synaptics_set_rate;
|
||||||
psmouse->disconnect = synaptics_disconnect;
|
psmouse->disconnect = synaptics_disconnect;
|
||||||
|
@ -680,4 +697,12 @@ int synaptics_init(struct psmouse *psmouse)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else /* CONFIG_MOUSE_PS2_SYNAPTICS */
|
||||||
|
|
||||||
|
int synaptics_init(struct psmouse *psmouse)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_MOUSE_PS2_SYNAPTICS */
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,6 @@
|
||||||
#ifndef _SYNAPTICS_H
|
#ifndef _SYNAPTICS_H
|
||||||
#define _SYNAPTICS_H
|
#define _SYNAPTICS_H
|
||||||
|
|
||||||
extern int synaptics_detect(struct psmouse *psmouse, int set_properties);
|
|
||||||
extern int synaptics_init(struct psmouse *psmouse);
|
|
||||||
extern void synaptics_reset(struct psmouse *psmouse);
|
|
||||||
|
|
||||||
/* synaptics queries */
|
/* synaptics queries */
|
||||||
#define SYN_QUE_IDENTIFY 0x00
|
#define SYN_QUE_IDENTIFY 0x00
|
||||||
#define SYN_QUE_MODES 0x01
|
#define SYN_QUE_MODES 0x01
|
||||||
|
@ -107,4 +103,8 @@ struct synaptics_data {
|
||||||
int scroll;
|
int scroll;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int synaptics_detect(struct psmouse *psmouse, int set_properties);
|
||||||
|
int synaptics_init(struct psmouse *psmouse);
|
||||||
|
void synaptics_reset(struct psmouse *psmouse);
|
||||||
|
|
||||||
#endif /* _SYNAPTICS_H */
|
#endif /* _SYNAPTICS_H */
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
/* ----------------------------------------------------------------------------
|
||||||
|
* touchkit_ps2.c -- Driver for eGalax TouchKit PS/2 Touchscreens
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005 by Stefan Lucke
|
||||||
|
* Copyright (C) 2004 by Daniel Ritz
|
||||||
|
* Copyright (C) by Todd E. Johnson (mtouchusb.c)
|
||||||
|
*
|
||||||
|
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
|
* Based upon touchkitusb.c
|
||||||
|
*
|
||||||
|
* Vendor documentation is available in support section of:
|
||||||
|
* http://www.egalax.com.tw/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <linux/serio.h>
|
||||||
|
#include <linux/libps2.h>
|
||||||
|
|
||||||
|
#include "psmouse.h"
|
||||||
|
#include "touchkit_ps2.h"
|
||||||
|
|
||||||
|
#define TOUCHKIT_MAX_XC 0x07ff
|
||||||
|
#define TOUCHKIT_MAX_YC 0x07ff
|
||||||
|
|
||||||
|
#define TOUCHKIT_CMD 0x0a
|
||||||
|
#define TOUCHKIT_CMD_LENGTH 1
|
||||||
|
|
||||||
|
#define TOUCHKIT_CMD_ACTIVE 'A'
|
||||||
|
#define TOUCHKIT_CMD_FIRMWARE_VERSION 'D'
|
||||||
|
#define TOUCHKIT_CMD_CONTROLLER_TYPE 'E'
|
||||||
|
|
||||||
|
#define TOUCHKIT_SEND_PARMS(s, r, c) ((s) << 12 | (r) << 8 | (c))
|
||||||
|
|
||||||
|
#define TOUCHKIT_GET_TOUCHED(packet) (((packet)[0]) & 0x01)
|
||||||
|
#define TOUCHKIT_GET_X(packet) (((packet)[1] << 7) | (packet)[2])
|
||||||
|
#define TOUCHKIT_GET_Y(packet) (((packet)[3] << 7) | (packet)[4])
|
||||||
|
|
||||||
|
static psmouse_ret_t touchkit_ps2_process_byte(struct psmouse *psmouse)
|
||||||
|
{
|
||||||
|
unsigned char *packet = psmouse->packet;
|
||||||
|
struct input_dev *dev = psmouse->dev;
|
||||||
|
|
||||||
|
if (psmouse->pktcnt != 5)
|
||||||
|
return PSMOUSE_GOOD_DATA;
|
||||||
|
|
||||||
|
input_report_abs(dev, ABS_X, TOUCHKIT_GET_X(packet));
|
||||||
|
input_report_abs(dev, ABS_Y, TOUCHKIT_GET_Y(packet));
|
||||||
|
input_report_key(dev, BTN_TOUCH, TOUCHKIT_GET_TOUCHED(packet));
|
||||||
|
input_sync(dev);
|
||||||
|
|
||||||
|
return PSMOUSE_FULL_PACKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties)
|
||||||
|
{
|
||||||
|
struct input_dev *dev = psmouse->dev;
|
||||||
|
unsigned char param[3];
|
||||||
|
int command;
|
||||||
|
|
||||||
|
param[0] = TOUCHKIT_CMD_LENGTH;
|
||||||
|
param[1] = TOUCHKIT_CMD_ACTIVE;
|
||||||
|
command = TOUCHKIT_SEND_PARMS(2, 3, TOUCHKIT_CMD);
|
||||||
|
|
||||||
|
if (ps2_command(&psmouse->ps2dev, param, command))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (param[0] != TOUCHKIT_CMD || param[1] != 0x01 ||
|
||||||
|
param[2] != TOUCHKIT_CMD_ACTIVE)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (set_properties) {
|
||||||
|
dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||||
|
set_bit(BTN_TOUCH, dev->keybit);
|
||||||
|
input_set_abs_params(dev, ABS_X, 0, TOUCHKIT_MAX_XC, 0, 0);
|
||||||
|
input_set_abs_params(dev, ABS_Y, 0, TOUCHKIT_MAX_YC, 0, 0);
|
||||||
|
|
||||||
|
psmouse->vendor = "eGalax";
|
||||||
|
psmouse->name = "Touchscreen";
|
||||||
|
psmouse->protocol_handler = touchkit_ps2_process_byte;
|
||||||
|
psmouse->pktsize = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
/* ----------------------------------------------------------------------------
|
||||||
|
* touchkit_ps2.h -- Driver for eGalax TouchKit PS/2 Touchscreens
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005 by Stefan Lucke
|
||||||
|
* Copyright (c) 2005 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TOUCHKIT_PS2_H
|
||||||
|
#define _TOUCHKIT_PS2_H
|
||||||
|
|
||||||
|
#ifdef CONFIG_MOUSE_PS2_TOUCHKIT
|
||||||
|
int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties);
|
||||||
|
#else
|
||||||
|
inline int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_MOUSE_PS2_TOUCHKIT */
|
||||||
|
|
||||||
|
#endif
|
|
@ -142,6 +142,13 @@ struct trackpoint_data
|
||||||
unsigned char ext_dev;
|
unsigned char ext_dev;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int trackpoint_detect(struct psmouse *psmouse, int set_properties);
|
#ifdef CONFIG_MOUSE_PS2_TRACKPOINT
|
||||||
|
int trackpoint_detect(struct psmouse *psmouse, int set_properties);
|
||||||
|
#else
|
||||||
|
inline int trackpoint_detect(struct psmouse *psmouse, int set_properties)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_MOUSE_PS2_TRACKPOINT */
|
||||||
|
|
||||||
#endif /* _TRACKPOINT_H */
|
#endif /* _TRACKPOINT_H */
|
||||||
|
|
|
@ -508,8 +508,7 @@ vsxxxaa_connect (struct serio *serio, struct serio_driver *drv)
|
||||||
input_dev->name = mouse->name;
|
input_dev->name = mouse->name;
|
||||||
input_dev->phys = mouse->phys;
|
input_dev->phys = mouse->phys;
|
||||||
input_dev->id.bustype = BUS_RS232;
|
input_dev->id.bustype = BUS_RS232;
|
||||||
input_dev->cdev.dev = &serio->dev;
|
input_dev->dev.parent = &serio->dev;
|
||||||
input_dev->private = mouse;
|
|
||||||
|
|
||||||
set_bit (EV_KEY, input_dev->evbit); /* We have buttons */
|
set_bit (EV_KEY, input_dev->evbit); /* We have buttons */
|
||||||
set_bit (EV_REL, input_dev->evbit);
|
set_bit (EV_REL, input_dev->evbit);
|
||||||
|
|
|
@ -63,9 +63,12 @@ struct mousedev {
|
||||||
int minor;
|
int minor;
|
||||||
char name[16];
|
char name[16];
|
||||||
wait_queue_head_t wait;
|
wait_queue_head_t wait;
|
||||||
struct list_head list;
|
struct list_head client_list;
|
||||||
struct input_handle handle;
|
struct input_handle handle;
|
||||||
|
|
||||||
|
struct list_head mixdev_node;
|
||||||
|
int mixdev_open;
|
||||||
|
|
||||||
struct mousedev_hw_data packet;
|
struct mousedev_hw_data packet;
|
||||||
unsigned int pkt_count;
|
unsigned int pkt_count;
|
||||||
int old_x[4], old_y[4];
|
int old_x[4], old_y[4];
|
||||||
|
@ -85,7 +88,7 @@ struct mousedev_motion {
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PACKET_QUEUE_LEN 16
|
#define PACKET_QUEUE_LEN 16
|
||||||
struct mousedev_list {
|
struct mousedev_client {
|
||||||
struct fasync_struct *fasync;
|
struct fasync_struct *fasync;
|
||||||
struct mousedev *mousedev;
|
struct mousedev *mousedev;
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
|
@ -111,6 +114,7 @@ static struct input_handler mousedev_handler;
|
||||||
|
|
||||||
static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
|
static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
|
||||||
static struct mousedev mousedev_mix;
|
static struct mousedev mousedev_mix;
|
||||||
|
static LIST_HEAD(mousedev_mix_list);
|
||||||
|
|
||||||
#define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
|
#define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
|
||||||
#define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
|
#define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
|
||||||
|
@ -120,15 +124,13 @@ static void mousedev_touchpad_event(struct input_dev *dev, struct mousedev *mous
|
||||||
int size, tmp;
|
int size, tmp;
|
||||||
enum { FRACTION_DENOM = 128 };
|
enum { FRACTION_DENOM = 128 };
|
||||||
|
|
||||||
if (mousedev->touch) {
|
|
||||||
size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
|
|
||||||
if (size == 0)
|
|
||||||
size = 256 * 2;
|
|
||||||
|
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case ABS_X:
|
case ABS_X:
|
||||||
fx(0) = value;
|
fx(0) = value;
|
||||||
if (mousedev->pkt_count >= 2) {
|
if (mousedev->touch && mousedev->pkt_count >= 2) {
|
||||||
|
size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
|
||||||
|
if (size == 0)
|
||||||
|
size = 256 * 2;
|
||||||
tmp = ((value - fx(2)) * (256 * FRACTION_DENOM)) / size;
|
tmp = ((value - fx(2)) * (256 * FRACTION_DENOM)) / size;
|
||||||
tmp += mousedev->frac_dx;
|
tmp += mousedev->frac_dx;
|
||||||
mousedev->packet.dx = tmp / FRACTION_DENOM;
|
mousedev->packet.dx = tmp / FRACTION_DENOM;
|
||||||
|
@ -138,7 +140,11 @@ static void mousedev_touchpad_event(struct input_dev *dev, struct mousedev *mous
|
||||||
|
|
||||||
case ABS_Y:
|
case ABS_Y:
|
||||||
fy(0) = value;
|
fy(0) = value;
|
||||||
if (mousedev->pkt_count >= 2) {
|
if (mousedev->touch && mousedev->pkt_count >= 2) {
|
||||||
|
/* use X size to keep the same scale */
|
||||||
|
size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
|
||||||
|
if (size == 0)
|
||||||
|
size = 256 * 2;
|
||||||
tmp = -((value - fy(2)) * (256 * FRACTION_DENOM)) / size;
|
tmp = -((value - fy(2)) * (256 * FRACTION_DENOM)) / size;
|
||||||
tmp += mousedev->frac_dy;
|
tmp += mousedev->frac_dy;
|
||||||
mousedev->packet.dy = tmp / FRACTION_DENOM;
|
mousedev->packet.dy = tmp / FRACTION_DENOM;
|
||||||
|
@ -146,7 +152,6 @@ static void mousedev_touchpad_event(struct input_dev *dev, struct mousedev *mous
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value)
|
static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value)
|
||||||
|
@ -223,47 +228,47 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int
|
||||||
|
|
||||||
static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_hw_data *packet)
|
static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_hw_data *packet)
|
||||||
{
|
{
|
||||||
struct mousedev_list *list;
|
struct mousedev_client *client;
|
||||||
struct mousedev_motion *p;
|
struct mousedev_motion *p;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int wake_readers = 0;
|
int wake_readers = 0;
|
||||||
|
|
||||||
list_for_each_entry(list, &mousedev->list, node) {
|
list_for_each_entry(client, &mousedev->client_list, node) {
|
||||||
spin_lock_irqsave(&list->packet_lock, flags);
|
spin_lock_irqsave(&client->packet_lock, flags);
|
||||||
|
|
||||||
p = &list->packets[list->head];
|
p = &client->packets[client->head];
|
||||||
if (list->ready && p->buttons != mousedev->packet.buttons) {
|
if (client->ready && p->buttons != mousedev->packet.buttons) {
|
||||||
unsigned int new_head = (list->head + 1) % PACKET_QUEUE_LEN;
|
unsigned int new_head = (client->head + 1) % PACKET_QUEUE_LEN;
|
||||||
if (new_head != list->tail) {
|
if (new_head != client->tail) {
|
||||||
p = &list->packets[list->head = new_head];
|
p = &client->packets[client->head = new_head];
|
||||||
memset(p, 0, sizeof(struct mousedev_motion));
|
memset(p, 0, sizeof(struct mousedev_motion));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packet->abs_event) {
|
if (packet->abs_event) {
|
||||||
p->dx += packet->x - list->pos_x;
|
p->dx += packet->x - client->pos_x;
|
||||||
p->dy += packet->y - list->pos_y;
|
p->dy += packet->y - client->pos_y;
|
||||||
list->pos_x = packet->x;
|
client->pos_x = packet->x;
|
||||||
list->pos_y = packet->y;
|
client->pos_y = packet->y;
|
||||||
}
|
}
|
||||||
|
|
||||||
list->pos_x += packet->dx;
|
client->pos_x += packet->dx;
|
||||||
list->pos_x = list->pos_x < 0 ? 0 : (list->pos_x >= xres ? xres : list->pos_x);
|
client->pos_x = client->pos_x < 0 ? 0 : (client->pos_x >= xres ? xres : client->pos_x);
|
||||||
list->pos_y += packet->dy;
|
client->pos_y += packet->dy;
|
||||||
list->pos_y = list->pos_y < 0 ? 0 : (list->pos_y >= yres ? yres : list->pos_y);
|
client->pos_y = client->pos_y < 0 ? 0 : (client->pos_y >= yres ? yres : client->pos_y);
|
||||||
|
|
||||||
p->dx += packet->dx;
|
p->dx += packet->dx;
|
||||||
p->dy += packet->dy;
|
p->dy += packet->dy;
|
||||||
p->dz += packet->dz;
|
p->dz += packet->dz;
|
||||||
p->buttons = mousedev->packet.buttons;
|
p->buttons = mousedev->packet.buttons;
|
||||||
|
|
||||||
if (p->dx || p->dy || p->dz || p->buttons != list->last_buttons)
|
if (p->dx || p->dy || p->dz || p->buttons != client->last_buttons)
|
||||||
list->ready = 1;
|
client->ready = 1;
|
||||||
|
|
||||||
spin_unlock_irqrestore(&list->packet_lock, flags);
|
spin_unlock_irqrestore(&client->packet_lock, flags);
|
||||||
|
|
||||||
if (list->ready) {
|
if (client->ready) {
|
||||||
kill_fasync(&list->fasync, SIGIO, POLL_IN);
|
kill_fasync(&client->fasync, SIGIO, POLL_IN);
|
||||||
wake_readers = 1;
|
wake_readers = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -351,9 +356,9 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig
|
||||||
static int mousedev_fasync(int fd, struct file *file, int on)
|
static int mousedev_fasync(int fd, struct file *file, int on)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
struct mousedev_list *list = file->private_data;
|
struct mousedev_client *client = file->private_data;
|
||||||
|
|
||||||
retval = fasync_helper(fd, file, on, &list->fasync);
|
retval = fasync_helper(fd, file, on, &client->fasync);
|
||||||
|
|
||||||
return retval < 0 ? retval : 0;
|
return retval < 0 ? retval : 0;
|
||||||
}
|
}
|
||||||
|
@ -364,50 +369,95 @@ static void mousedev_free(struct mousedev *mousedev)
|
||||||
kfree(mousedev);
|
kfree(mousedev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mixdev_release(void)
|
static int mixdev_add_device(struct mousedev *mousedev)
|
||||||
{
|
{
|
||||||
struct input_handle *handle;
|
int error;
|
||||||
|
|
||||||
list_for_each_entry(handle, &mousedev_handler.h_list, h_node) {
|
if (mousedev_mix.open) {
|
||||||
struct mousedev *mousedev = handle->private;
|
error = input_open_device(&mousedev->handle);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
if (!mousedev->open) {
|
mousedev->open++;
|
||||||
|
mousedev->mixdev_open++;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mixdev_remove_device(struct mousedev *mousedev)
|
||||||
|
{
|
||||||
|
if (mousedev->mixdev_open) {
|
||||||
|
mousedev->mixdev_open = 0;
|
||||||
|
if (!--mousedev->open && mousedev->exist)
|
||||||
|
input_close_device(&mousedev->handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
list_del_init(&mousedev->mixdev_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mixdev_open_devices(void)
|
||||||
|
{
|
||||||
|
struct mousedev *mousedev;
|
||||||
|
|
||||||
|
list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
|
||||||
|
if (mousedev->exist && !mousedev->open) {
|
||||||
|
if (input_open_device(&mousedev->handle))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mousedev->open++;
|
||||||
|
mousedev->mixdev_open++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mixdev_close_devices(void)
|
||||||
|
{
|
||||||
|
struct mousedev *mousedev, *next;
|
||||||
|
|
||||||
|
list_for_each_entry_safe(mousedev, next, &mousedev_mix_list, mixdev_node) {
|
||||||
|
if (mousedev->mixdev_open) {
|
||||||
|
mousedev->mixdev_open = 0;
|
||||||
|
if (!--mousedev->open) {
|
||||||
if (mousedev->exist)
|
if (mousedev->exist)
|
||||||
input_close_device(&mousedev->handle);
|
input_close_device(&mousedev->handle);
|
||||||
else
|
else
|
||||||
mousedev_free(mousedev);
|
mousedev_free(mousedev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mousedev_release(struct inode * inode, struct file * file)
|
static int mousedev_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct mousedev_list *list = file->private_data;
|
struct mousedev_client *client = file->private_data;
|
||||||
|
struct mousedev *mousedev = client->mousedev;
|
||||||
|
|
||||||
mousedev_fasync(-1, file, 0);
|
mousedev_fasync(-1, file, 0);
|
||||||
|
|
||||||
list_del(&list->node);
|
list_del(&client->node);
|
||||||
|
kfree(client);
|
||||||
|
|
||||||
if (!--list->mousedev->open) {
|
if (!--mousedev->open) {
|
||||||
if (list->mousedev->minor == MOUSEDEV_MIX)
|
if (mousedev->minor == MOUSEDEV_MIX)
|
||||||
mixdev_release();
|
mixdev_close_devices();
|
||||||
else if (!mousedev_mix.open) {
|
else if (mousedev->exist)
|
||||||
if (list->mousedev->exist)
|
input_close_device(&mousedev->handle);
|
||||||
input_close_device(&list->mousedev->handle);
|
|
||||||
else
|
else
|
||||||
mousedev_free(list->mousedev);
|
mousedev_free(mousedev);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kfree(list);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mousedev_open(struct inode * inode, struct file * file)
|
|
||||||
|
static int mousedev_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct mousedev_list *list;
|
struct mousedev_client *client;
|
||||||
struct input_handle *handle;
|
|
||||||
struct mousedev *mousedev;
|
struct mousedev *mousedev;
|
||||||
|
int error;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
|
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
|
||||||
|
@ -417,31 +467,37 @@ static int mousedev_open(struct inode * inode, struct file * file)
|
||||||
#endif
|
#endif
|
||||||
i = iminor(inode) - MOUSEDEV_MINOR_BASE;
|
i = iminor(inode) - MOUSEDEV_MINOR_BASE;
|
||||||
|
|
||||||
if (i >= MOUSEDEV_MINORS || !mousedev_table[i])
|
if (i >= MOUSEDEV_MINORS)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if (!(list = kzalloc(sizeof(struct mousedev_list), GFP_KERNEL)))
|
mousedev = mousedev_table[i];
|
||||||
|
if (!mousedev)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL);
|
||||||
|
if (!client)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
spin_lock_init(&list->packet_lock);
|
spin_lock_init(&client->packet_lock);
|
||||||
list->pos_x = xres / 2;
|
client->pos_x = xres / 2;
|
||||||
list->pos_y = yres / 2;
|
client->pos_y = yres / 2;
|
||||||
list->mousedev = mousedev_table[i];
|
client->mousedev = mousedev;
|
||||||
list_add_tail(&list->node, &mousedev_table[i]->list);
|
list_add_tail(&client->node, &mousedev->client_list);
|
||||||
file->private_data = list;
|
|
||||||
|
|
||||||
if (!list->mousedev->open++) {
|
if (!mousedev->open++) {
|
||||||
if (list->mousedev->minor == MOUSEDEV_MIX) {
|
if (mousedev->minor == MOUSEDEV_MIX)
|
||||||
list_for_each_entry(handle, &mousedev_handler.h_list, h_node) {
|
mixdev_open_devices();
|
||||||
mousedev = handle->private;
|
else if (mousedev->exist) {
|
||||||
if (!mousedev->open && mousedev->exist)
|
error = input_open_device(&mousedev->handle);
|
||||||
input_open_device(handle);
|
if (error) {
|
||||||
|
list_del(&client->node);
|
||||||
|
kfree(client);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else
|
|
||||||
if (!mousedev_mix.open && list->mousedev->exist)
|
|
||||||
input_open_device(&list->mousedev->handle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file->private_data = client;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -450,13 +506,13 @@ static inline int mousedev_limit_delta(int delta, int limit)
|
||||||
return delta > limit ? limit : (delta < -limit ? -limit : delta);
|
return delta > limit ? limit : (delta < -limit ? -limit : delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mousedev_packet(struct mousedev_list *list, signed char *ps2_data)
|
static void mousedev_packet(struct mousedev_client *client, signed char *ps2_data)
|
||||||
{
|
{
|
||||||
struct mousedev_motion *p;
|
struct mousedev_motion *p;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&list->packet_lock, flags);
|
spin_lock_irqsave(&client->packet_lock, flags);
|
||||||
p = &list->packets[list->tail];
|
p = &client->packets[client->tail];
|
||||||
|
|
||||||
ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
|
ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
|
||||||
ps2_data[1] = mousedev_limit_delta(p->dx, 127);
|
ps2_data[1] = mousedev_limit_delta(p->dx, 127);
|
||||||
|
@ -464,44 +520,44 @@ static void mousedev_packet(struct mousedev_list *list, signed char *ps2_data)
|
||||||
p->dx -= ps2_data[1];
|
p->dx -= ps2_data[1];
|
||||||
p->dy -= ps2_data[2];
|
p->dy -= ps2_data[2];
|
||||||
|
|
||||||
switch (list->mode) {
|
switch (client->mode) {
|
||||||
case MOUSEDEV_EMUL_EXPS:
|
case MOUSEDEV_EMUL_EXPS:
|
||||||
ps2_data[3] = mousedev_limit_delta(p->dz, 7);
|
ps2_data[3] = mousedev_limit_delta(p->dz, 7);
|
||||||
p->dz -= ps2_data[3];
|
p->dz -= ps2_data[3];
|
||||||
ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
|
ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
|
||||||
list->bufsiz = 4;
|
client->bufsiz = 4;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MOUSEDEV_EMUL_IMPS:
|
case MOUSEDEV_EMUL_IMPS:
|
||||||
ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
|
ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
|
||||||
ps2_data[3] = mousedev_limit_delta(p->dz, 127);
|
ps2_data[3] = mousedev_limit_delta(p->dz, 127);
|
||||||
p->dz -= ps2_data[3];
|
p->dz -= ps2_data[3];
|
||||||
list->bufsiz = 4;
|
client->bufsiz = 4;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MOUSEDEV_EMUL_PS2:
|
case MOUSEDEV_EMUL_PS2:
|
||||||
default:
|
default:
|
||||||
ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
|
ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
|
||||||
p->dz = 0;
|
p->dz = 0;
|
||||||
list->bufsiz = 3;
|
client->bufsiz = 3;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!p->dx && !p->dy && !p->dz) {
|
if (!p->dx && !p->dy && !p->dz) {
|
||||||
if (list->tail == list->head) {
|
if (client->tail == client->head) {
|
||||||
list->ready = 0;
|
client->ready = 0;
|
||||||
list->last_buttons = p->buttons;
|
client->last_buttons = p->buttons;
|
||||||
} else
|
} else
|
||||||
list->tail = (list->tail + 1) % PACKET_QUEUE_LEN;
|
client->tail = (client->tail + 1) % PACKET_QUEUE_LEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&list->packet_lock, flags);
|
spin_unlock_irqrestore(&client->packet_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static ssize_t mousedev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
|
static ssize_t mousedev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
|
||||||
{
|
{
|
||||||
struct mousedev_list *list = file->private_data;
|
struct mousedev_client *client = file->private_data;
|
||||||
unsigned char c;
|
unsigned char c;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
|
@ -510,95 +566,95 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si
|
||||||
if (get_user(c, buffer + i))
|
if (get_user(c, buffer + i))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
if (c == mousedev_imex_seq[list->imexseq]) {
|
if (c == mousedev_imex_seq[client->imexseq]) {
|
||||||
if (++list->imexseq == MOUSEDEV_SEQ_LEN) {
|
if (++client->imexseq == MOUSEDEV_SEQ_LEN) {
|
||||||
list->imexseq = 0;
|
client->imexseq = 0;
|
||||||
list->mode = MOUSEDEV_EMUL_EXPS;
|
client->mode = MOUSEDEV_EMUL_EXPS;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
list->imexseq = 0;
|
client->imexseq = 0;
|
||||||
|
|
||||||
if (c == mousedev_imps_seq[list->impsseq]) {
|
if (c == mousedev_imps_seq[client->impsseq]) {
|
||||||
if (++list->impsseq == MOUSEDEV_SEQ_LEN) {
|
if (++client->impsseq == MOUSEDEV_SEQ_LEN) {
|
||||||
list->impsseq = 0;
|
client->impsseq = 0;
|
||||||
list->mode = MOUSEDEV_EMUL_IMPS;
|
client->mode = MOUSEDEV_EMUL_IMPS;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
list->impsseq = 0;
|
client->impsseq = 0;
|
||||||
|
|
||||||
list->ps2[0] = 0xfa;
|
client->ps2[0] = 0xfa;
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|
||||||
case 0xeb: /* Poll */
|
case 0xeb: /* Poll */
|
||||||
mousedev_packet(list, &list->ps2[1]);
|
mousedev_packet(client, &client->ps2[1]);
|
||||||
list->bufsiz++; /* account for leading ACK */
|
client->bufsiz++; /* account for leading ACK */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xf2: /* Get ID */
|
case 0xf2: /* Get ID */
|
||||||
switch (list->mode) {
|
switch (client->mode) {
|
||||||
case MOUSEDEV_EMUL_PS2: list->ps2[1] = 0; break;
|
case MOUSEDEV_EMUL_PS2: client->ps2[1] = 0; break;
|
||||||
case MOUSEDEV_EMUL_IMPS: list->ps2[1] = 3; break;
|
case MOUSEDEV_EMUL_IMPS: client->ps2[1] = 3; break;
|
||||||
case MOUSEDEV_EMUL_EXPS: list->ps2[1] = 4; break;
|
case MOUSEDEV_EMUL_EXPS: client->ps2[1] = 4; break;
|
||||||
}
|
}
|
||||||
list->bufsiz = 2;
|
client->bufsiz = 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xe9: /* Get info */
|
case 0xe9: /* Get info */
|
||||||
list->ps2[1] = 0x60; list->ps2[2] = 3; list->ps2[3] = 200;
|
client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200;
|
||||||
list->bufsiz = 4;
|
client->bufsiz = 4;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xff: /* Reset */
|
case 0xff: /* Reset */
|
||||||
list->impsseq = list->imexseq = 0;
|
client->impsseq = client->imexseq = 0;
|
||||||
list->mode = MOUSEDEV_EMUL_PS2;
|
client->mode = MOUSEDEV_EMUL_PS2;
|
||||||
list->ps2[1] = 0xaa; list->ps2[2] = 0x00;
|
client->ps2[1] = 0xaa; client->ps2[2] = 0x00;
|
||||||
list->bufsiz = 3;
|
client->bufsiz = 3;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
list->bufsiz = 1;
|
client->bufsiz = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
list->buffer = list->bufsiz;
|
client->buffer = client->bufsiz;
|
||||||
}
|
}
|
||||||
|
|
||||||
kill_fasync(&list->fasync, SIGIO, POLL_IN);
|
kill_fasync(&client->fasync, SIGIO, POLL_IN);
|
||||||
|
|
||||||
wake_up_interruptible(&list->mousedev->wait);
|
wake_up_interruptible(&client->mousedev->wait);
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
|
static ssize_t mousedev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
|
||||||
{
|
{
|
||||||
struct mousedev_list *list = file->private_data;
|
struct mousedev_client *client = file->private_data;
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
if (!list->ready && !list->buffer && (file->f_flags & O_NONBLOCK))
|
if (!client->ready && !client->buffer && (file->f_flags & O_NONBLOCK))
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
retval = wait_event_interruptible(list->mousedev->wait,
|
retval = wait_event_interruptible(client->mousedev->wait,
|
||||||
!list->mousedev->exist || list->ready || list->buffer);
|
!client->mousedev->exist || client->ready || client->buffer);
|
||||||
|
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
if (!list->mousedev->exist)
|
if (!client->mousedev->exist)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if (!list->buffer && list->ready) {
|
if (!client->buffer && client->ready) {
|
||||||
mousedev_packet(list, list->ps2);
|
mousedev_packet(client, client->ps2);
|
||||||
list->buffer = list->bufsiz;
|
client->buffer = client->bufsiz;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count > list->buffer)
|
if (count > client->buffer)
|
||||||
count = list->buffer;
|
count = client->buffer;
|
||||||
|
|
||||||
list->buffer -= count;
|
client->buffer -= count;
|
||||||
|
|
||||||
if (copy_to_user(buffer, list->ps2 + list->bufsiz - list->buffer - count, count))
|
if (copy_to_user(buffer, client->ps2 + client->bufsiz - client->buffer - count, count))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
|
@ -607,11 +663,12 @@ static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t co
|
||||||
/* No kernel lock - fine */
|
/* No kernel lock - fine */
|
||||||
static unsigned int mousedev_poll(struct file *file, poll_table *wait)
|
static unsigned int mousedev_poll(struct file *file, poll_table *wait)
|
||||||
{
|
{
|
||||||
struct mousedev_list *list = file->private_data;
|
struct mousedev_client *client = file->private_data;
|
||||||
|
struct mousedev *mousedev = client->mousedev;
|
||||||
|
|
||||||
poll_wait(file, &list->mousedev->wait, wait);
|
poll_wait(file, &mousedev->wait, wait);
|
||||||
return ((list->ready || list->buffer) ? (POLLIN | POLLRDNORM) : 0) |
|
return ((client->ready || client->buffer) ? (POLLIN | POLLRDNORM) : 0) |
|
||||||
(list->mousedev->exist ? 0 : (POLLHUP | POLLERR));
|
(mousedev->exist ? 0 : (POLLHUP | POLLERR));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations mousedev_fops = {
|
static const struct file_operations mousedev_fops = {
|
||||||
|
@ -624,23 +681,27 @@ static const 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,
|
static int mousedev_connect(struct input_handler *handler, struct input_dev *dev,
|
||||||
const struct input_device_id *id)
|
const struct input_device_id *id)
|
||||||
{
|
{
|
||||||
struct mousedev *mousedev;
|
struct mousedev *mousedev;
|
||||||
struct class_device *cdev;
|
struct class_device *cdev;
|
||||||
int minor = 0;
|
dev_t devt;
|
||||||
|
int minor;
|
||||||
|
int error;
|
||||||
|
|
||||||
for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
|
for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
|
||||||
if (minor == MOUSEDEV_MINORS) {
|
if (minor == MOUSEDEV_MINORS) {
|
||||||
printk(KERN_ERR "mousedev: no more free mousedev devices\n");
|
printk(KERN_ERR "mousedev: no more free mousedev devices\n");
|
||||||
return NULL;
|
return -ENFILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL)))
|
mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL);
|
||||||
return NULL;
|
if (!mousedev)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&mousedev->list);
|
INIT_LIST_HEAD(&mousedev->client_list);
|
||||||
|
INIT_LIST_HEAD(&mousedev->mixdev_node);
|
||||||
init_waitqueue_head(&mousedev->wait);
|
init_waitqueue_head(&mousedev->wait);
|
||||||
|
|
||||||
mousedev->minor = minor;
|
mousedev->minor = minor;
|
||||||
|
@ -651,42 +712,66 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru
|
||||||
mousedev->handle.private = mousedev;
|
mousedev->handle.private = mousedev;
|
||||||
sprintf(mousedev->name, "mouse%d", minor);
|
sprintf(mousedev->name, "mouse%d", minor);
|
||||||
|
|
||||||
if (mousedev_mix.open)
|
|
||||||
input_open_device(&mousedev->handle);
|
|
||||||
|
|
||||||
mousedev_table[minor] = mousedev;
|
mousedev_table[minor] = mousedev;
|
||||||
|
|
||||||
cdev = class_device_create(&input_class, &dev->cdev,
|
devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
|
||||||
MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
|
|
||||||
|
cdev = class_device_create(&input_class, &dev->cdev, devt,
|
||||||
dev->cdev.dev, mousedev->name);
|
dev->cdev.dev, mousedev->name);
|
||||||
|
if (IS_ERR(cdev)) {
|
||||||
|
error = PTR_ERR(cdev);
|
||||||
|
goto err_free_mousedev;
|
||||||
|
}
|
||||||
|
|
||||||
/* temporary symlink to keep userspace happy */
|
/* temporary symlink to keep userspace happy */
|
||||||
sysfs_create_link(&input_class.subsys.kobj, &cdev->kobj,
|
error = sysfs_create_link(&input_class.subsys.kobj,
|
||||||
mousedev->name);
|
&cdev->kobj, mousedev->name);
|
||||||
|
if (error)
|
||||||
|
goto err_cdev_destroy;
|
||||||
|
|
||||||
return &mousedev->handle;
|
error = input_register_handle(&mousedev->handle);
|
||||||
|
if (error)
|
||||||
|
goto err_remove_link;
|
||||||
|
|
||||||
|
error = mixdev_add_device(mousedev);
|
||||||
|
if (error)
|
||||||
|
goto err_unregister_handle;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_unregister_handle:
|
||||||
|
input_unregister_handle(&mousedev->handle);
|
||||||
|
err_remove_link:
|
||||||
|
sysfs_remove_link(&input_class.subsys.kobj, mousedev->name);
|
||||||
|
err_cdev_destroy:
|
||||||
|
class_device_destroy(&input_class, devt);
|
||||||
|
err_free_mousedev:
|
||||||
|
mousedev_table[minor] = NULL;
|
||||||
|
kfree(mousedev);
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mousedev_disconnect(struct input_handle *handle)
|
static void mousedev_disconnect(struct input_handle *handle)
|
||||||
{
|
{
|
||||||
struct mousedev *mousedev = handle->private;
|
struct mousedev *mousedev = handle->private;
|
||||||
struct mousedev_list *list;
|
struct mousedev_client *client;
|
||||||
|
|
||||||
|
input_unregister_handle(handle);
|
||||||
|
|
||||||
sysfs_remove_link(&input_class.subsys.kobj, mousedev->name);
|
sysfs_remove_link(&input_class.subsys.kobj, mousedev->name);
|
||||||
class_device_destroy(&input_class,
|
class_device_destroy(&input_class,
|
||||||
MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor));
|
MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor));
|
||||||
mousedev->exist = 0;
|
mousedev->exist = 0;
|
||||||
|
|
||||||
|
mixdev_remove_device(mousedev);
|
||||||
|
|
||||||
if (mousedev->open) {
|
if (mousedev->open) {
|
||||||
input_close_device(handle);
|
input_close_device(handle);
|
||||||
wake_up_interruptible(&mousedev->wait);
|
wake_up_interruptible(&mousedev->wait);
|
||||||
list_for_each_entry(list, &mousedev->list, node)
|
list_for_each_entry(client, &mousedev->client_list, node)
|
||||||
kill_fasync(&list->fasync, SIGIO, POLL_HUP);
|
kill_fasync(&client->fasync, SIGIO, POLL_HUP);
|
||||||
} else {
|
} else
|
||||||
if (mousedev_mix.open)
|
|
||||||
input_close_device(handle);
|
|
||||||
mousedev_free(mousedev);
|
mousedev_free(mousedev);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct input_device_id mousedev_ids[] = {
|
static const struct input_device_id mousedev_ids[] = {
|
||||||
|
@ -746,7 +831,7 @@ static int __init mousedev_init(void)
|
||||||
return 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.client_list);
|
||||||
init_waitqueue_head(&mousedev_mix.wait);
|
init_waitqueue_head(&mousedev_mix.wait);
|
||||||
mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;
|
mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;
|
||||||
mousedev_mix.exist = 1;
|
mousedev_mix.exist = 1;
|
||||||
|
|
|
@ -1,166 +0,0 @@
|
||||||
/*
|
|
||||||
* $Id: power.c,v 1.10 2001/09/25 09:17:15 vojtech Exp $
|
|
||||||
*
|
|
||||||
* Copyright (c) 2001 "Crazy" James Simmons
|
|
||||||
*
|
|
||||||
* Input driver Power Management.
|
|
||||||
*
|
|
||||||
* Sponsored by Transvirtual Technology.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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 by
|
|
||||||
* e-mail - mail your message to <jsimmons@transvirtual.com>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/input.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/tty.h>
|
|
||||||
#include <linux/delay.h>
|
|
||||||
#include <linux/pm.h>
|
|
||||||
|
|
||||||
static struct input_handler power_handler;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Power management can't be done in a interrupt context. So we have to
|
|
||||||
* use keventd.
|
|
||||||
*/
|
|
||||||
static int suspend_button_pushed = 0;
|
|
||||||
static void suspend_button_task_handler(void *data)
|
|
||||||
{
|
|
||||||
udelay(200); /* debounce */
|
|
||||||
suspend_button_pushed = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static DECLARE_WORK(suspend_button_task, suspend_button_task_handler, NULL);
|
|
||||||
|
|
||||||
static void power_event(struct input_handle *handle, unsigned int type,
|
|
||||||
unsigned int code, int down)
|
|
||||||
{
|
|
||||||
struct input_dev *dev = handle->dev;
|
|
||||||
|
|
||||||
printk("Entering power_event\n");
|
|
||||||
|
|
||||||
if (type == EV_PWR) {
|
|
||||||
switch (code) {
|
|
||||||
case KEY_SUSPEND:
|
|
||||||
printk("Powering down entire device\n");
|
|
||||||
|
|
||||||
if (!suspend_button_pushed) {
|
|
||||||
suspend_button_pushed = 1;
|
|
||||||
schedule_work(&suspend_button_task);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case KEY_POWER:
|
|
||||||
/* Hum power down the machine. */
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == EV_KEY) {
|
|
||||||
switch (code) {
|
|
||||||
case KEY_SUSPEND:
|
|
||||||
printk("Powering down input device\n");
|
|
||||||
/* This is risky. See pm.h for details. */
|
|
||||||
if (dev->state != PM_RESUME)
|
|
||||||
dev->state = PM_RESUME;
|
|
||||||
else
|
|
||||||
dev->state = PM_SUSPEND;
|
|
||||||
pm_send(dev->pm_dev, dev->state, dev);
|
|
||||||
break;
|
|
||||||
case KEY_POWER:
|
|
||||||
/* Turn the input device off completely ? */
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct input_handle *power_connect(struct input_handler *handler,
|
|
||||||
struct input_dev *dev,
|
|
||||||
const struct input_device_id *id)
|
|
||||||
{
|
|
||||||
struct input_handle *handle;
|
|
||||||
|
|
||||||
if (!(handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL)))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
handle->dev = dev;
|
|
||||||
handle->handler = handler;
|
|
||||||
|
|
||||||
input_open_device(handle);
|
|
||||||
|
|
||||||
printk(KERN_INFO "power.c: Adding power management to input layer\n");
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void power_disconnect(struct input_handle *handle)
|
|
||||||
{
|
|
||||||
input_close_device(handle);
|
|
||||||
kfree(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct input_device_id power_ids[] = {
|
|
||||||
{
|
|
||||||
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
|
|
||||||
.evbit = { BIT(EV_KEY) },
|
|
||||||
.keybit = { [LONG(KEY_SUSPEND)] = BIT(KEY_SUSPEND) }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
|
|
||||||
.evbit = { BIT(EV_KEY) },
|
|
||||||
.keybit = { [LONG(KEY_POWER)] = BIT(KEY_POWER) }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
|
|
||||||
.evbit = { BIT(EV_PWR) },
|
|
||||||
},
|
|
||||||
{ }, /* Terminating entry */
|
|
||||||
};
|
|
||||||
|
|
||||||
MODULE_DEVICE_TABLE(input, power_ids);
|
|
||||||
|
|
||||||
static struct input_handler power_handler = {
|
|
||||||
.event = power_event,
|
|
||||||
.connect = power_connect,
|
|
||||||
.disconnect = power_disconnect,
|
|
||||||
.name = "power",
|
|
||||||
.id_table = power_ids,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int __init power_init(void)
|
|
||||||
{
|
|
||||||
return input_register_handler(&power_handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit power_exit(void)
|
|
||||||
{
|
|
||||||
input_unregister_handler(&power_handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
module_init(power_init);
|
|
||||||
module_exit(power_exit);
|
|
||||||
|
|
||||||
MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
|
|
||||||
MODULE_DESCRIPTION("Input Power Management driver");
|
|
||||||
MODULE_LICENSE("GPL");
|
|
|
@ -83,69 +83,85 @@ DECLARE_TASKLET_DISABLED(hil_mlcs_tasklet, hil_mlcs_process, 0);
|
||||||
|
|
||||||
/********************** Device info/instance management **********************/
|
/********************** Device info/instance management **********************/
|
||||||
|
|
||||||
static void hil_mlc_clear_di_map (hil_mlc *mlc, int val) {
|
static void hil_mlc_clear_di_map(hil_mlc *mlc, int val)
|
||||||
|
{
|
||||||
int j;
|
int j;
|
||||||
for (j = val; j < 7 ; j++) {
|
|
||||||
|
for (j = val; j < 7 ; j++)
|
||||||
mlc->di_map[j] = -1;
|
mlc->di_map[j] = -1;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hil_mlc_clear_di_scratch (hil_mlc *mlc) {
|
static void hil_mlc_clear_di_scratch(hil_mlc *mlc)
|
||||||
memset(&(mlc->di_scratch), 0, sizeof(mlc->di_scratch));
|
{
|
||||||
|
memset(&mlc->di_scratch, 0, sizeof(mlc->di_scratch));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hil_mlc_copy_di_scratch (hil_mlc *mlc, int idx) {
|
static void hil_mlc_copy_di_scratch(hil_mlc *mlc, int idx)
|
||||||
memcpy(&(mlc->di[idx]), &(mlc->di_scratch), sizeof(mlc->di_scratch));
|
{
|
||||||
|
memcpy(&mlc->di[idx], &mlc->di_scratch, sizeof(mlc->di_scratch));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hil_mlc_match_di_scratch (hil_mlc *mlc) {
|
static int hil_mlc_match_di_scratch(hil_mlc *mlc)
|
||||||
|
{
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
|
for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
|
||||||
int j, found;
|
int j, found = 0;
|
||||||
|
|
||||||
/* In-use slots are not eligible. */
|
/* In-use slots are not eligible. */
|
||||||
found = 0;
|
for (j = 0; j < 7 ; j++)
|
||||||
for (j = 0; j < 7 ; j++) {
|
if (mlc->di_map[j] == idx)
|
||||||
if (mlc->di_map[j] == idx) found++;
|
found++;
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!memcmp(mlc->di + idx, &mlc->di_scratch,
|
||||||
|
sizeof(mlc->di_scratch)))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (found) continue;
|
return idx >= HIL_MLC_DEVMEM ? -1 : idx;
|
||||||
if (!memcmp(mlc->di + idx,
|
|
||||||
&(mlc->di_scratch),
|
|
||||||
sizeof(mlc->di_scratch))) break;
|
|
||||||
}
|
|
||||||
return((idx >= HIL_MLC_DEVMEM) ? -1 : idx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hil_mlc_find_free_di(hil_mlc *mlc) {
|
static int hil_mlc_find_free_di(hil_mlc *mlc)
|
||||||
|
{
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
/* TODO: Pick all-zero slots first, failing that,
|
/* TODO: Pick all-zero slots first, failing that,
|
||||||
* randomize the slot picked among those eligible.
|
* randomize the slot picked among those eligible.
|
||||||
*/
|
*/
|
||||||
for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
|
for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
|
||||||
int j, found;
|
int j, found = 0;
|
||||||
found = 0;
|
|
||||||
for (j = 0; j < 7 ; j++) {
|
for (j = 0; j < 7 ; j++)
|
||||||
if (mlc->di_map[j] == idx) found++;
|
if (mlc->di_map[j] == idx)
|
||||||
|
found++;
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (!found) break;
|
|
||||||
}
|
return idx; /* Note: It is guaranteed at least one above will match */
|
||||||
return(idx); /* Note: It is guaranteed at least one above will match */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void hil_mlc_clean_serio_map(hil_mlc *mlc) {
|
static inline void hil_mlc_clean_serio_map(hil_mlc *mlc)
|
||||||
|
{
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
|
for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
|
||||||
int j, found;
|
int j, found = 0;
|
||||||
found = 0;
|
|
||||||
for (j = 0; j < 7 ; j++) {
|
for (j = 0; j < 7 ; j++)
|
||||||
if (mlc->di_map[j] == idx) found++;
|
if (mlc->di_map[j] == idx)
|
||||||
}
|
found++;
|
||||||
if (!found) mlc->serio_map[idx].di_revmap = -1;
|
|
||||||
|
if (!found)
|
||||||
|
mlc->serio_map[idx].di_revmap = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hil_mlc_send_polls(hil_mlc *mlc) {
|
static void hil_mlc_send_polls(hil_mlc *mlc)
|
||||||
|
{
|
||||||
int did, i, cnt;
|
int did, i, cnt;
|
||||||
struct serio *serio;
|
struct serio *serio;
|
||||||
struct serio_driver *drv;
|
struct serio_driver *drv;
|
||||||
|
@ -157,27 +173,32 @@ static void hil_mlc_send_polls(hil_mlc *mlc) {
|
||||||
|
|
||||||
while (mlc->icount < 15 - i) {
|
while (mlc->icount < 15 - i) {
|
||||||
hil_packet p;
|
hil_packet p;
|
||||||
|
|
||||||
p = mlc->ipacket[i];
|
p = mlc->ipacket[i];
|
||||||
if (did != (p & HIL_PKT_ADDR_MASK) >> 8) {
|
if (did != (p & HIL_PKT_ADDR_MASK) >> 8) {
|
||||||
if (drv == NULL || drv->interrupt == NULL) goto skip;
|
if (drv && drv->interrupt) {
|
||||||
|
|
||||||
drv->interrupt(serio, 0, 0);
|
drv->interrupt(serio, 0, 0);
|
||||||
drv->interrupt(serio, HIL_ERR_INT >> 16, 0);
|
drv->interrupt(serio, HIL_ERR_INT >> 16, 0);
|
||||||
drv->interrupt(serio, HIL_PKT_CMD >> 8, 0);
|
drv->interrupt(serio, HIL_PKT_CMD >> 8, 0);
|
||||||
drv->interrupt(serio, HIL_CMD_POL + cnt, 0);
|
drv->interrupt(serio, HIL_CMD_POL + cnt, 0);
|
||||||
skip:
|
}
|
||||||
|
|
||||||
did = (p & HIL_PKT_ADDR_MASK) >> 8;
|
did = (p & HIL_PKT_ADDR_MASK) >> 8;
|
||||||
serio = did ? mlc->serio[mlc->di_map[did-1]] : NULL;
|
serio = did ? mlc->serio[mlc->di_map[did-1]] : NULL;
|
||||||
drv = (serio != NULL) ? serio->drv : NULL;
|
drv = (serio != NULL) ? serio->drv : NULL;
|
||||||
cnt = 0;
|
cnt = 0;
|
||||||
}
|
}
|
||||||
cnt++; i++;
|
|
||||||
if (drv == NULL || drv->interrupt == NULL) continue;
|
cnt++;
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (drv && drv->interrupt) {
|
||||||
drv->interrupt(serio, (p >> 24), 0);
|
drv->interrupt(serio, (p >> 24), 0);
|
||||||
drv->interrupt(serio, (p >> 16) & 0xff, 0);
|
drv->interrupt(serio, (p >> 16) & 0xff, 0);
|
||||||
drv->interrupt(serio, (p >> 8) & ~HIL_PKT_ADDR_MASK, 0);
|
drv->interrupt(serio, (p >> 8) & ~HIL_PKT_ADDR_MASK, 0);
|
||||||
drv->interrupt(serio, p & 0xff, 0);
|
drv->interrupt(serio, p & 0xff, 0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************** State engine *********************************/
|
/*************************** State engine *********************************/
|
||||||
|
@ -215,12 +236,16 @@ static void hil_mlc_send_polls(hil_mlc *mlc) {
|
||||||
#define HILSEN_DOZE (HILSEN_SAME | HILSEN_SCHED | HILSEN_BREAK)
|
#define HILSEN_DOZE (HILSEN_SAME | HILSEN_SCHED | HILSEN_BREAK)
|
||||||
#define HILSEN_SLEEP (HILSEN_SAME | HILSEN_BREAK)
|
#define HILSEN_SLEEP (HILSEN_SAME | HILSEN_BREAK)
|
||||||
|
|
||||||
static int hilse_match(hil_mlc *mlc, int unused) {
|
static int hilse_match(hil_mlc *mlc, int unused)
|
||||||
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = hil_mlc_match_di_scratch(mlc);
|
rc = hil_mlc_match_di_scratch(mlc);
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
rc = hil_mlc_find_free_di(mlc);
|
rc = hil_mlc_find_free_di(mlc);
|
||||||
if (rc == -1) goto err;
|
if (rc == -1)
|
||||||
|
goto err;
|
||||||
|
|
||||||
#ifdef HIL_MLC_DEBUG
|
#ifdef HIL_MLC_DEBUG
|
||||||
printk(KERN_DEBUG PREFIX "new in slot %i\n", rc);
|
printk(KERN_DEBUG PREFIX "new in slot %i\n", rc);
|
||||||
#endif
|
#endif
|
||||||
|
@ -231,6 +256,7 @@ static int hilse_match(hil_mlc *mlc, int unused) {
|
||||||
serio_rescan(mlc->serio[rc]);
|
serio_rescan(mlc->serio[rc]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
mlc->di_map[mlc->ddi] = rc;
|
mlc->di_map[mlc->ddi] = rc;
|
||||||
#ifdef HIL_MLC_DEBUG
|
#ifdef HIL_MLC_DEBUG
|
||||||
printk(KERN_DEBUG PREFIX "same in slot %i\n", rc);
|
printk(KERN_DEBUG PREFIX "same in slot %i\n", rc);
|
||||||
|
@ -238,45 +264,53 @@ static int hilse_match(hil_mlc *mlc, int unused) {
|
||||||
mlc->serio_map[rc].di_revmap = mlc->ddi;
|
mlc->serio_map[rc].di_revmap = mlc->ddi;
|
||||||
hil_mlc_clean_serio_map(mlc);
|
hil_mlc_clean_serio_map(mlc);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
printk(KERN_ERR PREFIX "Residual device slots exhausted, close some serios!\n");
|
printk(KERN_ERR PREFIX "Residual device slots exhausted, close some serios!\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* An LCV used to prevent runaway loops, forces 5 second sleep when reset. */
|
/* An LCV used to prevent runaway loops, forces 5 second sleep when reset. */
|
||||||
static int hilse_init_lcv(hil_mlc *mlc, int unused) {
|
static int hilse_init_lcv(hil_mlc *mlc, int unused)
|
||||||
|
{
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
|
||||||
do_gettimeofday(&tv);
|
do_gettimeofday(&tv);
|
||||||
|
|
||||||
if(mlc->lcv == 0) goto restart; /* First init, no need to dally */
|
if (mlc->lcv && (tv.tv_sec - mlc->lcv_tv.tv_sec) < 5)
|
||||||
if(tv.tv_sec - mlc->lcv_tv.tv_sec < 5) return -1;
|
return -1;
|
||||||
restart:
|
|
||||||
mlc->lcv_tv = tv;
|
mlc->lcv_tv = tv;
|
||||||
mlc->lcv = 0;
|
mlc->lcv = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hilse_inc_lcv(hil_mlc *mlc, int lim) {
|
static int hilse_inc_lcv(hil_mlc *mlc, int lim)
|
||||||
if (mlc->lcv++ >= lim) return -1;
|
{
|
||||||
return 0;
|
return mlc->lcv++ >= lim ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
static int hilse_set_lcv(hil_mlc *mlc, int val) {
|
static int hilse_set_lcv(hil_mlc *mlc, int val)
|
||||||
|
{
|
||||||
mlc->lcv = val;
|
mlc->lcv = val;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Management of the discovered device index (zero based, -1 means no devs) */
|
/* Management of the discovered device index (zero based, -1 means no devs) */
|
||||||
static int hilse_set_ddi(hil_mlc *mlc, int val) {
|
static int hilse_set_ddi(hil_mlc *mlc, int val)
|
||||||
|
{
|
||||||
mlc->ddi = val;
|
mlc->ddi = val;
|
||||||
hil_mlc_clear_di_map(mlc, val + 1);
|
hil_mlc_clear_di_map(mlc, val + 1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hilse_dec_ddi(hil_mlc *mlc, int unused) {
|
static int hilse_dec_ddi(hil_mlc *mlc, int unused)
|
||||||
|
{
|
||||||
mlc->ddi--;
|
mlc->ddi--;
|
||||||
if (mlc->ddi <= -1) {
|
if (mlc->ddi <= -1) {
|
||||||
mlc->ddi = -1;
|
mlc->ddi = -1;
|
||||||
|
@ -284,19 +318,20 @@ static int hilse_dec_ddi(hil_mlc *mlc, int unused) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
hil_mlc_clear_di_map(mlc, mlc->ddi + 1);
|
hil_mlc_clear_di_map(mlc, mlc->ddi + 1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hilse_inc_ddi(hil_mlc *mlc, int unused) {
|
static int hilse_inc_ddi(hil_mlc *mlc, int unused)
|
||||||
if (mlc->ddi >= 6) {
|
{
|
||||||
BUG();
|
BUG_ON(mlc->ddi >= 6);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
mlc->ddi++;
|
mlc->ddi++;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hilse_take_idd(hil_mlc *mlc, int unused) {
|
static int hilse_take_idd(hil_mlc *mlc, int unused)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Help the state engine:
|
/* Help the state engine:
|
||||||
|
@ -304,7 +339,9 @@ static int hilse_take_idd(hil_mlc *mlc, int unused) {
|
||||||
*
|
*
|
||||||
* Real IDD response does not start with a command.
|
* Real IDD response does not start with a command.
|
||||||
*/
|
*/
|
||||||
if (mlc->ipacket[0] & HIL_PKT_CMD) goto bail;
|
if (mlc->ipacket[0] & HIL_PKT_CMD)
|
||||||
|
goto bail;
|
||||||
|
|
||||||
/* Should have the command echoed further down. */
|
/* Should have the command echoed further down. */
|
||||||
for (i = 1; i < 16; i++) {
|
for (i = 1; i < 16; i++) {
|
||||||
if (((mlc->ipacket[i] & HIL_PKT_ADDR_MASK) ==
|
if (((mlc->ipacket[i] & HIL_PKT_ADDR_MASK) ==
|
||||||
|
@ -313,77 +350,91 @@ static int hilse_take_idd(hil_mlc *mlc, int unused) {
|
||||||
((mlc->ipacket[i] & HIL_PKT_DATA_MASK) == HIL_CMD_IDD))
|
((mlc->ipacket[i] & HIL_PKT_DATA_MASK) == HIL_CMD_IDD))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (i > 15) goto bail;
|
if (i > 15)
|
||||||
|
goto bail;
|
||||||
|
|
||||||
/* And the rest of the packets should still be clear. */
|
/* And the rest of the packets should still be clear. */
|
||||||
while (++i < 16) {
|
while (++i < 16)
|
||||||
if (mlc->ipacket[i]) break;
|
if (mlc->ipacket[i])
|
||||||
}
|
break;
|
||||||
if (i < 16) goto bail;
|
|
||||||
for (i = 0; i < 16; i++) {
|
if (i < 16)
|
||||||
|
goto bail;
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
mlc->di_scratch.idd[i] =
|
mlc->di_scratch.idd[i] =
|
||||||
mlc->ipacket[i] & HIL_PKT_DATA_MASK;
|
mlc->ipacket[i] & HIL_PKT_DATA_MASK;
|
||||||
}
|
|
||||||
/* Next step is to see if RSC supported */
|
/* Next step is to see if RSC supported */
|
||||||
if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_RSC)
|
if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_RSC)
|
||||||
return HILSEN_NEXT;
|
return HILSEN_NEXT;
|
||||||
|
|
||||||
if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD)
|
if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD)
|
||||||
return HILSEN_DOWN | 4;
|
return HILSEN_DOWN | 4;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
bail:
|
bail:
|
||||||
mlc->ddi--;
|
mlc->ddi--;
|
||||||
|
|
||||||
return -1; /* This should send us off to ACF */
|
return -1; /* This should send us off to ACF */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hilse_take_rsc(hil_mlc *mlc, int unused) {
|
static int hilse_take_rsc(hil_mlc *mlc, int unused)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < 16; i++) {
|
for (i = 0; i < 16; i++)
|
||||||
mlc->di_scratch.rsc[i] =
|
mlc->di_scratch.rsc[i] =
|
||||||
mlc->ipacket[i] & HIL_PKT_DATA_MASK;
|
mlc->ipacket[i] & HIL_PKT_DATA_MASK;
|
||||||
}
|
|
||||||
/* Next step is to see if EXD supported (IDD has already been read) */
|
/* Next step is to see if EXD supported (IDD has already been read) */
|
||||||
if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD)
|
if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD)
|
||||||
return HILSEN_NEXT;
|
return HILSEN_NEXT;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hilse_take_exd(hil_mlc *mlc, int unused) {
|
static int hilse_take_exd(hil_mlc *mlc, int unused)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < 16; i++) {
|
for (i = 0; i < 16; i++)
|
||||||
mlc->di_scratch.exd[i] =
|
mlc->di_scratch.exd[i] =
|
||||||
mlc->ipacket[i] & HIL_PKT_DATA_MASK;
|
mlc->ipacket[i] & HIL_PKT_DATA_MASK;
|
||||||
}
|
|
||||||
/* Next step is to see if RNM supported. */
|
/* Next step is to see if RNM supported. */
|
||||||
if (mlc->di_scratch.exd[0] & HIL_EXD_HEADER_RNM)
|
if (mlc->di_scratch.exd[0] & HIL_EXD_HEADER_RNM)
|
||||||
return HILSEN_NEXT;
|
return HILSEN_NEXT;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hilse_take_rnm(hil_mlc *mlc, int unused) {
|
static int hilse_take_rnm(hil_mlc *mlc, int unused)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < 16; i++) {
|
for (i = 0; i < 16; i++)
|
||||||
mlc->di_scratch.rnm[i] =
|
mlc->di_scratch.rnm[i] =
|
||||||
mlc->ipacket[i] & HIL_PKT_DATA_MASK;
|
mlc->ipacket[i] & HIL_PKT_DATA_MASK;
|
||||||
}
|
|
||||||
do {
|
printk(KERN_INFO PREFIX "Device name gotten: %16s\n",
|
||||||
char nam[17];
|
mlc->di_scratch.rnm);
|
||||||
snprintf(nam, 16, "%s", mlc->di_scratch.rnm);
|
|
||||||
nam[16] = '\0';
|
|
||||||
printk(KERN_INFO PREFIX "Device name gotten: %s\n", nam);
|
|
||||||
} while (0);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hilse_operate(hil_mlc *mlc, int repoll) {
|
static int hilse_operate(hil_mlc *mlc, int repoll)
|
||||||
|
{
|
||||||
|
|
||||||
if (mlc->opercnt == 0) hil_mlcs_probe = 0;
|
if (mlc->opercnt == 0)
|
||||||
|
hil_mlcs_probe = 0;
|
||||||
mlc->opercnt = 1;
|
mlc->opercnt = 1;
|
||||||
|
|
||||||
hil_mlc_send_polls(mlc);
|
hil_mlc_send_polls(mlc);
|
||||||
|
|
||||||
if (!hil_mlcs_probe) return 0;
|
if (!hil_mlcs_probe)
|
||||||
|
return 0;
|
||||||
hil_mlcs_probe = 0;
|
hil_mlcs_probe = 0;
|
||||||
mlc->opercnt = 0;
|
mlc->opercnt = 0;
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -408,7 +459,7 @@ static int hilse_operate(hil_mlc *mlc, int repoll) {
|
||||||
#define OUT_LAST(pack) \
|
#define OUT_LAST(pack) \
|
||||||
{ HILSE_OUT_LAST, { .packet = pack }, 0, 0, 0, 0 },
|
{ HILSE_OUT_LAST, { .packet = pack }, 0, 0, 0, 0 },
|
||||||
|
|
||||||
struct hilse_node hil_mlc_se[HILSEN_END] = {
|
const struct hilse_node hil_mlc_se[HILSEN_END] = {
|
||||||
|
|
||||||
/* 0 HILSEN_START */
|
/* 0 HILSEN_START */
|
||||||
FUNC(hilse_init_lcv, 0, HILSEN_NEXT, HILSEN_SLEEP, 0)
|
FUNC(hilse_init_lcv, 0, HILSEN_NEXT, HILSEN_SLEEP, 0)
|
||||||
|
@ -530,7 +581,8 @@ struct hilse_node hil_mlc_se[HILSEN_END] = {
|
||||||
/* 60 HILSEN_END */
|
/* 60 HILSEN_END */
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void hilse_setup_input(hil_mlc *mlc, struct hilse_node *node) {
|
static inline void hilse_setup_input(hil_mlc *mlc, const struct hilse_node *node)
|
||||||
|
{
|
||||||
|
|
||||||
switch (node->act) {
|
switch (node->act) {
|
||||||
case HILSE_EXPECT_DISC:
|
case HILSE_EXPECT_DISC:
|
||||||
|
@ -555,29 +607,27 @@ static inline void hilse_setup_input(hil_mlc *mlc, struct hilse_node *node) {
|
||||||
do_gettimeofday(&(mlc->instart));
|
do_gettimeofday(&(mlc->instart));
|
||||||
mlc->icount = 15;
|
mlc->icount = 15;
|
||||||
memset(mlc->ipacket, 0, 16 * sizeof(hil_packet));
|
memset(mlc->ipacket, 0, 16 * sizeof(hil_packet));
|
||||||
BUG_ON(down_trylock(&(mlc->isem)));
|
BUG_ON(down_trylock(&mlc->isem));
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HIL_MLC_DEBUG
|
#ifdef HIL_MLC_DEBUG
|
||||||
static int doze = 0;
|
static int doze;
|
||||||
static int seidx; /* For debug */
|
static int seidx; /* For debug */
|
||||||
static int kick = 1;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int hilse_donode (hil_mlc *mlc) {
|
static int hilse_donode(hil_mlc *mlc)
|
||||||
struct hilse_node *node;
|
{
|
||||||
|
const struct hilse_node *node;
|
||||||
int nextidx = 0;
|
int nextidx = 0;
|
||||||
int sched_long = 0;
|
int sched_long = 0;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
#ifdef HIL_MLC_DEBUG
|
#ifdef HIL_MLC_DEBUG
|
||||||
if (mlc->seidx && (mlc->seidx != seidx) && mlc->seidx != 41 && mlc->seidx != 42 && mlc->seidx != 43) {
|
if (mlc->seidx && mlc->seidx != seidx &&
|
||||||
printk(KERN_DEBUG PREFIX "z%i \n%s {%i}", doze, kick ? "K" : "", mlc->seidx);
|
mlc->seidx != 41 && mlc->seidx != 42 && mlc->seidx != 43) {
|
||||||
|
printk(KERN_DEBUG PREFIX "z%i \n {%i}", doze, mlc->seidx);
|
||||||
doze = 0;
|
doze = 0;
|
||||||
}
|
}
|
||||||
kick = 0;
|
|
||||||
|
|
||||||
seidx = mlc->seidx;
|
seidx = mlc->seidx;
|
||||||
#endif
|
#endif
|
||||||
|
@ -588,52 +638,61 @@ static int hilse_donode (hil_mlc *mlc) {
|
||||||
hil_packet pack;
|
hil_packet pack;
|
||||||
|
|
||||||
case HILSE_FUNC:
|
case HILSE_FUNC:
|
||||||
if (node->object.func == NULL) break;
|
BUG_ON(node->object.func == NULL);
|
||||||
rc = node->object.func(mlc, node->arg);
|
rc = node->object.func(mlc, node->arg);
|
||||||
nextidx = (rc > 0) ? node->ugly :
|
nextidx = (rc > 0) ? node->ugly :
|
||||||
((rc < 0) ? node->bad : node->good);
|
((rc < 0) ? node->bad : node->good);
|
||||||
if (nextidx == HILSEN_FOLLOW) nextidx = rc;
|
if (nextidx == HILSEN_FOLLOW)
|
||||||
|
nextidx = rc;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HILSE_EXPECT_LAST:
|
case HILSE_EXPECT_LAST:
|
||||||
case HILSE_EXPECT_DISC:
|
case HILSE_EXPECT_DISC:
|
||||||
case HILSE_EXPECT:
|
case HILSE_EXPECT:
|
||||||
case HILSE_IN:
|
case HILSE_IN:
|
||||||
/* Already set up from previous HILSE_OUT_* */
|
/* Already set up from previous HILSE_OUT_* */
|
||||||
write_lock_irqsave(&(mlc->lock), flags);
|
write_lock_irqsave(&mlc->lock, flags);
|
||||||
rc = mlc->in(mlc, node->arg);
|
rc = mlc->in(mlc, node->arg);
|
||||||
if (rc == 2) {
|
if (rc == 2) {
|
||||||
nextidx = HILSEN_DOZE;
|
nextidx = HILSEN_DOZE;
|
||||||
sched_long = 1;
|
sched_long = 1;
|
||||||
write_unlock_irqrestore(&(mlc->lock), flags);
|
write_unlock_irqrestore(&mlc->lock, flags);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (rc == 1) nextidx = node->ugly;
|
if (rc == 1)
|
||||||
else if (rc == 0) nextidx = node->good;
|
nextidx = node->ugly;
|
||||||
else nextidx = node->bad;
|
else if (rc == 0)
|
||||||
|
nextidx = node->good;
|
||||||
|
else
|
||||||
|
nextidx = node->bad;
|
||||||
mlc->istarted = 0;
|
mlc->istarted = 0;
|
||||||
write_unlock_irqrestore(&(mlc->lock), flags);
|
write_unlock_irqrestore(&mlc->lock, flags);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HILSE_OUT_LAST:
|
case HILSE_OUT_LAST:
|
||||||
write_lock_irqsave(&(mlc->lock), flags);
|
write_lock_irqsave(&mlc->lock, flags);
|
||||||
pack = node->object.packet;
|
pack = node->object.packet;
|
||||||
pack |= ((mlc->ddi + 1) << HIL_PKT_ADDR_SHIFT);
|
pack |= ((mlc->ddi + 1) << HIL_PKT_ADDR_SHIFT);
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
case HILSE_OUT_DISC:
|
case HILSE_OUT_DISC:
|
||||||
write_lock_irqsave(&(mlc->lock), flags);
|
write_lock_irqsave(&mlc->lock, flags);
|
||||||
pack = node->object.packet;
|
pack = node->object.packet;
|
||||||
pack |= ((mlc->ddi + 2) << HIL_PKT_ADDR_SHIFT);
|
pack |= ((mlc->ddi + 2) << HIL_PKT_ADDR_SHIFT);
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
case HILSE_OUT:
|
case HILSE_OUT:
|
||||||
write_lock_irqsave(&(mlc->lock), flags);
|
write_lock_irqsave(&mlc->lock, flags);
|
||||||
pack = node->object.packet;
|
pack = node->object.packet;
|
||||||
out:
|
out:
|
||||||
if (mlc->istarted) goto out2;
|
if (mlc->istarted)
|
||||||
|
goto out2;
|
||||||
/* Prepare to receive input */
|
/* Prepare to receive input */
|
||||||
if ((node + 1)->act & HILSE_IN)
|
if ((node + 1)->act & HILSE_IN)
|
||||||
hilse_setup_input(mlc, node + 1);
|
hilse_setup_input(mlc, node + 1);
|
||||||
|
|
||||||
out2:
|
out2:
|
||||||
write_unlock_irqrestore(&(mlc->lock), flags);
|
write_unlock_irqrestore(&mlc->lock, flags);
|
||||||
|
|
||||||
if (down_trylock(&mlc->osem)) {
|
if (down_trylock(&mlc->osem)) {
|
||||||
nextidx = HILSEN_DOZE;
|
nextidx = HILSEN_DOZE;
|
||||||
|
@ -641,43 +700,47 @@ static int hilse_donode (hil_mlc *mlc) {
|
||||||
}
|
}
|
||||||
up(&mlc->osem);
|
up(&mlc->osem);
|
||||||
|
|
||||||
write_lock_irqsave(&(mlc->lock), flags);
|
write_lock_irqsave(&mlc->lock, flags);
|
||||||
if (!(mlc->ostarted)) {
|
if (!mlc->ostarted) {
|
||||||
mlc->ostarted = 1;
|
mlc->ostarted = 1;
|
||||||
mlc->opacket = pack;
|
mlc->opacket = pack;
|
||||||
mlc->out(mlc);
|
mlc->out(mlc);
|
||||||
nextidx = HILSEN_DOZE;
|
nextidx = HILSEN_DOZE;
|
||||||
write_unlock_irqrestore(&(mlc->lock), flags);
|
write_unlock_irqrestore(&mlc->lock, flags);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mlc->ostarted = 0;
|
mlc->ostarted = 0;
|
||||||
do_gettimeofday(&(mlc->instart));
|
do_gettimeofday(&(mlc->instart));
|
||||||
write_unlock_irqrestore(&(mlc->lock), flags);
|
write_unlock_irqrestore(&mlc->lock, flags);
|
||||||
nextidx = HILSEN_NEXT;
|
nextidx = HILSEN_NEXT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HILSE_CTS:
|
case HILSE_CTS:
|
||||||
|
write_lock_irqsave(&mlc->lock, flags);
|
||||||
nextidx = mlc->cts(mlc) ? node->bad : node->good;
|
nextidx = mlc->cts(mlc) ? node->bad : node->good;
|
||||||
|
write_unlock_irqrestore(&mlc->lock, flags);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
BUG();
|
BUG();
|
||||||
nextidx = 0;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HIL_MLC_DEBUG
|
#ifdef HIL_MLC_DEBUG
|
||||||
if (nextidx == HILSEN_DOZE) doze++;
|
if (nextidx == HILSEN_DOZE)
|
||||||
|
doze++;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (nextidx & HILSEN_SCHED) {
|
while (nextidx & HILSEN_SCHED) {
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
|
||||||
if (!sched_long) goto sched;
|
if (!sched_long)
|
||||||
|
goto sched;
|
||||||
|
|
||||||
do_gettimeofday(&tv);
|
do_gettimeofday(&tv);
|
||||||
tv.tv_usec += 1000000 * (tv.tv_sec - mlc->instart.tv_sec);
|
tv.tv_usec += USEC_PER_SEC * (tv.tv_sec - mlc->instart.tv_sec);
|
||||||
tv.tv_usec -= mlc->instart.tv_usec;
|
tv.tv_usec -= mlc->instart.tv_usec;
|
||||||
if (tv.tv_usec >= mlc->intimeout) goto sched;
|
if (tv.tv_usec >= mlc->intimeout) goto sched;
|
||||||
tv.tv_usec = (mlc->intimeout - tv.tv_usec) * HZ / 1000000;
|
tv.tv_usec = (mlc->intimeout - tv.tv_usec) * HZ / USEC_PER_SEC;
|
||||||
if (!tv.tv_usec) goto sched;
|
if (!tv.tv_usec) goto sched;
|
||||||
mod_timer(&hil_mlcs_kicker, jiffies + tv.tv_usec);
|
mod_timer(&hil_mlcs_kicker, jiffies + tv.tv_usec);
|
||||||
break;
|
break;
|
||||||
|
@ -685,16 +748,23 @@ static int hilse_donode (hil_mlc *mlc) {
|
||||||
tasklet_schedule(&hil_mlcs_tasklet);
|
tasklet_schedule(&hil_mlcs_tasklet);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (nextidx & HILSEN_DOWN) mlc->seidx += nextidx & HILSEN_MASK;
|
|
||||||
else if (nextidx & HILSEN_UP) mlc->seidx -= nextidx & HILSEN_MASK;
|
|
||||||
else mlc->seidx = nextidx & HILSEN_MASK;
|
|
||||||
|
|
||||||
if (nextidx & HILSEN_BREAK) return 1;
|
if (nextidx & HILSEN_DOWN)
|
||||||
|
mlc->seidx += nextidx & HILSEN_MASK;
|
||||||
|
else if (nextidx & HILSEN_UP)
|
||||||
|
mlc->seidx -= nextidx & HILSEN_MASK;
|
||||||
|
else
|
||||||
|
mlc->seidx = nextidx & HILSEN_MASK;
|
||||||
|
|
||||||
|
if (nextidx & HILSEN_BREAK)
|
||||||
|
return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************** tasklet context functions **************************/
|
/******************** tasklet context functions **************************/
|
||||||
static void hil_mlcs_process(unsigned long unused) {
|
static void hil_mlcs_process(unsigned long unused)
|
||||||
|
{
|
||||||
struct list_head *tmp;
|
struct list_head *tmp;
|
||||||
|
|
||||||
read_lock(&hil_mlcs_lock);
|
read_lock(&hil_mlcs_lock);
|
||||||
|
@ -707,14 +777,15 @@ static void hil_mlcs_process(unsigned long unused) {
|
||||||
mlc->seidx != 43)
|
mlc->seidx != 43)
|
||||||
printk(KERN_DEBUG PREFIX " + ");
|
printk(KERN_DEBUG PREFIX " + ");
|
||||||
#endif
|
#endif
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
read_unlock(&hil_mlcs_lock);
|
read_unlock(&hil_mlcs_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************* Keepalive timer task *********************/
|
/************************* Keepalive timer task *********************/
|
||||||
|
|
||||||
void hil_mlcs_timer (unsigned long data) {
|
void hil_mlcs_timer(unsigned long data)
|
||||||
|
{
|
||||||
hil_mlcs_probe = 1;
|
hil_mlcs_probe = 1;
|
||||||
tasklet_schedule(&hil_mlcs_tasklet);
|
tasklet_schedule(&hil_mlcs_tasklet);
|
||||||
/* Re-insert the periodic task. */
|
/* Re-insert the periodic task. */
|
||||||
|
@ -724,22 +795,19 @@ void hil_mlcs_timer (unsigned long data) {
|
||||||
|
|
||||||
/******************** user/kernel context functions **********************/
|
/******************** user/kernel context functions **********************/
|
||||||
|
|
||||||
static int hil_mlc_serio_write(struct serio *serio, unsigned char c) {
|
static int hil_mlc_serio_write(struct serio *serio, unsigned char c)
|
||||||
|
{
|
||||||
struct hil_mlc_serio_map *map;
|
struct hil_mlc_serio_map *map;
|
||||||
struct hil_mlc *mlc;
|
struct hil_mlc *mlc;
|
||||||
struct serio_driver *drv;
|
struct serio_driver *drv;
|
||||||
uint8_t *idx, *last;
|
uint8_t *idx, *last;
|
||||||
|
|
||||||
map = serio->port_data;
|
map = serio->port_data;
|
||||||
if (map == NULL) {
|
BUG_ON(map == NULL);
|
||||||
BUG();
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
mlc = map->mlc;
|
mlc = map->mlc;
|
||||||
if (mlc == NULL) {
|
BUG_ON(mlc == NULL);
|
||||||
BUG();
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
mlc->serio_opacket[map->didx] |=
|
mlc->serio_opacket[map->didx] |=
|
||||||
((hil_packet)c) << (8 * (3 - mlc->serio_oidx[map->didx]));
|
((hil_packet)c) << (8 * (3 - mlc->serio_oidx[map->didx]));
|
||||||
|
|
||||||
|
@ -771,12 +839,11 @@ static int hil_mlc_serio_write(struct serio *serio, unsigned char c) {
|
||||||
return -EIO;
|
return -EIO;
|
||||||
emu:
|
emu:
|
||||||
drv = serio->drv;
|
drv = serio->drv;
|
||||||
if (drv == NULL) {
|
BUG_ON(drv == NULL);
|
||||||
BUG();
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
last = idx + 15;
|
last = idx + 15;
|
||||||
while ((last != idx) && (*last == 0)) last--;
|
while ((last != idx) && (*last == 0))
|
||||||
|
last--;
|
||||||
|
|
||||||
while (idx != last) {
|
while (idx != last) {
|
||||||
drv->interrupt(serio, 0, 0);
|
drv->interrupt(serio, 0, 0);
|
||||||
|
@ -796,7 +863,8 @@ static int hil_mlc_serio_write(struct serio *serio, unsigned char c) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hil_mlc_serio_open(struct serio *serio) {
|
static int hil_mlc_serio_open(struct serio *serio)
|
||||||
|
{
|
||||||
struct hil_mlc_serio_map *map;
|
struct hil_mlc_serio_map *map;
|
||||||
struct hil_mlc *mlc;
|
struct hil_mlc *mlc;
|
||||||
|
|
||||||
|
@ -804,61 +872,51 @@ static int hil_mlc_serio_open(struct serio *serio) {
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
map = serio->port_data;
|
map = serio->port_data;
|
||||||
if (map == NULL) {
|
BUG_ON(map == NULL);
|
||||||
BUG();
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
mlc = map->mlc;
|
mlc = map->mlc;
|
||||||
if (mlc == NULL) {
|
BUG_ON(mlc == NULL);
|
||||||
BUG();
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hil_mlc_serio_close(struct serio *serio) {
|
static void hil_mlc_serio_close(struct serio *serio)
|
||||||
|
{
|
||||||
struct hil_mlc_serio_map *map;
|
struct hil_mlc_serio_map *map;
|
||||||
struct hil_mlc *mlc;
|
struct hil_mlc *mlc;
|
||||||
|
|
||||||
map = serio->port_data;
|
map = serio->port_data;
|
||||||
if (map == NULL) {
|
BUG_ON(map == NULL);
|
||||||
BUG();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mlc = map->mlc;
|
mlc = map->mlc;
|
||||||
if (mlc == NULL) {
|
BUG_ON(mlc == NULL);
|
||||||
BUG();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
serio_set_drvdata(serio, NULL);
|
serio_set_drvdata(serio, NULL);
|
||||||
serio->drv = NULL;
|
serio->drv = NULL;
|
||||||
/* TODO wake up interruptable */
|
/* TODO wake up interruptable */
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct serio_device_id hil_mlc_serio_id = {
|
static const struct serio_device_id hil_mlc_serio_id = {
|
||||||
.type = SERIO_HIL_MLC,
|
.type = SERIO_HIL_MLC,
|
||||||
.proto = SERIO_HIL,
|
.proto = SERIO_HIL,
|
||||||
.extra = SERIO_ANY,
|
.extra = SERIO_ANY,
|
||||||
.id = SERIO_ANY,
|
.id = SERIO_ANY,
|
||||||
};
|
};
|
||||||
|
|
||||||
int hil_mlc_register(hil_mlc *mlc) {
|
int hil_mlc_register(hil_mlc *mlc)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
if (mlc == NULL) {
|
BUG_ON(mlc == NULL);
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
mlc->istarted = 0;
|
mlc->istarted = 0;
|
||||||
mlc->ostarted = 0;
|
mlc->ostarted = 0;
|
||||||
|
|
||||||
rwlock_init(&mlc->lock);
|
rwlock_init(&mlc->lock);
|
||||||
init_MUTEX(&(mlc->osem));
|
init_MUTEX(&mlc->osem);
|
||||||
|
|
||||||
init_MUTEX(&(mlc->isem));
|
init_MUTEX(&mlc->isem);
|
||||||
mlc->icount = -1;
|
mlc->icount = -1;
|
||||||
mlc->imatch = 0;
|
mlc->imatch = 0;
|
||||||
|
|
||||||
|
@ -873,6 +931,8 @@ int hil_mlc_register(hil_mlc *mlc) {
|
||||||
hil_mlc_copy_di_scratch(mlc, i);
|
hil_mlc_copy_di_scratch(mlc, i);
|
||||||
mlc_serio = kzalloc(sizeof(*mlc_serio), GFP_KERNEL);
|
mlc_serio = kzalloc(sizeof(*mlc_serio), GFP_KERNEL);
|
||||||
mlc->serio[i] = mlc_serio;
|
mlc->serio[i] = mlc_serio;
|
||||||
|
snprintf(mlc_serio->name, sizeof(mlc_serio->name)-1, "HIL_SERIO%d", i);
|
||||||
|
snprintf(mlc_serio->phys, sizeof(mlc_serio->phys)-1, "HIL%d", i);
|
||||||
mlc_serio->id = hil_mlc_serio_id;
|
mlc_serio->id = hil_mlc_serio_id;
|
||||||
mlc_serio->write = hil_mlc_serio_write;
|
mlc_serio->write = hil_mlc_serio_write;
|
||||||
mlc_serio->open = hil_mlc_serio_open;
|
mlc_serio->open = hil_mlc_serio_open;
|
||||||
|
@ -897,19 +957,18 @@ int hil_mlc_register(hil_mlc *mlc) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hil_mlc_unregister(hil_mlc *mlc) {
|
int hil_mlc_unregister(hil_mlc *mlc)
|
||||||
|
{
|
||||||
struct list_head *tmp;
|
struct list_head *tmp;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (mlc == NULL)
|
BUG_ON(mlc == NULL);
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
write_lock_irqsave(&hil_mlcs_lock, flags);
|
write_lock_irqsave(&hil_mlcs_lock, flags);
|
||||||
list_for_each(tmp, &hil_mlcs) {
|
list_for_each(tmp, &hil_mlcs)
|
||||||
if (list_entry(tmp, hil_mlc, list) == mlc)
|
if (list_entry(tmp, hil_mlc, list) == mlc)
|
||||||
goto found;
|
goto found;
|
||||||
}
|
|
||||||
|
|
||||||
/* not found in list */
|
/* not found in list */
|
||||||
write_unlock_irqrestore(&hil_mlcs_lock, flags);
|
write_unlock_irqrestore(&hil_mlcs_lock, flags);
|
||||||
|
|
|
@ -100,39 +100,46 @@ EXPORT_SYMBOL(hp_sdc_release_timer_irq);
|
||||||
EXPORT_SYMBOL(hp_sdc_release_hil_irq);
|
EXPORT_SYMBOL(hp_sdc_release_hil_irq);
|
||||||
EXPORT_SYMBOL(hp_sdc_release_cooked_irq);
|
EXPORT_SYMBOL(hp_sdc_release_cooked_irq);
|
||||||
|
|
||||||
|
EXPORT_SYMBOL(__hp_sdc_enqueue_transaction);
|
||||||
EXPORT_SYMBOL(hp_sdc_enqueue_transaction);
|
EXPORT_SYMBOL(hp_sdc_enqueue_transaction);
|
||||||
EXPORT_SYMBOL(hp_sdc_dequeue_transaction);
|
EXPORT_SYMBOL(hp_sdc_dequeue_transaction);
|
||||||
|
|
||||||
static hp_i8042_sdc hp_sdc; /* All driver state is kept in here. */
|
static hp_i8042_sdc hp_sdc; /* All driver state is kept in here. */
|
||||||
|
|
||||||
/*************** primitives for use in any context *********************/
|
/*************** primitives for use in any context *********************/
|
||||||
static inline uint8_t hp_sdc_status_in8 (void) {
|
static inline uint8_t hp_sdc_status_in8(void)
|
||||||
|
{
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
write_lock_irqsave(&hp_sdc.ibf_lock, flags);
|
write_lock_irqsave(&hp_sdc.ibf_lock, flags);
|
||||||
status = sdc_readb(hp_sdc.status_io);
|
status = sdc_readb(hp_sdc.status_io);
|
||||||
if (!(status & HP_SDC_STATUS_IBF)) hp_sdc.ibf = 0;
|
if (!(status & HP_SDC_STATUS_IBF))
|
||||||
|
hp_sdc.ibf = 0;
|
||||||
write_unlock_irqrestore(&hp_sdc.ibf_lock, flags);
|
write_unlock_irqrestore(&hp_sdc.ibf_lock, flags);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint8_t hp_sdc_data_in8 (void) {
|
static inline uint8_t hp_sdc_data_in8(void)
|
||||||
|
{
|
||||||
return sdc_readb(hp_sdc.data_io);
|
return sdc_readb(hp_sdc.data_io);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void hp_sdc_status_out8 (uint8_t val) {
|
static inline void hp_sdc_status_out8(uint8_t val)
|
||||||
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
write_lock_irqsave(&hp_sdc.ibf_lock, flags);
|
write_lock_irqsave(&hp_sdc.ibf_lock, flags);
|
||||||
hp_sdc.ibf = 1;
|
hp_sdc.ibf = 1;
|
||||||
if ((val & 0xf0) == 0xe0) hp_sdc.wi = 0xff;
|
if ((val & 0xf0) == 0xe0)
|
||||||
|
hp_sdc.wi = 0xff;
|
||||||
sdc_writeb(val, hp_sdc.status_io);
|
sdc_writeb(val, hp_sdc.status_io);
|
||||||
write_unlock_irqrestore(&hp_sdc.ibf_lock, flags);
|
write_unlock_irqrestore(&hp_sdc.ibf_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void hp_sdc_data_out8 (uint8_t val) {
|
static inline void hp_sdc_data_out8(uint8_t val)
|
||||||
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
write_lock_irqsave(&hp_sdc.ibf_lock, flags);
|
write_lock_irqsave(&hp_sdc.ibf_lock, flags);
|
||||||
|
@ -145,7 +152,8 @@ static inline void hp_sdc_data_out8 (uint8_t val) {
|
||||||
* absolutely needed, or in rarely invoked subroutines.
|
* absolutely needed, or in rarely invoked subroutines.
|
||||||
* Not only does it waste CPU cycles, it also wastes bus cycles.
|
* Not only does it waste CPU cycles, it also wastes bus cycles.
|
||||||
*/
|
*/
|
||||||
static inline void hp_sdc_spin_ibf(void) {
|
static inline void hp_sdc_spin_ibf(void)
|
||||||
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
rwlock_t *lock;
|
rwlock_t *lock;
|
||||||
|
|
||||||
|
@ -158,14 +166,16 @@ static inline void hp_sdc_spin_ibf(void) {
|
||||||
}
|
}
|
||||||
read_unlock(lock);
|
read_unlock(lock);
|
||||||
write_lock(lock);
|
write_lock(lock);
|
||||||
while (sdc_readb(hp_sdc.status_io) & HP_SDC_STATUS_IBF) {};
|
while (sdc_readb(hp_sdc.status_io) & HP_SDC_STATUS_IBF)
|
||||||
|
{ }
|
||||||
hp_sdc.ibf = 0;
|
hp_sdc.ibf = 0;
|
||||||
write_unlock_irqrestore(lock, flags);
|
write_unlock_irqrestore(lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/************************ Interrupt context functions ************************/
|
/************************ Interrupt context functions ************************/
|
||||||
static void hp_sdc_take (int irq, void *dev_id, uint8_t status, uint8_t data) {
|
static void hp_sdc_take(int irq, void *dev_id, uint8_t status, uint8_t data)
|
||||||
|
{
|
||||||
hp_sdc_transaction *curr;
|
hp_sdc_transaction *curr;
|
||||||
|
|
||||||
read_lock(&hp_sdc.rtq_lock);
|
read_lock(&hp_sdc.rtq_lock);
|
||||||
|
@ -183,13 +193,14 @@ static void hp_sdc_take (int irq, void *dev_id, uint8_t status, uint8_t data) {
|
||||||
|
|
||||||
if (hp_sdc.rqty <= 0) {
|
if (hp_sdc.rqty <= 0) {
|
||||||
/* All data has been gathered. */
|
/* All data has been gathered. */
|
||||||
if(curr->seq[curr->actidx] & HP_SDC_ACT_SEMAPHORE) {
|
if (curr->seq[curr->actidx] & HP_SDC_ACT_SEMAPHORE)
|
||||||
if (curr->act.semaphore) up(curr->act.semaphore);
|
if (curr->act.semaphore)
|
||||||
}
|
up(curr->act.semaphore);
|
||||||
if(curr->seq[curr->actidx] & HP_SDC_ACT_CALLBACK) {
|
|
||||||
|
if (curr->seq[curr->actidx] & HP_SDC_ACT_CALLBACK)
|
||||||
if (curr->act.irqhook)
|
if (curr->act.irqhook)
|
||||||
curr->act.irqhook(irq, dev_id, status, data);
|
curr->act.irqhook(irq, dev_id, status, data);
|
||||||
}
|
|
||||||
curr->actidx = curr->idx;
|
curr->actidx = curr->idx;
|
||||||
curr->idx++;
|
curr->idx++;
|
||||||
/* Return control of this transaction */
|
/* Return control of this transaction */
|
||||||
|
@ -201,7 +212,8 @@ static void hp_sdc_take (int irq, void *dev_id, uint8_t status, uint8_t data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static irqreturn_t hp_sdc_isr(int irq, void *dev_id) {
|
static irqreturn_t hp_sdc_isr(int irq, void *dev_id)
|
||||||
|
{
|
||||||
uint8_t status, data;
|
uint8_t status, data;
|
||||||
|
|
||||||
status = hp_sdc_status_in8();
|
status = hp_sdc_status_in8();
|
||||||
|
@ -209,13 +221,13 @@ static irqreturn_t hp_sdc_isr(int irq, void *dev_id) {
|
||||||
data = hp_sdc_data_in8();
|
data = hp_sdc_data_in8();
|
||||||
|
|
||||||
/* For now we are ignoring these until we get the SDC to behave. */
|
/* For now we are ignoring these until we get the SDC to behave. */
|
||||||
if (((status & 0xf1) == 0x51) && data == 0x82) {
|
if (((status & 0xf1) == 0x51) && data == 0x82)
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
|
||||||
|
|
||||||
switch(status & HP_SDC_STATUS_IRQMASK) {
|
switch (status & HP_SDC_STATUS_IRQMASK) {
|
||||||
case 0: /* This case is not documented. */
|
case 0: /* This case is not documented. */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HP_SDC_STATUS_USERTIMER:
|
case HP_SDC_STATUS_USERTIMER:
|
||||||
case HP_SDC_STATUS_PERIODIC:
|
case HP_SDC_STATUS_PERIODIC:
|
||||||
case HP_SDC_STATUS_TIMER:
|
case HP_SDC_STATUS_TIMER:
|
||||||
|
@ -224,9 +236,11 @@ static irqreturn_t hp_sdc_isr(int irq, void *dev_id) {
|
||||||
hp_sdc.timer(irq, dev_id, status, data);
|
hp_sdc.timer(irq, dev_id, status, data);
|
||||||
read_unlock(&hp_sdc.hook_lock);
|
read_unlock(&hp_sdc.hook_lock);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HP_SDC_STATUS_REG:
|
case HP_SDC_STATUS_REG:
|
||||||
hp_sdc_take(irq, dev_id, status, data);
|
hp_sdc_take(irq, dev_id, status, data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HP_SDC_STATUS_HILCMD:
|
case HP_SDC_STATUS_HILCMD:
|
||||||
case HP_SDC_STATUS_HILDATA:
|
case HP_SDC_STATUS_HILDATA:
|
||||||
read_lock(&hp_sdc.hook_lock);
|
read_lock(&hp_sdc.hook_lock);
|
||||||
|
@ -234,13 +248,16 @@ static irqreturn_t hp_sdc_isr(int irq, void *dev_id) {
|
||||||
hp_sdc.hil(irq, dev_id, status, data);
|
hp_sdc.hil(irq, dev_id, status, data);
|
||||||
read_unlock(&hp_sdc.hook_lock);
|
read_unlock(&hp_sdc.hook_lock);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HP_SDC_STATUS_PUP:
|
case HP_SDC_STATUS_PUP:
|
||||||
read_lock(&hp_sdc.hook_lock);
|
read_lock(&hp_sdc.hook_lock);
|
||||||
if (hp_sdc.pup != NULL)
|
if (hp_sdc.pup != NULL)
|
||||||
hp_sdc.pup(irq, dev_id, status, data);
|
hp_sdc.pup(irq, dev_id, status, data);
|
||||||
else printk(KERN_INFO PREFIX "HP SDC reports successful PUP.\n");
|
else
|
||||||
|
printk(KERN_INFO PREFIX "HP SDC reports successful PUP.\n");
|
||||||
read_unlock(&hp_sdc.hook_lock);
|
read_unlock(&hp_sdc.hook_lock);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
read_lock(&hp_sdc.hook_lock);
|
read_lock(&hp_sdc.hook_lock);
|
||||||
if (hp_sdc.cooked != NULL)
|
if (hp_sdc.cooked != NULL)
|
||||||
|
@ -248,11 +265,13 @@ static irqreturn_t hp_sdc_isr(int irq, void *dev_id) {
|
||||||
read_unlock(&hp_sdc.hook_lock);
|
read_unlock(&hp_sdc.hook_lock);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id) {
|
static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id)
|
||||||
|
{
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
status = hp_sdc_status_in8();
|
status = hp_sdc_status_in8();
|
||||||
|
@ -264,12 +283,12 @@ static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id) {
|
||||||
if (hp_sdc.timer != NULL)
|
if (hp_sdc.timer != NULL)
|
||||||
hp_sdc.timer(irq, dev_id, status, 0);
|
hp_sdc.timer(irq, dev_id, status, 0);
|
||||||
read_unlock(&hp_sdc.hook_lock);
|
read_unlock(&hp_sdc.hook_lock);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
/* TODO: pass this on to the HIL handler, or do SAK here? */
|
/* TODO: pass this on to the HIL handler, or do SAK here? */
|
||||||
printk(KERN_WARNING PREFIX "HIL NMI\n");
|
printk(KERN_WARNING PREFIX "HIL NMI\n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,13 +297,17 @@ static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id) {
|
||||||
|
|
||||||
unsigned long hp_sdc_put(void);
|
unsigned long hp_sdc_put(void);
|
||||||
|
|
||||||
static void hp_sdc_tasklet(unsigned long foo) {
|
static void hp_sdc_tasklet(unsigned long foo)
|
||||||
|
{
|
||||||
write_lock_irq(&hp_sdc.rtq_lock);
|
write_lock_irq(&hp_sdc.rtq_lock);
|
||||||
|
|
||||||
if (hp_sdc.rcurr >= 0) {
|
if (hp_sdc.rcurr >= 0) {
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
|
||||||
do_gettimeofday(&tv);
|
do_gettimeofday(&tv);
|
||||||
if (tv.tv_sec > hp_sdc.rtv.tv_sec) tv.tv_usec += 1000000;
|
if (tv.tv_sec > hp_sdc.rtv.tv_sec)
|
||||||
|
tv.tv_usec += USEC_PER_SEC;
|
||||||
|
|
||||||
if (tv.tv_usec - hp_sdc.rtv.tv_usec > HP_SDC_MAX_REG_DELAY) {
|
if (tv.tv_usec - hp_sdc.rtv.tv_usec > HP_SDC_MAX_REG_DELAY) {
|
||||||
hp_sdc_transaction *curr;
|
hp_sdc_transaction *curr;
|
||||||
uint8_t tmp;
|
uint8_t tmp;
|
||||||
|
@ -300,17 +323,18 @@ static void hp_sdc_tasklet(unsigned long foo) {
|
||||||
hp_sdc.rqty = 0;
|
hp_sdc.rqty = 0;
|
||||||
tmp = curr->seq[curr->actidx];
|
tmp = curr->seq[curr->actidx];
|
||||||
curr->seq[curr->actidx] |= HP_SDC_ACT_DEAD;
|
curr->seq[curr->actidx] |= HP_SDC_ACT_DEAD;
|
||||||
if(tmp & HP_SDC_ACT_SEMAPHORE) {
|
if (tmp & HP_SDC_ACT_SEMAPHORE)
|
||||||
if (curr->act.semaphore)
|
if (curr->act.semaphore)
|
||||||
up(curr->act.semaphore);
|
up(curr->act.semaphore);
|
||||||
}
|
|
||||||
if(tmp & HP_SDC_ACT_CALLBACK) {
|
if (tmp & HP_SDC_ACT_CALLBACK) {
|
||||||
/* Note this means that irqhooks may be called
|
/* Note this means that irqhooks may be called
|
||||||
* in tasklet/bh context.
|
* in tasklet/bh context.
|
||||||
*/
|
*/
|
||||||
if (curr->act.irqhook)
|
if (curr->act.irqhook)
|
||||||
curr->act.irqhook(0, NULL, 0, 0);
|
curr->act.irqhook(0, NULL, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
curr->actidx = curr->idx;
|
curr->actidx = curr->idx;
|
||||||
curr->idx++;
|
curr->idx++;
|
||||||
hp_sdc.rcurr = -1;
|
hp_sdc.rcurr = -1;
|
||||||
|
@ -320,7 +344,8 @@ static void hp_sdc_tasklet(unsigned long foo) {
|
||||||
hp_sdc_put();
|
hp_sdc_put();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long hp_sdc_put(void) {
|
unsigned long hp_sdc_put(void)
|
||||||
|
{
|
||||||
hp_sdc_transaction *curr;
|
hp_sdc_transaction *curr;
|
||||||
uint8_t act;
|
uint8_t act;
|
||||||
int idx, curridx;
|
int idx, curridx;
|
||||||
|
@ -333,19 +358,24 @@ unsigned long hp_sdc_put(void) {
|
||||||
requires output, so we skip to the administrativa. */
|
requires output, so we skip to the administrativa. */
|
||||||
if (hp_sdc.ibf) {
|
if (hp_sdc.ibf) {
|
||||||
hp_sdc_status_in8();
|
hp_sdc_status_in8();
|
||||||
if (hp_sdc.ibf) goto finish;
|
if (hp_sdc.ibf)
|
||||||
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
anew:
|
anew:
|
||||||
/* See if we are in the middle of a sequence. */
|
/* See if we are in the middle of a sequence. */
|
||||||
if (hp_sdc.wcurr < 0) hp_sdc.wcurr = 0;
|
if (hp_sdc.wcurr < 0)
|
||||||
|
hp_sdc.wcurr = 0;
|
||||||
read_lock_irq(&hp_sdc.rtq_lock);
|
read_lock_irq(&hp_sdc.rtq_lock);
|
||||||
if (hp_sdc.rcurr == hp_sdc.wcurr) hp_sdc.wcurr++;
|
if (hp_sdc.rcurr == hp_sdc.wcurr)
|
||||||
|
hp_sdc.wcurr++;
|
||||||
read_unlock_irq(&hp_sdc.rtq_lock);
|
read_unlock_irq(&hp_sdc.rtq_lock);
|
||||||
if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0;
|
if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN)
|
||||||
|
hp_sdc.wcurr = 0;
|
||||||
curridx = hp_sdc.wcurr;
|
curridx = hp_sdc.wcurr;
|
||||||
|
|
||||||
if (hp_sdc.tq[curridx] != NULL) goto start;
|
if (hp_sdc.tq[curridx] != NULL)
|
||||||
|
goto start;
|
||||||
|
|
||||||
while (++curridx != hp_sdc.wcurr) {
|
while (++curridx != hp_sdc.wcurr) {
|
||||||
if (curridx >= HP_SDC_QUEUE_LEN) {
|
if (curridx >= HP_SDC_QUEUE_LEN) {
|
||||||
|
@ -358,7 +388,8 @@ unsigned long hp_sdc_put(void) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
read_unlock_irq(&hp_sdc.rtq_lock);
|
read_unlock_irq(&hp_sdc.rtq_lock);
|
||||||
if (hp_sdc.tq[curridx] != NULL) break; /* Found one. */
|
if (hp_sdc.tq[curridx] != NULL)
|
||||||
|
break; /* Found one. */
|
||||||
}
|
}
|
||||||
if (curridx == hp_sdc.wcurr) { /* There's nothing queued to do. */
|
if (curridx == hp_sdc.wcurr) { /* There's nothing queued to do. */
|
||||||
curridx = -1;
|
curridx = -1;
|
||||||
|
@ -374,7 +405,8 @@ unsigned long hp_sdc_put(void) {
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hp_sdc.wcurr == -1) goto done;
|
if (hp_sdc.wcurr == -1)
|
||||||
|
goto done;
|
||||||
|
|
||||||
curr = hp_sdc.tq[curridx];
|
curr = hp_sdc.tq[curridx];
|
||||||
idx = curr->actidx;
|
idx = curr->actidx;
|
||||||
|
@ -383,7 +415,8 @@ unsigned long hp_sdc_put(void) {
|
||||||
hp_sdc.tq[curridx] = NULL;
|
hp_sdc.tq[curridx] = NULL;
|
||||||
/* Interleave outbound data between the transactions. */
|
/* Interleave outbound data between the transactions. */
|
||||||
hp_sdc.wcurr++;
|
hp_sdc.wcurr++;
|
||||||
if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0;
|
if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN)
|
||||||
|
hp_sdc.wcurr = 0;
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,11 +424,13 @@ unsigned long hp_sdc_put(void) {
|
||||||
idx++;
|
idx++;
|
||||||
|
|
||||||
if (curr->idx >= curr->endidx) {
|
if (curr->idx >= curr->endidx) {
|
||||||
if (act & HP_SDC_ACT_DEALLOC) kfree(curr);
|
if (act & HP_SDC_ACT_DEALLOC)
|
||||||
|
kfree(curr);
|
||||||
hp_sdc.tq[curridx] = NULL;
|
hp_sdc.tq[curridx] = NULL;
|
||||||
/* Interleave outbound data between the transactions. */
|
/* Interleave outbound data between the transactions. */
|
||||||
hp_sdc.wcurr++;
|
hp_sdc.wcurr++;
|
||||||
if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0;
|
if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN)
|
||||||
|
hp_sdc.wcurr = 0;
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,7 +446,8 @@ unsigned long hp_sdc_put(void) {
|
||||||
if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_PRECMD)
|
if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_PRECMD)
|
||||||
goto actdone;
|
goto actdone;
|
||||||
/* skip quantity field if data-out sequence follows. */
|
/* skip quantity field if data-out sequence follows. */
|
||||||
if (act & HP_SDC_ACT_DATAOUT) curr->idx++;
|
if (act & HP_SDC_ACT_DATAOUT)
|
||||||
|
curr->idx++;
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
if (act & HP_SDC_ACT_DATAOUT) {
|
if (act & HP_SDC_ACT_DATAOUT) {
|
||||||
|
@ -423,15 +459,15 @@ unsigned long hp_sdc_put(void) {
|
||||||
hp_sdc_data_out8(curr->seq[curr->idx]);
|
hp_sdc_data_out8(curr->seq[curr->idx]);
|
||||||
curr->idx++;
|
curr->idx++;
|
||||||
/* act finished? */
|
/* act finished? */
|
||||||
if ((curr->idx - idx >= qty) &&
|
if (curr->idx - idx >= qty &&
|
||||||
((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAOUT))
|
(act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAOUT)
|
||||||
goto actdone;
|
goto actdone;
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
idx += qty;
|
idx += qty;
|
||||||
act &= ~HP_SDC_ACT_DATAOUT;
|
act &= ~HP_SDC_ACT_DATAOUT;
|
||||||
}
|
} else
|
||||||
else while (act & HP_SDC_ACT_DATAREG) {
|
while (act & HP_SDC_ACT_DATAREG) {
|
||||||
int mask;
|
int mask;
|
||||||
uint8_t w7[4];
|
uint8_t w7[4];
|
||||||
|
|
||||||
|
@ -452,19 +488,23 @@ unsigned long hp_sdc_put(void) {
|
||||||
w7[3] = (mask & 8) ? curr->seq[++idx] : hp_sdc.r7[3];
|
w7[3] = (mask & 8) ? curr->seq[++idx] : hp_sdc.r7[3];
|
||||||
|
|
||||||
if (hp_sdc.wi > 0x73 || hp_sdc.wi < 0x70 ||
|
if (hp_sdc.wi > 0x73 || hp_sdc.wi < 0x70 ||
|
||||||
w7[hp_sdc.wi-0x70] == hp_sdc.r7[hp_sdc.wi-0x70]) {
|
w7[hp_sdc.wi - 0x70] == hp_sdc.r7[hp_sdc.wi - 0x70]) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
/* Need to point the write index register */
|
/* Need to point the write index register */
|
||||||
while ((i < 4) && w7[i] == hp_sdc.r7[i]) i++;
|
while (i < 4 && w7[i] == hp_sdc.r7[i])
|
||||||
|
i++;
|
||||||
|
|
||||||
if (i < 4) {
|
if (i < 4) {
|
||||||
hp_sdc_status_out8(HP_SDC_CMD_SET_D0 + i);
|
hp_sdc_status_out8(HP_SDC_CMD_SET_D0 + i);
|
||||||
hp_sdc.wi = 0x70 + i;
|
hp_sdc.wi = 0x70 + i;
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
idx++;
|
idx++;
|
||||||
if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAREG)
|
if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAREG)
|
||||||
goto actdone;
|
goto actdone;
|
||||||
|
|
||||||
curr->idx = idx;
|
curr->idx = idx;
|
||||||
act &= ~HP_SDC_ACT_DATAREG;
|
act &= ~HP_SDC_ACT_DATAREG;
|
||||||
break;
|
break;
|
||||||
|
@ -476,7 +516,8 @@ unsigned long hp_sdc_put(void) {
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
while ((i < 4) && w7[i] == hp_sdc.r7[i]) i++;
|
while ((i < 4) && w7[i] == hp_sdc.r7[i])
|
||||||
|
i++;
|
||||||
if (i >= 4) {
|
if (i >= 4) {
|
||||||
curr->idx = idx + 1;
|
curr->idx = idx + 1;
|
||||||
if ((act & HP_SDC_ACT_DURING) ==
|
if ((act & HP_SDC_ACT_DURING) ==
|
||||||
|
@ -519,75 +560,86 @@ unsigned long hp_sdc_put(void) {
|
||||||
goto actdone;
|
goto actdone;
|
||||||
}
|
}
|
||||||
|
|
||||||
actdone:
|
actdone:
|
||||||
if (act & HP_SDC_ACT_SEMAPHORE) {
|
if (act & HP_SDC_ACT_SEMAPHORE)
|
||||||
up(curr->act.semaphore);
|
up(curr->act.semaphore);
|
||||||
}
|
else if (act & HP_SDC_ACT_CALLBACK)
|
||||||
else if (act & HP_SDC_ACT_CALLBACK) {
|
|
||||||
curr->act.irqhook(0,NULL,0,0);
|
curr->act.irqhook(0,NULL,0,0);
|
||||||
}
|
|
||||||
if (curr->idx >= curr->endidx) { /* This transaction is over. */
|
if (curr->idx >= curr->endidx) { /* This transaction is over. */
|
||||||
if (act & HP_SDC_ACT_DEALLOC) kfree(curr);
|
if (act & HP_SDC_ACT_DEALLOC)
|
||||||
|
kfree(curr);
|
||||||
hp_sdc.tq[curridx] = NULL;
|
hp_sdc.tq[curridx] = NULL;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
curr->actidx = idx + 1;
|
curr->actidx = idx + 1;
|
||||||
curr->idx = idx + 2;
|
curr->idx = idx + 2;
|
||||||
}
|
}
|
||||||
/* Interleave outbound data between the transactions. */
|
/* Interleave outbound data between the transactions. */
|
||||||
hp_sdc.wcurr++;
|
hp_sdc.wcurr++;
|
||||||
if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0;
|
if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN)
|
||||||
|
hp_sdc.wcurr = 0;
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
/* If by some quirk IBF has cleared and our ISR has run to
|
/* If by some quirk IBF has cleared and our ISR has run to
|
||||||
see that that has happened, do it all again. */
|
see that that has happened, do it all again. */
|
||||||
if (!hp_sdc.ibf && limit++ < 20) goto anew;
|
if (!hp_sdc.ibf && limit++ < 20)
|
||||||
|
goto anew;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (hp_sdc.wcurr >= 0) tasklet_schedule(&hp_sdc.task);
|
if (hp_sdc.wcurr >= 0)
|
||||||
|
tasklet_schedule(&hp_sdc.task);
|
||||||
write_unlock(&hp_sdc.lock);
|
write_unlock(&hp_sdc.lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******* Functions called in either user or kernel context ****/
|
/******* Functions called in either user or kernel context ****/
|
||||||
int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) {
|
int __hp_sdc_enqueue_transaction(hp_sdc_transaction *this)
|
||||||
unsigned long flags;
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (this == NULL) {
|
if (this == NULL) {
|
||||||
tasklet_schedule(&hp_sdc.task);
|
BUG();
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
};
|
}
|
||||||
|
|
||||||
write_lock_irqsave(&hp_sdc.lock, flags);
|
|
||||||
|
|
||||||
/* Can't have same transaction on queue twice */
|
/* Can't have same transaction on queue twice */
|
||||||
for (i=0; i < HP_SDC_QUEUE_LEN; i++)
|
for (i = 0; i < HP_SDC_QUEUE_LEN; i++)
|
||||||
if (hp_sdc.tq[i] == this) goto fail;
|
if (hp_sdc.tq[i] == this)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
this->actidx = 0;
|
this->actidx = 0;
|
||||||
this->idx = 1;
|
this->idx = 1;
|
||||||
|
|
||||||
/* Search for empty slot */
|
/* Search for empty slot */
|
||||||
for (i=0; i < HP_SDC_QUEUE_LEN; i++) {
|
for (i = 0; i < HP_SDC_QUEUE_LEN; i++)
|
||||||
if (hp_sdc.tq[i] == NULL) {
|
if (hp_sdc.tq[i] == NULL) {
|
||||||
hp_sdc.tq[i] = this;
|
hp_sdc.tq[i] = this;
|
||||||
write_unlock_irqrestore(&hp_sdc.lock, flags);
|
|
||||||
tasklet_schedule(&hp_sdc.task);
|
tasklet_schedule(&hp_sdc.task);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
write_unlock_irqrestore(&hp_sdc.lock, flags);
|
|
||||||
printk(KERN_WARNING PREFIX "No free slot to add transaction.\n");
|
printk(KERN_WARNING PREFIX "No free slot to add transaction.\n");
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
write_unlock_irqrestore(&hp_sdc.lock,flags);
|
|
||||||
printk(KERN_WARNING PREFIX "Transaction add failed: transaction already queued?\n");
|
printk(KERN_WARNING PREFIX "Transaction add failed: transaction already queued?\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hp_sdc_dequeue_transaction(hp_sdc_transaction *this) {
|
int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) {
|
||||||
|
unsigned long flags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
write_lock_irqsave(&hp_sdc.lock, flags);
|
||||||
|
ret = __hp_sdc_enqueue_transaction(this);
|
||||||
|
write_unlock_irqrestore(&hp_sdc.lock,flags);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hp_sdc_dequeue_transaction(hp_sdc_transaction *this)
|
||||||
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -595,8 +647,9 @@ int hp_sdc_dequeue_transaction(hp_sdc_transaction *this) {
|
||||||
|
|
||||||
/* TODO: don't remove it if it's not done. */
|
/* TODO: don't remove it if it's not done. */
|
||||||
|
|
||||||
for (i=0; i < HP_SDC_QUEUE_LEN; i++)
|
for (i = 0; i < HP_SDC_QUEUE_LEN; i++)
|
||||||
if (hp_sdc.tq[i] == this) hp_sdc.tq[i] = NULL;
|
if (hp_sdc.tq[i] == this)
|
||||||
|
hp_sdc.tq[i] = NULL;
|
||||||
|
|
||||||
write_unlock_irqrestore(&hp_sdc.lock, flags);
|
write_unlock_irqrestore(&hp_sdc.lock, flags);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -605,11 +658,11 @@ int hp_sdc_dequeue_transaction(hp_sdc_transaction *this) {
|
||||||
|
|
||||||
|
|
||||||
/********************** User context functions **************************/
|
/********************** User context functions **************************/
|
||||||
int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback) {
|
int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback)
|
||||||
|
{
|
||||||
if (callback == NULL || hp_sdc.dev == NULL) {
|
if (callback == NULL || hp_sdc.dev == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
write_lock_irq(&hp_sdc.hook_lock);
|
write_lock_irq(&hp_sdc.hook_lock);
|
||||||
if (hp_sdc.timer != NULL) {
|
if (hp_sdc.timer != NULL) {
|
||||||
write_unlock_irq(&hp_sdc.hook_lock);
|
write_unlock_irq(&hp_sdc.hook_lock);
|
||||||
|
@ -629,11 +682,11 @@ int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback) {
|
int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback)
|
||||||
|
{
|
||||||
if (callback == NULL || hp_sdc.dev == NULL) {
|
if (callback == NULL || hp_sdc.dev == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
write_lock_irq(&hp_sdc.hook_lock);
|
write_lock_irq(&hp_sdc.hook_lock);
|
||||||
if (hp_sdc.hil != NULL) {
|
if (hp_sdc.hil != NULL) {
|
||||||
write_unlock_irq(&hp_sdc.hook_lock);
|
write_unlock_irq(&hp_sdc.hook_lock);
|
||||||
|
@ -650,11 +703,11 @@ int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback) {
|
int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback)
|
||||||
|
{
|
||||||
if (callback == NULL || hp_sdc.dev == NULL) {
|
if (callback == NULL || hp_sdc.dev == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
write_lock_irq(&hp_sdc.hook_lock);
|
write_lock_irq(&hp_sdc.hook_lock);
|
||||||
if (hp_sdc.cooked != NULL) {
|
if (hp_sdc.cooked != NULL) {
|
||||||
write_unlock_irq(&hp_sdc.hook_lock);
|
write_unlock_irq(&hp_sdc.hook_lock);
|
||||||
|
@ -672,9 +725,8 @@ int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hp_sdc_release_timer_irq(hp_sdc_irqhook *callback) {
|
int hp_sdc_release_timer_irq(hp_sdc_irqhook *callback)
|
||||||
|
{
|
||||||
|
|
||||||
write_lock_irq(&hp_sdc.hook_lock);
|
write_lock_irq(&hp_sdc.hook_lock);
|
||||||
if ((callback != hp_sdc.timer) ||
|
if ((callback != hp_sdc.timer) ||
|
||||||
(hp_sdc.timer == NULL)) {
|
(hp_sdc.timer == NULL)) {
|
||||||
|
@ -694,8 +746,8 @@ int hp_sdc_release_timer_irq(hp_sdc_irqhook *callback) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hp_sdc_release_hil_irq(hp_sdc_irqhook *callback) {
|
int hp_sdc_release_hil_irq(hp_sdc_irqhook *callback)
|
||||||
|
{
|
||||||
write_lock_irq(&hp_sdc.hook_lock);
|
write_lock_irq(&hp_sdc.hook_lock);
|
||||||
if ((callback != hp_sdc.hil) ||
|
if ((callback != hp_sdc.hil) ||
|
||||||
(hp_sdc.hil == NULL)) {
|
(hp_sdc.hil == NULL)) {
|
||||||
|
@ -715,8 +767,8 @@ int hp_sdc_release_hil_irq(hp_sdc_irqhook *callback) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback) {
|
int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback)
|
||||||
|
{
|
||||||
write_lock_irq(&hp_sdc.hook_lock);
|
write_lock_irq(&hp_sdc.hook_lock);
|
||||||
if ((callback != hp_sdc.cooked) ||
|
if ((callback != hp_sdc.cooked) ||
|
||||||
(hp_sdc.cooked == NULL)) {
|
(hp_sdc.cooked == NULL)) {
|
||||||
|
@ -738,7 +790,8 @@ int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback) {
|
||||||
|
|
||||||
/************************* Keepalive timer task *********************/
|
/************************* Keepalive timer task *********************/
|
||||||
|
|
||||||
void hp_sdc_kicker (unsigned long data) {
|
void hp_sdc_kicker (unsigned long data)
|
||||||
|
{
|
||||||
tasklet_schedule(&hp_sdc.task);
|
tasklet_schedule(&hp_sdc.task);
|
||||||
/* Re-insert the periodic task. */
|
/* Re-insert the periodic task. */
|
||||||
mod_timer(&hp_sdc.kicker, jiffies + HZ);
|
mod_timer(&hp_sdc.kicker, jiffies + HZ);
|
||||||
|
@ -748,7 +801,7 @@ void hp_sdc_kicker (unsigned long data) {
|
||||||
|
|
||||||
#if defined(__hppa__)
|
#if defined(__hppa__)
|
||||||
|
|
||||||
static struct parisc_device_id hp_sdc_tbl[] = {
|
static const struct parisc_device_id hp_sdc_tbl[] = {
|
||||||
{
|
{
|
||||||
.hw_type = HPHW_FIO,
|
.hw_type = HPHW_FIO,
|
||||||
.hversion_rev = HVERSION_REV_ANY_ID,
|
.hversion_rev = HVERSION_REV_ANY_ID,
|
||||||
|
@ -772,7 +825,6 @@ static struct parisc_driver hp_sdc_driver = {
|
||||||
|
|
||||||
static int __init hp_sdc_init(void)
|
static int __init hp_sdc_init(void)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
char *errstr;
|
char *errstr;
|
||||||
hp_sdc_transaction t_sync;
|
hp_sdc_transaction t_sync;
|
||||||
uint8_t ts_sync[6];
|
uint8_t ts_sync[6];
|
||||||
|
@ -796,7 +848,8 @@ static int __init hp_sdc_init(void)
|
||||||
hp_sdc.r7[3] = 0xff;
|
hp_sdc.r7[3] = 0xff;
|
||||||
hp_sdc.ibf = 1;
|
hp_sdc.ibf = 1;
|
||||||
|
|
||||||
for (i = 0; i < HP_SDC_QUEUE_LEN; i++) hp_sdc.tq[i] = NULL;
|
memset(&hp_sdc.tq, 0, sizeof(hp_sdc.tq));
|
||||||
|
|
||||||
hp_sdc.wcurr = -1;
|
hp_sdc.wcurr = -1;
|
||||||
hp_sdc.rcurr = -1;
|
hp_sdc.rcurr = -1;
|
||||||
hp_sdc.rqty = 0;
|
hp_sdc.rqty = 0;
|
||||||
|
@ -804,25 +857,30 @@ static int __init hp_sdc_init(void)
|
||||||
hp_sdc.dev_err = -ENODEV;
|
hp_sdc.dev_err = -ENODEV;
|
||||||
|
|
||||||
errstr = "IO not found for";
|
errstr = "IO not found for";
|
||||||
if (!hp_sdc.base_io) goto err0;
|
if (!hp_sdc.base_io)
|
||||||
|
goto err0;
|
||||||
|
|
||||||
errstr = "IRQ not found for";
|
errstr = "IRQ not found for";
|
||||||
if (!hp_sdc.irq) goto err0;
|
if (!hp_sdc.irq)
|
||||||
|
goto err0;
|
||||||
|
|
||||||
hp_sdc.dev_err = -EBUSY;
|
hp_sdc.dev_err = -EBUSY;
|
||||||
|
|
||||||
#if defined(__hppa__)
|
#if defined(__hppa__)
|
||||||
errstr = "IO not available for";
|
errstr = "IO not available for";
|
||||||
if (request_region(hp_sdc.data_io, 2, hp_sdc_driver.name)) goto err0;
|
if (request_region(hp_sdc.data_io, 2, hp_sdc_driver.name))
|
||||||
|
goto err0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
errstr = "IRQ not available for";
|
errstr = "IRQ not available for";
|
||||||
if(request_irq(hp_sdc.irq, &hp_sdc_isr, 0, "HP SDC",
|
if (request_irq(hp_sdc.irq, &hp_sdc_isr, IRQF_SHARED|IRQF_SAMPLE_RANDOM,
|
||||||
(void *) hp_sdc.base_io)) goto err1;
|
"HP SDC", &hp_sdc))
|
||||||
|
goto err1;
|
||||||
|
|
||||||
errstr = "NMI not available for";
|
errstr = "NMI not available for";
|
||||||
if (request_irq(hp_sdc.nmi, &hp_sdc_nmisr, 0, "HP SDC NMI",
|
if (request_irq(hp_sdc.nmi, &hp_sdc_nmisr, IRQF_SHARED,
|
||||||
(void *) hp_sdc.base_io)) goto err2;
|
"HP SDC NMI", &hp_sdc))
|
||||||
|
goto err2;
|
||||||
|
|
||||||
printk(KERN_INFO PREFIX "HP SDC at 0x%p, IRQ %d (NMI IRQ %d)\n",
|
printk(KERN_INFO PREFIX "HP SDC at 0x%p, IRQ %d (NMI IRQ %d)\n",
|
||||||
(void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi);
|
(void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi);
|
||||||
|
@ -854,13 +912,14 @@ static int __init hp_sdc_init(void)
|
||||||
hp_sdc.dev_err = 0;
|
hp_sdc.dev_err = 0;
|
||||||
return 0;
|
return 0;
|
||||||
err2:
|
err2:
|
||||||
free_irq(hp_sdc.irq, NULL);
|
free_irq(hp_sdc.irq, &hp_sdc);
|
||||||
err1:
|
err1:
|
||||||
release_region(hp_sdc.data_io, 2);
|
release_region(hp_sdc.data_io, 2);
|
||||||
err0:
|
err0:
|
||||||
printk(KERN_WARNING PREFIX ": %s SDC IO=0x%p IRQ=0x%x NMI=0x%x\n",
|
printk(KERN_WARNING PREFIX ": %s SDC IO=0x%p IRQ=0x%x NMI=0x%x\n",
|
||||||
errstr, (void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi);
|
errstr, (void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi);
|
||||||
hp_sdc.dev = NULL;
|
hp_sdc.dev = NULL;
|
||||||
|
|
||||||
return hp_sdc.dev_err;
|
return hp_sdc.dev_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -868,8 +927,10 @@ static int __init hp_sdc_init(void)
|
||||||
|
|
||||||
static int __init hp_sdc_init_hppa(struct parisc_device *d)
|
static int __init hp_sdc_init_hppa(struct parisc_device *d)
|
||||||
{
|
{
|
||||||
if (!d) return 1;
|
if (!d)
|
||||||
if (hp_sdc.dev != NULL) return 1; /* We only expect one SDC */
|
return 1;
|
||||||
|
if (hp_sdc.dev != NULL)
|
||||||
|
return 1; /* We only expect one SDC */
|
||||||
|
|
||||||
hp_sdc.dev = d;
|
hp_sdc.dev = d;
|
||||||
hp_sdc.irq = d->irq;
|
hp_sdc.irq = d->irq;
|
||||||
|
@ -898,16 +959,14 @@ static void hp_sdc_exit(void)
|
||||||
/* Wait until we know this has been processed by the i8042 */
|
/* Wait until we know this has been processed by the i8042 */
|
||||||
hp_sdc_spin_ibf();
|
hp_sdc_spin_ibf();
|
||||||
|
|
||||||
free_irq(hp_sdc.nmi, NULL);
|
free_irq(hp_sdc.nmi, &hp_sdc);
|
||||||
free_irq(hp_sdc.irq, NULL);
|
free_irq(hp_sdc.irq, &hp_sdc);
|
||||||
write_unlock_irq(&hp_sdc.lock);
|
write_unlock_irq(&hp_sdc.lock);
|
||||||
|
|
||||||
del_timer(&hp_sdc.kicker);
|
del_timer(&hp_sdc.kicker);
|
||||||
|
|
||||||
tasklet_kill(&hp_sdc.task);
|
tasklet_kill(&hp_sdc.task);
|
||||||
|
|
||||||
/* release_region(hp_sdc.data_io, 2); */
|
|
||||||
|
|
||||||
#if defined(__hppa__)
|
#if defined(__hppa__)
|
||||||
if (unregister_parisc_driver(&hp_sdc_driver))
|
if (unregister_parisc_driver(&hp_sdc_driver))
|
||||||
printk(KERN_WARNING PREFIX "Error unregistering HP SDC");
|
printk(KERN_WARNING PREFIX "Error unregistering HP SDC");
|
||||||
|
@ -979,7 +1038,7 @@ static int __init hp_sdc_register(void)
|
||||||
}
|
}
|
||||||
hp_sdc.r11 = tq_init_seq[4];
|
hp_sdc.r11 = tq_init_seq[4];
|
||||||
if (hp_sdc.r11 & HP_SDC_CFG_NEW) {
|
if (hp_sdc.r11 & HP_SDC_CFG_NEW) {
|
||||||
char *str;
|
const char *str;
|
||||||
printk(KERN_INFO PREFIX "New style SDC\n");
|
printk(KERN_INFO PREFIX "New style SDC\n");
|
||||||
tq_init_seq[1] = HP_SDC_CMD_READ_XTD;
|
tq_init_seq[1] = HP_SDC_CMD_READ_XTD;
|
||||||
tq_init.actidx = 0;
|
tq_init.actidx = 0;
|
||||||
|
@ -995,12 +1054,10 @@ static int __init hp_sdc_register(void)
|
||||||
hp_sdc.r7e = tq_init_seq[4];
|
hp_sdc.r7e = tq_init_seq[4];
|
||||||
HP_SDC_XTD_REV_STRINGS(hp_sdc.r7e & HP_SDC_XTD_REV, str)
|
HP_SDC_XTD_REV_STRINGS(hp_sdc.r7e & HP_SDC_XTD_REV, str)
|
||||||
printk(KERN_INFO PREFIX "Revision: %s\n", str);
|
printk(KERN_INFO PREFIX "Revision: %s\n", str);
|
||||||
if (hp_sdc.r7e & HP_SDC_XTD_BEEPER) {
|
if (hp_sdc.r7e & HP_SDC_XTD_BEEPER)
|
||||||
printk(KERN_INFO PREFIX "TI SN76494 beeper present\n");
|
printk(KERN_INFO PREFIX "TI SN76494 beeper present\n");
|
||||||
}
|
if (hp_sdc.r7e & HP_SDC_XTD_BBRTC)
|
||||||
if (hp_sdc.r7e & HP_SDC_XTD_BBRTC) {
|
|
||||||
printk(KERN_INFO PREFIX "OKI MSM-58321 BBRTC present\n");
|
printk(KERN_INFO PREFIX "OKI MSM-58321 BBRTC present\n");
|
||||||
}
|
|
||||||
printk(KERN_INFO PREFIX "Spunking the self test register to force PUP "
|
printk(KERN_INFO PREFIX "Spunking the self test register to force PUP "
|
||||||
"on next firmware reset.\n");
|
"on next firmware reset.\n");
|
||||||
tq_init_seq[0] = HP_SDC_ACT_PRECMD |
|
tq_init_seq[0] = HP_SDC_ACT_PRECMD |
|
||||||
|
@ -1015,11 +1072,9 @@ static int __init hp_sdc_register(void)
|
||||||
hp_sdc_enqueue_transaction(&tq_init);
|
hp_sdc_enqueue_transaction(&tq_init);
|
||||||
down(&tq_init_sem);
|
down(&tq_init_sem);
|
||||||
up(&tq_init_sem);
|
up(&tq_init_sem);
|
||||||
}
|
} else
|
||||||
else {
|
|
||||||
printk(KERN_INFO PREFIX "Old style SDC (1820-%s).\n",
|
printk(KERN_INFO PREFIX "Old style SDC (1820-%s).\n",
|
||||||
(hp_sdc.r11 & HP_SDC_CFG_REV) ? "3300" : "2564/3087");
|
(hp_sdc.r11 & HP_SDC_CFG_REV) ? "3300" : "2564/3087");
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,11 +59,12 @@ struct hp_sdc_mlc_priv_s {
|
||||||
|
|
||||||
/************************* Interrupt context ******************************/
|
/************************* Interrupt context ******************************/
|
||||||
static void hp_sdc_mlc_isr (int irq, void *dev_id,
|
static void hp_sdc_mlc_isr (int irq, void *dev_id,
|
||||||
uint8_t status, uint8_t data) {
|
uint8_t status, uint8_t data)
|
||||||
|
{
|
||||||
int idx;
|
int idx;
|
||||||
hil_mlc *mlc = &hp_sdc_mlc;
|
hil_mlc *mlc = &hp_sdc_mlc;
|
||||||
|
|
||||||
write_lock(&(mlc->lock));
|
write_lock(&mlc->lock);
|
||||||
if (mlc->icount < 0) {
|
if (mlc->icount < 0) {
|
||||||
printk(KERN_WARNING PREFIX "HIL Overflow!\n");
|
printk(KERN_WARNING PREFIX "HIL Overflow!\n");
|
||||||
up(&mlc->isem);
|
up(&mlc->isem);
|
||||||
|
@ -73,18 +74,19 @@ static void hp_sdc_mlc_isr (int irq, void *dev_id,
|
||||||
if ((status & HP_SDC_STATUS_IRQMASK) == HP_SDC_STATUS_HILDATA) {
|
if ((status & HP_SDC_STATUS_IRQMASK) == HP_SDC_STATUS_HILDATA) {
|
||||||
mlc->ipacket[idx] |= data | HIL_ERR_INT;
|
mlc->ipacket[idx] |= data | HIL_ERR_INT;
|
||||||
mlc->icount--;
|
mlc->icount--;
|
||||||
if (hp_sdc_mlc_priv.got5x) goto check;
|
if (hp_sdc_mlc_priv.got5x || !idx)
|
||||||
if (!idx) goto check;
|
goto check;
|
||||||
if ((mlc->ipacket[idx-1] & HIL_PKT_ADDR_MASK) !=
|
if ((mlc->ipacket[idx - 1] & HIL_PKT_ADDR_MASK) !=
|
||||||
(mlc->ipacket[idx] & HIL_PKT_ADDR_MASK)) {
|
(mlc->ipacket[idx] & HIL_PKT_ADDR_MASK)) {
|
||||||
mlc->ipacket[idx] &= ~HIL_PKT_ADDR_MASK;
|
mlc->ipacket[idx] &= ~HIL_PKT_ADDR_MASK;
|
||||||
mlc->ipacket[idx] |= (mlc->ipacket[idx-1]
|
mlc->ipacket[idx] |= (mlc->ipacket[idx - 1]
|
||||||
& HIL_PKT_ADDR_MASK);
|
& HIL_PKT_ADDR_MASK);
|
||||||
}
|
}
|
||||||
goto check;
|
goto check;
|
||||||
}
|
}
|
||||||
/* We know status is 5X */
|
/* We know status is 5X */
|
||||||
if (data & HP_SDC_HIL_ISERR) goto err;
|
if (data & HP_SDC_HIL_ISERR)
|
||||||
|
goto err;
|
||||||
mlc->ipacket[idx] =
|
mlc->ipacket[idx] =
|
||||||
(data & HP_SDC_HIL_R1MASK) << HIL_PKT_ADDR_SHIFT;
|
(data & HP_SDC_HIL_R1MASK) << HIL_PKT_ADDR_SHIFT;
|
||||||
hp_sdc_mlc_priv.got5x = 1;
|
hp_sdc_mlc_priv.got5x = 1;
|
||||||
|
@ -92,54 +94,61 @@ static void hp_sdc_mlc_isr (int irq, void *dev_id,
|
||||||
|
|
||||||
check:
|
check:
|
||||||
hp_sdc_mlc_priv.got5x = 0;
|
hp_sdc_mlc_priv.got5x = 0;
|
||||||
if (mlc->imatch == 0) goto done;
|
if (mlc->imatch == 0)
|
||||||
|
goto done;
|
||||||
if ((mlc->imatch == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
|
if ((mlc->imatch == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
|
||||||
&& (mlc->ipacket[idx] == (mlc->imatch | idx))) goto done;
|
&& (mlc->ipacket[idx] == (mlc->imatch | idx)))
|
||||||
if (mlc->ipacket[idx] == mlc->imatch) goto done;
|
goto done;
|
||||||
|
if (mlc->ipacket[idx] == mlc->imatch)
|
||||||
|
goto done;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
printk(KERN_DEBUG PREFIX "err code %x\n", data);
|
printk(KERN_DEBUG PREFIX "err code %x\n", data);
|
||||||
|
|
||||||
switch (data) {
|
switch (data) {
|
||||||
case HP_SDC_HIL_RC_DONE:
|
case HP_SDC_HIL_RC_DONE:
|
||||||
printk(KERN_WARNING PREFIX "Bastard SDC reconfigured loop!\n");
|
printk(KERN_WARNING PREFIX "Bastard SDC reconfigured loop!\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HP_SDC_HIL_ERR:
|
case HP_SDC_HIL_ERR:
|
||||||
mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_PERR |
|
mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_PERR |
|
||||||
HIL_ERR_FERR | HIL_ERR_FOF;
|
HIL_ERR_FERR | HIL_ERR_FOF;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HP_SDC_HIL_TO:
|
case HP_SDC_HIL_TO:
|
||||||
mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_LERR;
|
mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_LERR;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HP_SDC_HIL_RC:
|
case HP_SDC_HIL_RC:
|
||||||
printk(KERN_WARNING PREFIX "Bastard SDC decided to reconfigure loop!\n");
|
printk(KERN_WARNING PREFIX "Bastard SDC decided to reconfigure loop!\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printk(KERN_WARNING PREFIX "Unkown HIL Error status (%x)!\n", data);
|
printk(KERN_WARNING PREFIX "Unkown HIL Error status (%x)!\n", data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No more data will be coming due to an error. */
|
/* No more data will be coming due to an error. */
|
||||||
done:
|
done:
|
||||||
tasklet_schedule(mlc->tasklet);
|
tasklet_schedule(mlc->tasklet);
|
||||||
up(&(mlc->isem));
|
up(&mlc->isem);
|
||||||
out:
|
out:
|
||||||
write_unlock(&(mlc->lock));
|
write_unlock(&mlc->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************** Tasklet or userspace context functions ****************/
|
/******************** Tasklet or userspace context functions ****************/
|
||||||
|
|
||||||
static int hp_sdc_mlc_in (hil_mlc *mlc, suseconds_t timeout) {
|
static int hp_sdc_mlc_in(hil_mlc *mlc, suseconds_t timeout)
|
||||||
unsigned long flags;
|
{
|
||||||
struct hp_sdc_mlc_priv_s *priv;
|
struct hp_sdc_mlc_priv_s *priv;
|
||||||
int rc = 2;
|
int rc = 2;
|
||||||
|
|
||||||
priv = mlc->priv;
|
priv = mlc->priv;
|
||||||
|
|
||||||
write_lock_irqsave(&(mlc->lock), flags);
|
|
||||||
|
|
||||||
/* Try to down the semaphore */
|
/* Try to down the semaphore */
|
||||||
if (down_trylock(&(mlc->isem))) {
|
if (down_trylock(&mlc->isem)) {
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
if (priv->emtestmode) {
|
if (priv->emtestmode) {
|
||||||
mlc->ipacket[0] =
|
mlc->ipacket[0] =
|
||||||
|
@ -152,55 +161,49 @@ static int hp_sdc_mlc_in (hil_mlc *mlc, suseconds_t timeout) {
|
||||||
goto wasup;
|
goto wasup;
|
||||||
}
|
}
|
||||||
do_gettimeofday(&tv);
|
do_gettimeofday(&tv);
|
||||||
tv.tv_usec += 1000000 * (tv.tv_sec - mlc->instart.tv_sec);
|
tv.tv_usec += USEC_PER_SEC * (tv.tv_sec - mlc->instart.tv_sec);
|
||||||
if (tv.tv_usec - mlc->instart.tv_usec > mlc->intimeout) {
|
if (tv.tv_usec - mlc->instart.tv_usec > mlc->intimeout) {
|
||||||
/* printk("!%i %i",
|
/* printk("!%i %i",
|
||||||
tv.tv_usec - mlc->instart.tv_usec,
|
tv.tv_usec - mlc->instart.tv_usec,
|
||||||
mlc->intimeout);
|
mlc->intimeout);
|
||||||
*/
|
*/
|
||||||
rc = 1;
|
rc = 1;
|
||||||
up(&(mlc->isem));
|
up(&mlc->isem);
|
||||||
}
|
}
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
wasup:
|
wasup:
|
||||||
up(&(mlc->isem));
|
up(&mlc->isem);
|
||||||
rc = 0;
|
rc = 0;
|
||||||
goto done;
|
|
||||||
done:
|
done:
|
||||||
write_unlock_irqrestore(&(mlc->lock), flags);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hp_sdc_mlc_cts (hil_mlc *mlc) {
|
static int hp_sdc_mlc_cts(hil_mlc *mlc)
|
||||||
|
{
|
||||||
struct hp_sdc_mlc_priv_s *priv;
|
struct hp_sdc_mlc_priv_s *priv;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
priv = mlc->priv;
|
priv = mlc->priv;
|
||||||
|
|
||||||
write_lock_irqsave(&(mlc->lock), flags);
|
|
||||||
|
|
||||||
/* Try to down the semaphores -- they should be up. */
|
/* Try to down the semaphores -- they should be up. */
|
||||||
if (down_trylock(&(mlc->isem))) {
|
BUG_ON(down_trylock(&mlc->isem));
|
||||||
BUG();
|
BUG_ON(down_trylock(&mlc->osem));
|
||||||
goto busy;
|
|
||||||
}
|
|
||||||
if (down_trylock(&(mlc->osem))) {
|
|
||||||
BUG();
|
|
||||||
up(&(mlc->isem));
|
|
||||||
goto busy;
|
|
||||||
}
|
|
||||||
up(&(mlc->isem));
|
|
||||||
up(&(mlc->osem));
|
|
||||||
|
|
||||||
if (down_trylock(&(mlc->csem))) {
|
up(&mlc->isem);
|
||||||
if (priv->trans.act.semaphore != &(mlc->csem)) goto poll;
|
up(&mlc->osem);
|
||||||
|
|
||||||
|
if (down_trylock(&mlc->csem)) {
|
||||||
|
if (priv->trans.act.semaphore != &mlc->csem)
|
||||||
|
goto poll;
|
||||||
|
else
|
||||||
goto busy;
|
goto busy;
|
||||||
}
|
}
|
||||||
if (!(priv->tseq[4] & HP_SDC_USE_LOOP)) goto done;
|
|
||||||
|
if (!(priv->tseq[4] & HP_SDC_USE_LOOP))
|
||||||
|
goto done;
|
||||||
|
|
||||||
poll:
|
poll:
|
||||||
priv->trans.act.semaphore = &(mlc->csem);
|
priv->trans.act.semaphore = &mlc->csem;
|
||||||
priv->trans.actidx = 0;
|
priv->trans.actidx = 0;
|
||||||
priv->trans.idx = 1;
|
priv->trans.idx = 1;
|
||||||
priv->trans.endidx = 5;
|
priv->trans.endidx = 5;
|
||||||
|
@ -210,48 +213,39 @@ static int hp_sdc_mlc_cts (hil_mlc *mlc) {
|
||||||
priv->tseq[2] = 1;
|
priv->tseq[2] = 1;
|
||||||
priv->tseq[3] = 0;
|
priv->tseq[3] = 0;
|
||||||
priv->tseq[4] = 0;
|
priv->tseq[4] = 0;
|
||||||
hp_sdc_enqueue_transaction(&(priv->trans));
|
__hp_sdc_enqueue_transaction(&priv->trans);
|
||||||
busy:
|
busy:
|
||||||
write_unlock_irqrestore(&(mlc->lock), flags);
|
|
||||||
return 1;
|
return 1;
|
||||||
done:
|
done:
|
||||||
priv->trans.act.semaphore = &(mlc->osem);
|
priv->trans.act.semaphore = &mlc->osem;
|
||||||
up(&(mlc->csem));
|
up(&mlc->csem);
|
||||||
write_unlock_irqrestore(&(mlc->lock), flags);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hp_sdc_mlc_out (hil_mlc *mlc) {
|
static void hp_sdc_mlc_out(hil_mlc *mlc)
|
||||||
|
{
|
||||||
struct hp_sdc_mlc_priv_s *priv;
|
struct hp_sdc_mlc_priv_s *priv;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
priv = mlc->priv;
|
priv = mlc->priv;
|
||||||
|
|
||||||
write_lock_irqsave(&(mlc->lock), flags);
|
|
||||||
|
|
||||||
/* Try to down the semaphore -- it should be up. */
|
/* Try to down the semaphore -- it should be up. */
|
||||||
if (down_trylock(&(mlc->osem))) {
|
BUG_ON(down_trylock(&mlc->osem));
|
||||||
BUG();
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mlc->opacket & HIL_DO_ALTER_CTRL) goto do_control;
|
if (mlc->opacket & HIL_DO_ALTER_CTRL)
|
||||||
|
goto do_control;
|
||||||
|
|
||||||
do_data:
|
do_data:
|
||||||
if (priv->emtestmode) {
|
if (priv->emtestmode) {
|
||||||
up(&(mlc->osem));
|
up(&mlc->osem);
|
||||||
goto done;
|
return;
|
||||||
}
|
}
|
||||||
/* Shouldn't be sending commands when loop may be busy */
|
/* Shouldn't be sending commands when loop may be busy */
|
||||||
if (down_trylock(&(mlc->csem))) {
|
BUG_ON(down_trylock(&mlc->csem));
|
||||||
BUG();
|
up(&mlc->csem);
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
up(&(mlc->csem));
|
|
||||||
|
|
||||||
priv->trans.actidx = 0;
|
priv->trans.actidx = 0;
|
||||||
priv->trans.idx = 1;
|
priv->trans.idx = 1;
|
||||||
priv->trans.act.semaphore = &(mlc->osem);
|
priv->trans.act.semaphore = &mlc->osem;
|
||||||
priv->trans.endidx = 6;
|
priv->trans.endidx = 6;
|
||||||
priv->tseq[0] =
|
priv->tseq[0] =
|
||||||
HP_SDC_ACT_DATAREG | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_SEMAPHORE;
|
HP_SDC_ACT_DATAREG | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_SEMAPHORE;
|
||||||
|
@ -264,7 +258,8 @@ static void hp_sdc_mlc_out (hil_mlc *mlc) {
|
||||||
(mlc->opacket & HIL_PKT_DATA_MASK)
|
(mlc->opacket & HIL_PKT_DATA_MASK)
|
||||||
>> HIL_PKT_DATA_SHIFT;
|
>> HIL_PKT_DATA_SHIFT;
|
||||||
priv->tseq[4] = 0; /* No timeout */
|
priv->tseq[4] = 0; /* No timeout */
|
||||||
if (priv->tseq[3] == HIL_CMD_DHR) priv->tseq[4] = 1;
|
if (priv->tseq[3] == HIL_CMD_DHR)
|
||||||
|
priv->tseq[4] = 1;
|
||||||
priv->tseq[5] = HP_SDC_CMD_DO_HIL;
|
priv->tseq[5] = HP_SDC_CMD_DO_HIL;
|
||||||
goto enqueue;
|
goto enqueue;
|
||||||
|
|
||||||
|
@ -274,11 +269,12 @@ static void hp_sdc_mlc_out (hil_mlc *mlc) {
|
||||||
/* we cannot emulate this, it should not be used. */
|
/* we cannot emulate this, it should not be used. */
|
||||||
BUG_ON((mlc->opacket & (HIL_CTRL_APE | HIL_CTRL_IPF)) == HIL_CTRL_APE);
|
BUG_ON((mlc->opacket & (HIL_CTRL_APE | HIL_CTRL_IPF)) == HIL_CTRL_APE);
|
||||||
|
|
||||||
if ((mlc->opacket & HIL_CTRL_ONLY) == HIL_CTRL_ONLY) goto control_only;
|
if ((mlc->opacket & HIL_CTRL_ONLY) == HIL_CTRL_ONLY)
|
||||||
if (mlc->opacket & HIL_CTRL_APE) {
|
goto control_only;
|
||||||
BUG(); /* Should not send command/data after engaging APE */
|
|
||||||
goto done;
|
/* Should not send command/data after engaging APE */
|
||||||
}
|
BUG_ON(mlc->opacket & HIL_CTRL_APE);
|
||||||
|
|
||||||
/* Disengaging APE this way would not be valid either since
|
/* Disengaging APE this way would not be valid either since
|
||||||
* the loop must be allowed to idle.
|
* the loop must be allowed to idle.
|
||||||
*
|
*
|
||||||
|
@ -290,22 +286,20 @@ static void hp_sdc_mlc_out (hil_mlc *mlc) {
|
||||||
control_only:
|
control_only:
|
||||||
priv->trans.actidx = 0;
|
priv->trans.actidx = 0;
|
||||||
priv->trans.idx = 1;
|
priv->trans.idx = 1;
|
||||||
priv->trans.act.semaphore = &(mlc->osem);
|
priv->trans.act.semaphore = &mlc->osem;
|
||||||
priv->trans.endidx = 4;
|
priv->trans.endidx = 4;
|
||||||
priv->tseq[0] =
|
priv->tseq[0] =
|
||||||
HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE;
|
HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE;
|
||||||
priv->tseq[1] = HP_SDC_CMD_SET_LPC;
|
priv->tseq[1] = HP_SDC_CMD_SET_LPC;
|
||||||
priv->tseq[2] = 1;
|
priv->tseq[2] = 1;
|
||||||
// priv->tseq[3] = (mlc->ddc + 1) | HP_SDC_LPS_ACSUCC;
|
/* priv->tseq[3] = (mlc->ddc + 1) | HP_SDC_LPS_ACSUCC; */
|
||||||
priv->tseq[3] = 0;
|
priv->tseq[3] = 0;
|
||||||
if (mlc->opacket & HIL_CTRL_APE) {
|
if (mlc->opacket & HIL_CTRL_APE) {
|
||||||
priv->tseq[3] |= HP_SDC_LPC_APE_IPF;
|
priv->tseq[3] |= HP_SDC_LPC_APE_IPF;
|
||||||
down_trylock(&(mlc->csem));
|
down_trylock(&mlc->csem);
|
||||||
}
|
}
|
||||||
enqueue:
|
enqueue:
|
||||||
hp_sdc_enqueue_transaction(&(priv->trans));
|
hp_sdc_enqueue_transaction(&priv->trans);
|
||||||
done:
|
|
||||||
write_unlock_irqrestore(&(mlc->lock), flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init hp_sdc_mlc_init(void)
|
static int __init hp_sdc_mlc_init(void)
|
||||||
|
@ -316,18 +310,18 @@ static int __init hp_sdc_mlc_init(void)
|
||||||
|
|
||||||
hp_sdc_mlc_priv.emtestmode = 0;
|
hp_sdc_mlc_priv.emtestmode = 0;
|
||||||
hp_sdc_mlc_priv.trans.seq = hp_sdc_mlc_priv.tseq;
|
hp_sdc_mlc_priv.trans.seq = hp_sdc_mlc_priv.tseq;
|
||||||
hp_sdc_mlc_priv.trans.act.semaphore = &(mlc->osem);
|
hp_sdc_mlc_priv.trans.act.semaphore = &mlc->osem;
|
||||||
hp_sdc_mlc_priv.got5x = 0;
|
hp_sdc_mlc_priv.got5x = 0;
|
||||||
|
|
||||||
mlc->cts = &hp_sdc_mlc_cts;
|
mlc->cts = &hp_sdc_mlc_cts;
|
||||||
mlc->in = &hp_sdc_mlc_in;
|
mlc->in = &hp_sdc_mlc_in;
|
||||||
mlc->out = &hp_sdc_mlc_out;
|
mlc->out = &hp_sdc_mlc_out;
|
||||||
|
mlc->priv = &hp_sdc_mlc_priv;
|
||||||
|
|
||||||
if (hil_mlc_register(mlc)) {
|
if (hil_mlc_register(mlc)) {
|
||||||
printk(KERN_WARNING PREFIX "Failed to register MLC structure with hil_mlc\n");
|
printk(KERN_WARNING PREFIX "Failed to register MLC structure with hil_mlc\n");
|
||||||
goto err0;
|
goto err0;
|
||||||
}
|
}
|
||||||
mlc->priv = &hp_sdc_mlc_priv;
|
|
||||||
|
|
||||||
if (hp_sdc_request_hil_irq(&hp_sdc_mlc_isr)) {
|
if (hp_sdc_request_hil_irq(&hp_sdc_mlc_isr)) {
|
||||||
printk(KERN_WARNING PREFIX "Request for raw HIL ISR hook denied\n");
|
printk(KERN_WARNING PREFIX "Request for raw HIL ISR hook denied\n");
|
||||||
|
@ -335,10 +329,9 @@ static int __init hp_sdc_mlc_init(void)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
err1:
|
err1:
|
||||||
if (hil_mlc_unregister(mlc)) {
|
if (hil_mlc_unregister(mlc))
|
||||||
printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
|
printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
|
||||||
"This is bad. Could cause an oops.\n");
|
"This is bad. Could cause an oops.\n");
|
||||||
}
|
|
||||||
err0:
|
err0:
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
@ -346,14 +339,14 @@ static int __init hp_sdc_mlc_init(void)
|
||||||
static void __exit hp_sdc_mlc_exit(void)
|
static void __exit hp_sdc_mlc_exit(void)
|
||||||
{
|
{
|
||||||
hil_mlc *mlc = &hp_sdc_mlc;
|
hil_mlc *mlc = &hp_sdc_mlc;
|
||||||
if (hp_sdc_release_hil_irq(&hp_sdc_mlc_isr)) {
|
|
||||||
|
if (hp_sdc_release_hil_irq(&hp_sdc_mlc_isr))
|
||||||
printk(KERN_ERR PREFIX "Failed to release the raw HIL ISR hook.\n"
|
printk(KERN_ERR PREFIX "Failed to release the raw HIL ISR hook.\n"
|
||||||
"This is bad. Could cause an oops.\n");
|
"This is bad. Could cause an oops.\n");
|
||||||
}
|
|
||||||
if (hil_mlc_unregister(mlc)) {
|
if (hil_mlc_unregister(mlc))
|
||||||
printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
|
printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
|
||||||
"This is bad. Could cause an oops.\n");
|
"This is bad. Could cause an oops.\n");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(hp_sdc_mlc_init);
|
module_init(hp_sdc_mlc_init);
|
||||||
|
|
|
@ -159,6 +159,28 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
|
||||||
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E4010"),
|
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E4010"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* No data is coming from the touchscreen unless KBC
|
||||||
|
* is in legacy mode.
|
||||||
|
*/
|
||||||
|
.ident = "Panasonic CF-29",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Errors on MUX ports are reported without raising AUXDATA
|
||||||
|
* causing "spurious NAK" messages.
|
||||||
|
*/
|
||||||
|
.ident = "HP Pavilion DV4017EA",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EA032EA#ABF)"),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.ident = "Toshiba P10",
|
.ident = "Toshiba P10",
|
||||||
.matches = {
|
.matches = {
|
||||||
|
@ -280,6 +302,8 @@ static struct pnp_driver i8042_pnp_kbd_driver = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct pnp_device_id pnp_aux_devids[] = {
|
static struct pnp_device_id pnp_aux_devids[] = {
|
||||||
|
{ .id = "FJC6000", .driver_data = 0 },
|
||||||
|
{ .id = "FJC6001", .driver_data = 0 },
|
||||||
{ .id = "PNP0f03", .driver_data = 0 },
|
{ .id = "PNP0f03", .driver_data = 0 },
|
||||||
{ .id = "PNP0f0b", .driver_data = 0 },
|
{ .id = "PNP0f0b", .driver_data = 0 },
|
||||||
{ .id = "PNP0f0e", .driver_data = 0 },
|
{ .id = "PNP0f0e", .driver_data = 0 },
|
||||||
|
|
|
@ -767,6 +767,13 @@ static void i8042_controller_reset(void)
|
||||||
{
|
{
|
||||||
i8042_flush();
|
i8042_flush();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable both KBD and AUX interfaces so they don't get in the way
|
||||||
|
*/
|
||||||
|
|
||||||
|
i8042_ctr |= I8042_CTR_KBDDIS | I8042_CTR_AUXDIS;
|
||||||
|
i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Disable MUX mode if present.
|
* Disable MUX mode if present.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -39,7 +39,8 @@
|
||||||
/*
|
/*
|
||||||
* This code has been heavily tested on a Nokia 770, and lightly
|
* This code has been heavily tested on a Nokia 770, and lightly
|
||||||
* tested on other ads7846 devices (OSK/Mistral, Lubbock).
|
* tested on other ads7846 devices (OSK/Mistral, Lubbock).
|
||||||
* Support for ads7843 and ads7845 has only been stubbed in.
|
* Support for ads7843 tested on Atmel at91sam926x-EK.
|
||||||
|
* Support for ads7845 has only been stubbed in.
|
||||||
*
|
*
|
||||||
* IRQ handling needs a workaround because of a shortcoming in handling
|
* IRQ handling needs a workaround because of a shortcoming in handling
|
||||||
* edge triggered IRQs on some platforms like the OMAP1/2. These
|
* edge triggered IRQs on some platforms like the OMAP1/2. These
|
||||||
|
@ -246,9 +247,8 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
|
||||||
|
|
||||||
/* REVISIT: take a few more samples, and compare ... */
|
/* REVISIT: take a few more samples, and compare ... */
|
||||||
|
|
||||||
/* maybe off internal vREF */
|
/* converter in low power mode & enable PENIRQ */
|
||||||
if (use_internal) {
|
req->ref_off = PWRDOWN;
|
||||||
req->ref_off = REF_OFF;
|
|
||||||
req->xfer[4].tx_buf = &req->ref_off;
|
req->xfer[4].tx_buf = &req->ref_off;
|
||||||
req->xfer[4].len = 1;
|
req->xfer[4].len = 1;
|
||||||
spi_message_add_tail(&req->xfer[4], &req->msg);
|
spi_message_add_tail(&req->xfer[4], &req->msg);
|
||||||
|
@ -257,7 +257,6 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
|
||||||
req->xfer[5].len = 2;
|
req->xfer[5].len = 2;
|
||||||
CS_CHANGE(req->xfer[5]);
|
CS_CHANGE(req->xfer[5]);
|
||||||
spi_message_add_tail(&req->xfer[5], &req->msg);
|
spi_message_add_tail(&req->xfer[5], &req->msg);
|
||||||
}
|
|
||||||
|
|
||||||
ts->irq_disabled = 1;
|
ts->irq_disabled = 1;
|
||||||
disable_irq(spi->irq);
|
disable_irq(spi->irq);
|
||||||
|
@ -536,6 +535,9 @@ static void ads7846_rx(void *ads)
|
||||||
} else
|
} else
|
||||||
Rt = 0;
|
Rt = 0;
|
||||||
|
|
||||||
|
if (ts->model == 7843)
|
||||||
|
Rt = ts->pressure_max / 2;
|
||||||
|
|
||||||
/* Sample found inconsistent by debouncing or pressure is beyond
|
/* Sample found inconsistent by debouncing or pressure is beyond
|
||||||
* the maximum. Don't report it to user space, repeat at least
|
* the maximum. Don't report it to user space, repeat at least
|
||||||
* once more the measurement
|
* once more the measurement
|
||||||
|
@ -897,7 +899,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
|
||||||
|
|
||||||
input_dev->name = "ADS784x Touchscreen";
|
input_dev->name = "ADS784x Touchscreen";
|
||||||
input_dev->phys = ts->phys;
|
input_dev->phys = ts->phys;
|
||||||
input_dev->cdev.dev = &spi->dev;
|
input_dev->dev.parent = &spi->dev;
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -300,8 +300,7 @@ static int __init corgits_probe(struct platform_device *pdev)
|
||||||
input_dev->id.vendor = 0x0001;
|
input_dev->id.vendor = 0x0001;
|
||||||
input_dev->id.product = 0x0002;
|
input_dev->id.product = 0x0002;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &pdev->dev;
|
input_dev->dev.parent = &pdev->dev;
|
||||||
input_dev->private = corgi_ts;
|
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -312,14 +312,13 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
init_completion(&elo->cmd_done);
|
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->name = "Elo Serial TouchScreen";
|
input_dev->name = "Elo Serial TouchScreen";
|
||||||
input_dev->phys = elo->phys;
|
input_dev->phys = elo->phys;
|
||||||
input_dev->id.bustype = BUS_RS232;
|
input_dev->id.bustype = BUS_RS232;
|
||||||
input_dev->id.vendor = SERIO_ELO;
|
input_dev->id.vendor = SERIO_ELO;
|
||||||
input_dev->id.product = elo->id;
|
input_dev->id.product = elo->id;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &serio->dev;
|
input_dev->dev.parent = &serio->dev;
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -130,13 +130,13 @@ static int gunze_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
gunze->dev = input_dev;
|
gunze->dev = input_dev;
|
||||||
snprintf(gunze->phys, sizeof(serio->phys), "%s/input0", serio->phys);
|
snprintf(gunze->phys, sizeof(serio->phys), "%s/input0", serio->phys);
|
||||||
|
|
||||||
input_dev->private = gunze;
|
|
||||||
input_dev->name = "Gunze AHL-51S TouchScreen";
|
input_dev->name = "Gunze AHL-51S TouchScreen";
|
||||||
input_dev->phys = gunze->phys;
|
input_dev->phys = gunze->phys;
|
||||||
input_dev->id.bustype = BUS_RS232;
|
input_dev->id.bustype = BUS_RS232;
|
||||||
input_dev->id.vendor = SERIO_GUNZE;
|
input_dev->id.vendor = SERIO_GUNZE;
|
||||||
input_dev->id.product = 0x0051;
|
input_dev->id.product = 0x0051;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
|
input_dev->dev.parent = &serio->dev;
|
||||||
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);
|
||||||
input_set_abs_params(input_dev, ABS_X, 24, 1000, 0, 0);
|
input_set_abs_params(input_dev, ABS_X, 24, 1000, 0, 0);
|
||||||
|
|
|
@ -147,7 +147,7 @@ enum flite_pwr {
|
||||||
unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr)
|
unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr)
|
||||||
{
|
{
|
||||||
unsigned char brightness = (pwr == FLITE_PWR_OFF) ? 0 : flite_brightness;
|
unsigned char brightness = (pwr == FLITE_PWR_OFF) ? 0 : flite_brightness;
|
||||||
struct h3600_dev *ts = dev->private;
|
struct h3600_dev *ts = input_get_drvdata(dev);
|
||||||
|
|
||||||
/* Must be in this order */
|
/* Must be in this order */
|
||||||
ts->serio->write(ts->serio, 1);
|
ts->serio->write(ts->serio, 1);
|
||||||
|
@ -260,7 +260,7 @@ static int h3600ts_event(struct input_dev *dev, unsigned int type,
|
||||||
unsigned int code, int value)
|
unsigned int code, int value)
|
||||||
{
|
{
|
||||||
#if 0
|
#if 0
|
||||||
struct h3600_dev *ts = dev->private;
|
struct h3600_dev *ts = input_get_drvdata(dev);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case EV_LED: {
|
case EV_LED: {
|
||||||
|
@ -367,8 +367,9 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
input_dev->id.vendor = SERIO_H3600;
|
input_dev->id.vendor = SERIO_H3600;
|
||||||
input_dev->id.product = 0x0666; /* FIXME !!! We can ask the hardware */
|
input_dev->id.product = 0x0666; /* FIXME !!! We can ask the hardware */
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &serio->dev;
|
input_dev->dev.parent = &serio->dev;
|
||||||
input_dev->private = ts;
|
|
||||||
|
input_set_drvdata(input_dev, ts);
|
||||||
|
|
||||||
input_dev->event = h3600ts_event;
|
input_dev->event = h3600ts_event;
|
||||||
|
|
||||||
|
|
|
@ -144,13 +144,13 @@ static int mtouch_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
mtouch->dev = input_dev;
|
mtouch->dev = input_dev;
|
||||||
snprintf(mtouch->phys, sizeof(mtouch->phys), "%s/input0", serio->phys);
|
snprintf(mtouch->phys, sizeof(mtouch->phys), "%s/input0", serio->phys);
|
||||||
|
|
||||||
input_dev->private = mtouch;
|
|
||||||
input_dev->name = "MicroTouch Serial TouchScreen";
|
input_dev->name = "MicroTouch Serial TouchScreen";
|
||||||
input_dev->phys = mtouch->phys;
|
input_dev->phys = mtouch->phys;
|
||||||
input_dev->id.bustype = BUS_RS232;
|
input_dev->id.bustype = BUS_RS232;
|
||||||
input_dev->id.vendor = SERIO_MICROTOUCH;
|
input_dev->id.vendor = SERIO_MICROTOUCH;
|
||||||
input_dev->id.product = 0;
|
input_dev->id.product = 0;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
|
input_dev->dev.parent = &serio->dev;
|
||||||
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);
|
||||||
input_set_abs_params(mtouch->dev, ABS_X, MTOUCH_MIN_XC, MTOUCH_MAX_XC, 0, 0);
|
input_set_abs_params(mtouch->dev, ABS_X, MTOUCH_MIN_XC, MTOUCH_MAX_XC, 0, 0);
|
||||||
|
|
|
@ -105,14 +105,13 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
pm->dev = input_dev;
|
pm->dev = input_dev;
|
||||||
snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys);
|
snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys);
|
||||||
|
|
||||||
input_dev->private = pm;
|
|
||||||
input_dev->name = "Penmount Serial TouchScreen";
|
input_dev->name = "Penmount Serial TouchScreen";
|
||||||
input_dev->phys = pm->phys;
|
input_dev->phys = pm->phys;
|
||||||
input_dev->id.bustype = BUS_RS232;
|
input_dev->id.bustype = BUS_RS232;
|
||||||
input_dev->id.vendor = SERIO_PENMOUNT;
|
input_dev->id.vendor = SERIO_PENMOUNT;
|
||||||
input_dev->id.product = 0;
|
input_dev->id.product = 0;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
input_dev->cdev.dev = &serio->dev;
|
input_dev->dev.parent = &serio->dev;
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -118,13 +118,13 @@ static int tr_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
tr->dev = input_dev;
|
tr->dev = input_dev;
|
||||||
snprintf(tr->phys, sizeof(tr->phys), "%s/input0", serio->phys);
|
snprintf(tr->phys, sizeof(tr->phys), "%s/input0", serio->phys);
|
||||||
|
|
||||||
input_dev->private = tr;
|
|
||||||
input_dev->name = "Touchright Serial TouchScreen";
|
input_dev->name = "Touchright Serial TouchScreen";
|
||||||
input_dev->phys = tr->phys;
|
input_dev->phys = tr->phys;
|
||||||
input_dev->id.bustype = BUS_RS232;
|
input_dev->id.bustype = BUS_RS232;
|
||||||
input_dev->id.vendor = SERIO_TOUCHRIGHT;
|
input_dev->id.vendor = SERIO_TOUCHRIGHT;
|
||||||
input_dev->id.product = 0;
|
input_dev->id.product = 0;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
|
input_dev->dev.parent = &serio->dev;
|
||||||
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);
|
||||||
input_set_abs_params(tr->dev, ABS_X, TR_MIN_XC, TR_MAX_XC, 0, 0);
|
input_set_abs_params(tr->dev, ABS_X, TR_MIN_XC, TR_MAX_XC, 0, 0);
|
||||||
|
|
|
@ -125,13 +125,13 @@ static int tw_connect(struct serio *serio, struct serio_driver *drv)
|
||||||
tw->dev = input_dev;
|
tw->dev = input_dev;
|
||||||
snprintf(tw->phys, sizeof(tw->phys), "%s/input0", serio->phys);
|
snprintf(tw->phys, sizeof(tw->phys), "%s/input0", serio->phys);
|
||||||
|
|
||||||
input_dev->private = tw;
|
|
||||||
input_dev->name = "Touchwindow Serial TouchScreen";
|
input_dev->name = "Touchwindow Serial TouchScreen";
|
||||||
input_dev->phys = tw->phys;
|
input_dev->phys = tw->phys;
|
||||||
input_dev->id.bustype = BUS_RS232;
|
input_dev->id.bustype = BUS_RS232;
|
||||||
input_dev->id.vendor = SERIO_TOUCHWIN;
|
input_dev->id.vendor = SERIO_TOUCHWIN;
|
||||||
input_dev->id.product = 0;
|
input_dev->id.product = 0;
|
||||||
input_dev->id.version = 0x0100;
|
input_dev->id.version = 0x0100;
|
||||||
|
input_dev->dev.parent = &serio->dev;
|
||||||
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);
|
||||||
input_set_abs_params(tw->dev, ABS_X, TW_MIN_XC, TW_MAX_XC, 0, 0);
|
input_set_abs_params(tw->dev, ABS_X, TW_MIN_XC, TW_MAX_XC, 0, 0);
|
||||||
|
|
|
@ -97,6 +97,8 @@ struct ucb1400 {
|
||||||
};
|
};
|
||||||
|
|
||||||
static int adcsync;
|
static int adcsync;
|
||||||
|
static int ts_delay = 55; /* us */
|
||||||
|
static int ts_delay_pressure; /* us */
|
||||||
|
|
||||||
static inline u16 ucb1400_reg_read(struct ucb1400 *ucb, u16 reg)
|
static inline u16 ucb1400_reg_read(struct ucb1400 *ucb, u16 reg)
|
||||||
{
|
{
|
||||||
|
@ -159,6 +161,7 @@ static inline unsigned int ucb1400_ts_read_pressure(struct ucb1400 *ucb)
|
||||||
UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
|
UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
|
||||||
UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
|
UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
|
||||||
UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
|
UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
|
||||||
|
udelay(ts_delay_pressure);
|
||||||
return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPY);
|
return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,7 +183,7 @@ static inline unsigned int ucb1400_ts_read_xpos(struct ucb1400 *ucb)
|
||||||
UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
|
UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
|
||||||
UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
|
UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
|
||||||
|
|
||||||
udelay(55);
|
udelay(ts_delay);
|
||||||
|
|
||||||
return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPY);
|
return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPY);
|
||||||
}
|
}
|
||||||
|
@ -203,7 +206,7 @@ static inline unsigned int ucb1400_ts_read_ypos(struct ucb1400 *ucb)
|
||||||
UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
|
UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
|
||||||
UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
|
UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
|
||||||
|
|
||||||
udelay(55);
|
udelay(ts_delay);
|
||||||
|
|
||||||
return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPX);
|
return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPX);
|
||||||
}
|
}
|
||||||
|
@ -369,7 +372,7 @@ static irqreturn_t ucb1400_hard_irq(int irqnr, void *devid)
|
||||||
|
|
||||||
static int ucb1400_ts_open(struct input_dev *idev)
|
static int ucb1400_ts_open(struct input_dev *idev)
|
||||||
{
|
{
|
||||||
struct ucb1400 *ucb = idev->private;
|
struct ucb1400 *ucb = input_get_drvdata(idev);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
BUG_ON(ucb->ts_task);
|
BUG_ON(ucb->ts_task);
|
||||||
|
@ -385,7 +388,7 @@ static int ucb1400_ts_open(struct input_dev *idev)
|
||||||
|
|
||||||
static void ucb1400_ts_close(struct input_dev *idev)
|
static void ucb1400_ts_close(struct input_dev *idev)
|
||||||
{
|
{
|
||||||
struct ucb1400 *ucb = idev->private;
|
struct ucb1400 *ucb = input_get_drvdata(idev);
|
||||||
|
|
||||||
if (ucb->ts_task)
|
if (ucb->ts_task)
|
||||||
kthread_stop(ucb->ts_task);
|
kthread_stop(ucb->ts_task);
|
||||||
|
@ -507,8 +510,9 @@ static int ucb1400_ts_probe(struct device *dev)
|
||||||
}
|
}
|
||||||
printk(KERN_DEBUG "UCB1400: found IRQ %d\n", ucb->irq);
|
printk(KERN_DEBUG "UCB1400: found IRQ %d\n", ucb->irq);
|
||||||
|
|
||||||
idev->private = ucb;
|
input_set_drvdata(idev, ucb);
|
||||||
idev->cdev.dev = dev;
|
|
||||||
|
idev->dev.parent = dev;
|
||||||
idev->name = "UCB1400 touchscreen interface";
|
idev->name = "UCB1400 touchscreen interface";
|
||||||
idev->id.vendor = ucb1400_reg_read(ucb, AC97_VENDOR_ID1);
|
idev->id.vendor = ucb1400_reg_read(ucb, AC97_VENDOR_ID1);
|
||||||
idev->id.product = id;
|
idev->id.product = id;
|
||||||
|
@ -571,7 +575,15 @@ static void __exit ucb1400_ts_exit(void)
|
||||||
driver_unregister(&ucb1400_ts_driver);
|
driver_unregister(&ucb1400_ts_driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
module_param(adcsync, int, 0444);
|
module_param(adcsync, bool, 0444);
|
||||||
|
MODULE_PARM_DESC(adcsync, "Synchronize touch readings with ADCSYNC pin.");
|
||||||
|
|
||||||
|
module_param(ts_delay, int, 0444);
|
||||||
|
MODULE_PARM_DESC(ts_delay, "Delay between panel setup and position read. Default = 55us.");
|
||||||
|
|
||||||
|
module_param(ts_delay_pressure, int, 0444);
|
||||||
|
MODULE_PARM_DESC(ts_delay_pressure,
|
||||||
|
"delay between panel setup and pressure read. Default = 0us.");
|
||||||
|
|
||||||
module_init(ucb1400_ts_init);
|
module_init(ucb1400_ts_init);
|
||||||
module_exit(ucb1400_ts_exit);
|
module_exit(ucb1400_ts_exit);
|
||||||
|
|
|
@ -111,13 +111,13 @@ struct tsdev {
|
||||||
int minor;
|
int minor;
|
||||||
char name[8];
|
char name[8];
|
||||||
wait_queue_head_t wait;
|
wait_queue_head_t wait;
|
||||||
struct list_head list;
|
struct list_head client_list;
|
||||||
struct input_handle handle;
|
struct input_handle handle;
|
||||||
int x, y, pressure;
|
int x, y, pressure;
|
||||||
struct ts_calibration cal;
|
struct ts_calibration cal;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tsdev_list {
|
struct tsdev_client {
|
||||||
struct fasync_struct *fasync;
|
struct fasync_struct *fasync;
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
struct tsdev *tsdev;
|
struct tsdev *tsdev;
|
||||||
|
@ -139,38 +139,49 @@ static struct tsdev *tsdev_table[TSDEV_MINORS/2];
|
||||||
|
|
||||||
static int tsdev_fasync(int fd, struct file *file, int on)
|
static int tsdev_fasync(int fd, struct file *file, int on)
|
||||||
{
|
{
|
||||||
struct tsdev_list *list = file->private_data;
|
struct tsdev_client *client = file->private_data;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
retval = fasync_helper(fd, file, on, &list->fasync);
|
retval = fasync_helper(fd, file, on, &client->fasync);
|
||||||
return retval < 0 ? retval : 0;
|
return retval < 0 ? retval : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tsdev_open(struct inode *inode, struct file *file)
|
static int tsdev_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
int i = iminor(inode) - TSDEV_MINOR_BASE;
|
int i = iminor(inode) - TSDEV_MINOR_BASE;
|
||||||
struct tsdev_list *list;
|
struct tsdev_client *client;
|
||||||
|
struct tsdev *tsdev;
|
||||||
|
int error;
|
||||||
|
|
||||||
printk(KERN_WARNING "tsdev (compaq touchscreen emulation) is scheduled "
|
printk(KERN_WARNING "tsdev (compaq touchscreen emulation) is scheduled "
|
||||||
"for removal.\nSee Documentation/feature-removal-schedule.txt "
|
"for removal.\nSee Documentation/feature-removal-schedule.txt "
|
||||||
"for details.\n");
|
"for details.\n");
|
||||||
|
|
||||||
if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK])
|
if (i >= TSDEV_MINORS)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if (!(list = kzalloc(sizeof(struct tsdev_list), GFP_KERNEL)))
|
tsdev = tsdev_table[i & TSDEV_MINOR_MASK];
|
||||||
|
if (!tsdev || !tsdev->exist)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
client = kzalloc(sizeof(struct tsdev_client), GFP_KERNEL);
|
||||||
|
if (!client)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
list->raw = (i >= TSDEV_MINORS/2) ? 1 : 0;
|
client->tsdev = tsdev;
|
||||||
|
client->raw = (i >= TSDEV_MINORS / 2) ? 1 : 0;
|
||||||
|
list_add_tail(&client->node, &tsdev->client_list);
|
||||||
|
|
||||||
i &= TSDEV_MINOR_MASK;
|
if (!tsdev->open++ && tsdev->exist) {
|
||||||
list->tsdev = tsdev_table[i];
|
error = input_open_device(&tsdev->handle);
|
||||||
list_add_tail(&list->node, &tsdev_table[i]->list);
|
if (error) {
|
||||||
file->private_data = list;
|
list_del(&client->node);
|
||||||
|
kfree(client);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!list->tsdev->open++)
|
file->private_data = client;
|
||||||
if (list->tsdev->exist)
|
|
||||||
input_open_device(&list->tsdev->handle);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,45 +193,48 @@ static void tsdev_free(struct tsdev *tsdev)
|
||||||
|
|
||||||
static int tsdev_release(struct inode *inode, struct file *file)
|
static int tsdev_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct tsdev_list *list = file->private_data;
|
struct tsdev_client *client = file->private_data;
|
||||||
|
struct tsdev *tsdev = client->tsdev;
|
||||||
|
|
||||||
tsdev_fasync(-1, file, 0);
|
tsdev_fasync(-1, file, 0);
|
||||||
list_del(&list->node);
|
|
||||||
|
|
||||||
if (!--list->tsdev->open) {
|
list_del(&client->node);
|
||||||
if (list->tsdev->exist)
|
kfree(client);
|
||||||
input_close_device(&list->tsdev->handle);
|
|
||||||
|
if (!--tsdev->open) {
|
||||||
|
if (tsdev->exist)
|
||||||
|
input_close_device(&tsdev->handle);
|
||||||
else
|
else
|
||||||
tsdev_free(list->tsdev);
|
tsdev_free(tsdev);
|
||||||
}
|
}
|
||||||
kfree(list);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count,
|
static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count,
|
||||||
loff_t * ppos)
|
loff_t *ppos)
|
||||||
{
|
{
|
||||||
struct tsdev_list *list = file->private_data;
|
struct tsdev_client *client = file->private_data;
|
||||||
|
struct tsdev *tsdev = client->tsdev;
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
if (list->head == list->tail && list->tsdev->exist && (file->f_flags & O_NONBLOCK))
|
if (client->head == client->tail && tsdev->exist && (file->f_flags & O_NONBLOCK))
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
retval = wait_event_interruptible(list->tsdev->wait,
|
retval = wait_event_interruptible(tsdev->wait,
|
||||||
list->head != list->tail || !list->tsdev->exist);
|
client->head != client->tail || !tsdev->exist);
|
||||||
|
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
if (!list->tsdev->exist)
|
if (!tsdev->exist)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
while (list->head != list->tail &&
|
while (client->head != client->tail &&
|
||||||
retval + sizeof (struct ts_event) <= count) {
|
retval + sizeof (struct ts_event) <= count) {
|
||||||
if (copy_to_user (buffer + retval, list->event + list->tail,
|
if (copy_to_user (buffer + retval, client->event + client->tail,
|
||||||
sizeof (struct ts_event)))
|
sizeof (struct ts_event)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
|
client->tail = (client->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
|
||||||
retval += sizeof (struct ts_event);
|
retval += sizeof (struct ts_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,31 +242,32 @@ static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No kernel lock - fine */
|
/* No kernel lock - fine */
|
||||||
static unsigned int tsdev_poll(struct file *file, poll_table * wait)
|
static unsigned int tsdev_poll(struct file *file, poll_table *wait)
|
||||||
{
|
{
|
||||||
struct tsdev_list *list = file->private_data;
|
struct tsdev_client *client = file->private_data;
|
||||||
|
struct tsdev *tsdev = client->tsdev;
|
||||||
|
|
||||||
poll_wait(file, &list->tsdev->wait, wait);
|
poll_wait(file, &tsdev->wait, wait);
|
||||||
return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) |
|
return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) |
|
||||||
(list->tsdev->exist ? 0 : (POLLHUP | POLLERR));
|
(tsdev->exist ? 0 : (POLLHUP | POLLERR));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tsdev_ioctl(struct inode *inode, struct file *file,
|
static int tsdev_ioctl(struct inode *inode, struct file *file,
|
||||||
unsigned int cmd, unsigned long arg)
|
unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
struct tsdev_list *list = file->private_data;
|
struct tsdev_client *client = file->private_data;
|
||||||
struct tsdev *tsdev = list->tsdev;
|
struct tsdev *tsdev = client->tsdev;
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case TS_GET_CAL:
|
case TS_GET_CAL:
|
||||||
if (copy_to_user ((void __user *)arg, &tsdev->cal,
|
if (copy_to_user((void __user *)arg, &tsdev->cal,
|
||||||
sizeof (struct ts_calibration)))
|
sizeof (struct ts_calibration)))
|
||||||
retval = -EFAULT;
|
retval = -EFAULT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TS_SET_CAL:
|
case TS_SET_CAL:
|
||||||
if (copy_from_user (&tsdev->cal, (void __user *)arg,
|
if (copy_from_user(&tsdev->cal, (void __user *)arg,
|
||||||
sizeof (struct ts_calibration)))
|
sizeof (struct ts_calibration)))
|
||||||
retval = -EFAULT;
|
retval = -EFAULT;
|
||||||
break;
|
break;
|
||||||
|
@ -279,7 +294,7 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
|
||||||
unsigned int code, int value)
|
unsigned int code, int value)
|
||||||
{
|
{
|
||||||
struct tsdev *tsdev = handle->private;
|
struct tsdev *tsdev = handle->private;
|
||||||
struct tsdev_list *list;
|
struct tsdev_client *client;
|
||||||
struct timeval time;
|
struct timeval time;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -343,18 +358,18 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
|
||||||
if (type != EV_SYN || code != SYN_REPORT)
|
if (type != EV_SYN || code != SYN_REPORT)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
list_for_each_entry(list, &tsdev->list, node) {
|
list_for_each_entry(client, &tsdev->client_list, node) {
|
||||||
int x, y, tmp;
|
int x, y, tmp;
|
||||||
|
|
||||||
do_gettimeofday(&time);
|
do_gettimeofday(&time);
|
||||||
list->event[list->head].millisecs = time.tv_usec / 100;
|
client->event[client->head].millisecs = time.tv_usec / 100;
|
||||||
list->event[list->head].pressure = tsdev->pressure;
|
client->event[client->head].pressure = tsdev->pressure;
|
||||||
|
|
||||||
x = tsdev->x;
|
x = tsdev->x;
|
||||||
y = tsdev->y;
|
y = tsdev->y;
|
||||||
|
|
||||||
/* Calibration */
|
/* Calibration */
|
||||||
if (!list->raw) {
|
if (!client->raw) {
|
||||||
x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans;
|
x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans;
|
||||||
y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;
|
y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;
|
||||||
if (tsdev->cal.xyswap) {
|
if (tsdev->cal.xyswap) {
|
||||||
|
@ -362,33 +377,35 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
list->event[list->head].x = x;
|
client->event[client->head].x = x;
|
||||||
list->event[list->head].y = y;
|
client->event[client->head].y = y;
|
||||||
list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1);
|
client->head = (client->head + 1) & (TSDEV_BUFFER_SIZE - 1);
|
||||||
kill_fasync(&list->fasync, SIGIO, POLL_IN);
|
kill_fasync(&client->fasync, SIGIO, POLL_IN);
|
||||||
}
|
}
|
||||||
wake_up_interruptible(&tsdev->wait);
|
wake_up_interruptible(&tsdev->wait);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct input_handle *tsdev_connect(struct input_handler *handler,
|
static int tsdev_connect(struct input_handler *handler, struct input_dev *dev,
|
||||||
struct input_dev *dev,
|
|
||||||
const struct input_device_id *id)
|
const struct input_device_id *id)
|
||||||
{
|
{
|
||||||
struct tsdev *tsdev;
|
struct tsdev *tsdev;
|
||||||
struct class_device *cdev;
|
struct class_device *cdev;
|
||||||
|
dev_t devt;
|
||||||
int minor, delta;
|
int minor, delta;
|
||||||
|
int error;
|
||||||
|
|
||||||
for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++);
|
for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++);
|
||||||
if (minor >= TSDEV_MINORS / 2) {
|
if (minor >= TSDEV_MINORS / 2) {
|
||||||
printk(KERN_ERR
|
printk(KERN_ERR
|
||||||
"tsdev: You have way too many touchscreens\n");
|
"tsdev: You have way too many touchscreens\n");
|
||||||
return NULL;
|
return -ENFILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL)))
|
tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL);
|
||||||
return NULL;
|
if (!tsdev)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&tsdev->list);
|
INIT_LIST_HEAD(&tsdev->client_list);
|
||||||
init_waitqueue_head(&tsdev->wait);
|
init_waitqueue_head(&tsdev->wait);
|
||||||
|
|
||||||
sprintf(tsdev->name, "ts%d", minor);
|
sprintf(tsdev->name, "ts%d", minor);
|
||||||
|
@ -415,21 +432,43 @@ static struct input_handle *tsdev_connect(struct input_handler *handler,
|
||||||
|
|
||||||
tsdev_table[minor] = tsdev;
|
tsdev_table[minor] = tsdev;
|
||||||
|
|
||||||
cdev = class_device_create(&input_class, &dev->cdev,
|
devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
|
||||||
MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
|
|
||||||
|
cdev = class_device_create(&input_class, &dev->cdev, devt,
|
||||||
dev->cdev.dev, tsdev->name);
|
dev->cdev.dev, tsdev->name);
|
||||||
|
if (IS_ERR(cdev)) {
|
||||||
|
error = PTR_ERR(cdev);
|
||||||
|
goto err_free_tsdev;
|
||||||
|
}
|
||||||
|
|
||||||
/* temporary symlink to keep userspace happy */
|
/* temporary symlink to keep userspace happy */
|
||||||
sysfs_create_link(&input_class.subsys.kobj, &cdev->kobj,
|
error = sysfs_create_link(&input_class.subsys.kobj,
|
||||||
tsdev->name);
|
&cdev->kobj, tsdev->name);
|
||||||
|
if (error)
|
||||||
|
goto err_cdev_destroy;
|
||||||
|
|
||||||
return &tsdev->handle;
|
error = input_register_handle(&tsdev->handle);
|
||||||
|
if (error)
|
||||||
|
goto err_remove_link;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_remove_link:
|
||||||
|
sysfs_remove_link(&input_class.subsys.kobj, tsdev->name);
|
||||||
|
err_cdev_destroy:
|
||||||
|
class_device_destroy(&input_class, devt);
|
||||||
|
err_free_tsdev:
|
||||||
|
tsdev_table[minor] = NULL;
|
||||||
|
kfree(tsdev);
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tsdev_disconnect(struct input_handle *handle)
|
static void tsdev_disconnect(struct input_handle *handle)
|
||||||
{
|
{
|
||||||
struct tsdev *tsdev = handle->private;
|
struct tsdev *tsdev = handle->private;
|
||||||
struct tsdev_list *list;
|
struct tsdev_client *client;
|
||||||
|
|
||||||
|
input_unregister_handle(handle);
|
||||||
|
|
||||||
sysfs_remove_link(&input_class.subsys.kobj, tsdev->name);
|
sysfs_remove_link(&input_class.subsys.kobj, tsdev->name);
|
||||||
class_device_destroy(&input_class,
|
class_device_destroy(&input_class,
|
||||||
|
@ -439,8 +478,8 @@ static void tsdev_disconnect(struct input_handle *handle)
|
||||||
if (tsdev->open) {
|
if (tsdev->open) {
|
||||||
input_close_device(handle);
|
input_close_device(handle);
|
||||||
wake_up_interruptible(&tsdev->wait);
|
wake_up_interruptible(&tsdev->wait);
|
||||||
list_for_each_entry(list, &tsdev->list, node)
|
list_for_each_entry(client, &tsdev->client_list, node)
|
||||||
kill_fasync(&list->fasync, SIGIO, POLL_HUP);
|
kill_fasync(&client->fasync, SIGIO, POLL_HUP);
|
||||||
} else
|
} else
|
||||||
tsdev_free(tsdev);
|
tsdev_free(tsdev);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,6 @@ obj-$(CONFIG_USB_ATI_REMOTE) += ati_remote.o
|
||||||
obj-$(CONFIG_USB_ATI_REMOTE2) += ati_remote2.o
|
obj-$(CONFIG_USB_ATI_REMOTE2) += ati_remote2.o
|
||||||
obj-$(CONFIG_USB_KBTAB) += kbtab.o
|
obj-$(CONFIG_USB_KBTAB) += kbtab.o
|
||||||
obj-$(CONFIG_USB_KEYSPAN_REMOTE) += keyspan_remote.o
|
obj-$(CONFIG_USB_KEYSPAN_REMOTE) += keyspan_remote.o
|
||||||
obj-$(CONFIG_USB_MTOUCH) += mtouchusb.o
|
|
||||||
obj-$(CONFIG_USB_ITMTOUCH) += itmtouch.o
|
|
||||||
obj-$(CONFIG_USB_EGALAX) += touchkitusb.o
|
|
||||||
obj-$(CONFIG_USB_TOUCHSCREEN) += usbtouchscreen.o
|
obj-$(CONFIG_USB_TOUCHSCREEN) += usbtouchscreen.o
|
||||||
obj-$(CONFIG_USB_POWERMATE) += powermate.o
|
obj-$(CONFIG_USB_POWERMATE) += powermate.o
|
||||||
obj-$(CONFIG_USB_WACOM) += wacom.o
|
obj-$(CONFIG_USB_WACOM) += wacom.o
|
||||||
|
|
|
@ -111,7 +111,7 @@ resubmit:
|
||||||
|
|
||||||
static int usb_acecad_open(struct input_dev *dev)
|
static int usb_acecad_open(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct usb_acecad *acecad = dev->private;
|
struct usb_acecad *acecad = input_get_drvdata(dev);
|
||||||
|
|
||||||
acecad->irq->dev = acecad->usbdev;
|
acecad->irq->dev = acecad->usbdev;
|
||||||
if (usb_submit_urb(acecad->irq, GFP_KERNEL))
|
if (usb_submit_urb(acecad->irq, GFP_KERNEL))
|
||||||
|
@ -122,7 +122,7 @@ static int usb_acecad_open(struct input_dev *dev)
|
||||||
|
|
||||||
static void usb_acecad_close(struct input_dev *dev)
|
static void usb_acecad_close(struct input_dev *dev)
|
||||||
{
|
{
|
||||||
struct usb_acecad *acecad = dev->private;
|
struct usb_acecad *acecad = input_get_drvdata(dev);
|
||||||
|
|
||||||
usb_kill_urb(acecad->irq);
|
usb_kill_urb(acecad->irq);
|
||||||
}
|
}
|
||||||
|
@ -135,6 +135,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
|
||||||
struct usb_acecad *acecad;
|
struct usb_acecad *acecad;
|
||||||
struct input_dev *input_dev;
|
struct input_dev *input_dev;
|
||||||
int pipe, maxp;
|
int pipe, maxp;
|
||||||
|
int err = -ENOMEM;
|
||||||
|
|
||||||
if (interface->desc.bNumEndpoints != 1)
|
if (interface->desc.bNumEndpoints != 1)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
@ -149,16 +150,22 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
|
||||||
|
|
||||||
acecad = kzalloc(sizeof(struct usb_acecad), GFP_KERNEL);
|
acecad = kzalloc(sizeof(struct usb_acecad), GFP_KERNEL);
|
||||||
input_dev = input_allocate_device();
|
input_dev = input_allocate_device();
|
||||||
if (!acecad || !input_dev)
|
if (!acecad || !input_dev) {
|
||||||
|
err = -ENOMEM;
|
||||||
goto fail1;
|
goto fail1;
|
||||||
|
}
|
||||||
|
|
||||||
acecad->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &acecad->data_dma);
|
acecad->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &acecad->data_dma);
|
||||||
if (!acecad->data)
|
if (!acecad->data) {
|
||||||
|
err= -ENOMEM;
|
||||||
goto fail1;
|
goto fail1;
|
||||||
|
}
|
||||||
|
|
||||||
acecad->irq = usb_alloc_urb(0, GFP_KERNEL);
|
acecad->irq = usb_alloc_urb(0, GFP_KERNEL);
|
||||||
if (!acecad->irq)
|
if (!acecad->irq) {
|
||||||
|
err = -ENOMEM;
|
||||||
goto fail2;
|
goto fail2;
|
||||||
|
}
|
||||||
|
|
||||||
acecad->usbdev = dev;
|
acecad->usbdev = dev;
|
||||||
acecad->input = input_dev;
|
acecad->input = input_dev;
|
||||||
|
@ -178,8 +185,9 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
|
||||||
input_dev->name = acecad->name;
|
input_dev->name = acecad->name;
|
||||||
input_dev->phys = acecad->phys;
|
input_dev->phys = acecad->phys;
|
||||||
usb_to_input_id(dev, &input_dev->id);
|
usb_to_input_id(dev, &input_dev->id);
|
||||||
input_dev->cdev.dev = &intf->dev;
|
input_dev->dev.parent = &intf->dev;
|
||||||
input_dev->private = acecad;
|
|
||||||
|
input_set_drvdata(input_dev, acecad);
|
||||||
|
|
||||||
input_dev->open = usb_acecad_open;
|
input_dev->open = usb_acecad_open;
|
||||||
input_dev->close = usb_acecad_close;
|
input_dev->close = usb_acecad_close;
|
||||||
|
@ -221,7 +229,9 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
|
||||||
acecad->irq->transfer_dma = acecad->data_dma;
|
acecad->irq->transfer_dma = acecad->data_dma;
|
||||||
acecad->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
acecad->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||||
|
|
||||||
input_register_device(acecad->input);
|
err = input_register_device(acecad->input);
|
||||||
|
if (err)
|
||||||
|
goto fail2;
|
||||||
|
|
||||||
usb_set_intfdata(intf, acecad);
|
usb_set_intfdata(intf, acecad);
|
||||||
|
|
||||||
|
@ -230,7 +240,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
|
||||||
fail2: usb_buffer_free(dev, 8, acecad->data, acecad->data_dma);
|
fail2: usb_buffer_free(dev, 8, acecad->data, acecad->data_dma);
|
||||||
fail1: input_free_device(input_dev);
|
fail1: input_free_device(input_dev);
|
||||||
kfree(acecad);
|
kfree(acecad);
|
||||||
return -ENOMEM;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void usb_acecad_disconnect(struct usb_interface *intf)
|
static void usb_acecad_disconnect(struct usb_interface *intf)
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue